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 "gtksignal.h"
32 #include "gtkwindow.h"
33 #include "gdk/gdkkeysyms.h"
34 #include "gtkclipboard.h"
35 #include <pango/pango.h>
36 #include "gtkimagemenuitem.h"
38 #include "gtkseparatormenuitem.h"
39 #include "gtkmenuitem.h"
40 #include "gtknotebook.h"
42 #include "gtkbindings.h"
44 struct _GtkLabelSelectionInfo
47 gint selection_anchor;
50 GtkWidget *popup_menu;
76 static guint signals[LAST_SIGNAL] = { 0 };
78 static void gtk_label_class_init (GtkLabelClass *klass);
79 static void gtk_label_init (GtkLabel *label);
80 static void gtk_label_set_property (GObject *object,
84 static void gtk_label_get_property (GObject *object,
88 static void gtk_label_destroy (GtkObject *object);
89 static void gtk_label_finalize (GObject *object);
90 static void gtk_label_size_request (GtkWidget *widget,
91 GtkRequisition *requisition);
92 static void gtk_label_size_allocate (GtkWidget *widget,
93 GtkAllocation *allocation);
94 static void gtk_label_state_changed (GtkWidget *widget,
96 static void gtk_label_style_set (GtkWidget *widget,
97 GtkStyle *previous_style);
98 static void gtk_label_direction_changed (GtkWidget *widget,
99 GtkTextDirection previous_dir);
100 static gint gtk_label_expose (GtkWidget *widget,
101 GdkEventExpose *event);
103 static void gtk_label_realize (GtkWidget *widget);
104 static void gtk_label_unrealize (GtkWidget *widget);
105 static void gtk_label_map (GtkWidget *widget);
106 static void gtk_label_unmap (GtkWidget *widget);
107 static gint gtk_label_button_press (GtkWidget *widget,
108 GdkEventButton *event);
109 static gint gtk_label_button_release (GtkWidget *widget,
110 GdkEventButton *event);
111 static gint gtk_label_motion (GtkWidget *widget,
112 GdkEventMotion *event);
115 static void gtk_label_set_text_internal (GtkLabel *label,
117 static void gtk_label_set_label_internal (GtkLabel *label,
119 static void gtk_label_set_use_markup_internal (GtkLabel *label,
121 static void gtk_label_set_use_underline_internal (GtkLabel *label,
123 static void gtk_label_set_attributes_internal (GtkLabel *label,
124 PangoAttrList *attrs);
125 static void gtk_label_set_uline_text_internal (GtkLabel *label,
127 static void gtk_label_set_pattern_internal (GtkLabel *label,
128 const gchar *pattern);
129 static void set_markup (GtkLabel *label,
131 gboolean with_uline);
132 static void gtk_label_recalculate (GtkLabel *label);
133 static void gtk_label_hierarchy_changed (GtkWidget *widget,
134 GtkWidget *old_toplevel);
136 static void gtk_label_create_window (GtkLabel *label);
137 static void gtk_label_destroy_window (GtkLabel *label);
138 static void gtk_label_clear_layout (GtkLabel *label);
139 static void gtk_label_ensure_layout (GtkLabel *label);
140 static void gtk_label_select_region_index (GtkLabel *label,
144 static gboolean gtk_label_mnemonic_activate (GtkWidget *widget,
145 gboolean group_cycling);
146 static void gtk_label_setup_mnemonic (GtkLabel *label,
148 static gboolean gtk_label_focus (GtkWidget *widget,
149 GtkDirectionType direction);
151 /* For selectable lables: */
152 static void gtk_label_move_cursor (GtkLabel *label,
153 GtkMovementStep step,
155 gboolean extend_selection);
156 static void gtk_label_copy_clipboard (GtkLabel *label);
157 static void gtk_label_select_all (GtkLabel *label);
158 static void gtk_label_do_popup (GtkLabel *label,
159 GdkEventButton *event);
161 static gint gtk_label_move_forward_word (GtkLabel *label,
163 static gint gtk_label_move_backward_word (GtkLabel *label,
166 static GtkMiscClass *parent_class = NULL;
170 gtk_label_get_type (void)
172 static GtkType label_type = 0;
176 static const GTypeInfo label_info =
178 sizeof (GtkLabelClass),
179 NULL, /* base_init */
180 NULL, /* base_finalize */
181 (GClassInitFunc) gtk_label_class_init,
182 NULL, /* class_finalize */
183 NULL, /* class_data */
185 32, /* n_preallocs */
186 (GInstanceInitFunc) gtk_label_init,
189 label_type = g_type_register_static (GTK_TYPE_MISC, "GtkLabel", &label_info, 0);
196 add_move_binding (GtkBindingSet *binding_set,
199 GtkMovementStep step,
202 g_return_if_fail ((modmask & GDK_SHIFT_MASK) == 0);
204 gtk_binding_entry_add_signal (binding_set, keyval, modmask,
208 G_TYPE_BOOLEAN, FALSE);
210 /* Selection-extending version */
211 gtk_binding_entry_add_signal (binding_set, keyval, modmask | GDK_SHIFT_MASK,
215 G_TYPE_BOOLEAN, TRUE);
219 gtk_label_class_init (GtkLabelClass *class)
221 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
222 GtkObjectClass *object_class = GTK_OBJECT_CLASS (class);
223 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
224 GtkBindingSet *binding_set;
226 parent_class = gtk_type_class (GTK_TYPE_MISC);
228 gobject_class->set_property = gtk_label_set_property;
229 gobject_class->get_property = gtk_label_get_property;
230 gobject_class->finalize = gtk_label_finalize;
232 object_class->destroy = gtk_label_destroy;
234 widget_class->size_request = gtk_label_size_request;
235 widget_class->size_allocate = gtk_label_size_allocate;
236 widget_class->state_changed = gtk_label_state_changed;
237 widget_class->style_set = gtk_label_style_set;
238 widget_class->direction_changed = gtk_label_direction_changed;
239 widget_class->expose_event = gtk_label_expose;
240 widget_class->realize = gtk_label_realize;
241 widget_class->unrealize = gtk_label_unrealize;
242 widget_class->map = gtk_label_map;
243 widget_class->unmap = gtk_label_unmap;
244 widget_class->button_press_event = gtk_label_button_press;
245 widget_class->button_release_event = gtk_label_button_release;
246 widget_class->motion_notify_event = gtk_label_motion;
247 widget_class->hierarchy_changed = gtk_label_hierarchy_changed;
248 widget_class->mnemonic_activate = gtk_label_mnemonic_activate;
249 widget_class->focus = gtk_label_focus;
251 class->move_cursor = gtk_label_move_cursor;
252 class->copy_clipboard = gtk_label_copy_clipboard;
254 signals[MOVE_CURSOR] =
255 gtk_signal_new ("move_cursor",
256 GTK_RUN_LAST | GTK_RUN_ACTION,
257 GTK_CLASS_TYPE (object_class),
258 GTK_SIGNAL_OFFSET (GtkLabelClass, move_cursor),
259 _gtk_marshal_VOID__ENUM_INT_BOOLEAN,
260 GTK_TYPE_NONE, 3, GTK_TYPE_MOVEMENT_STEP, GTK_TYPE_INT, GTK_TYPE_BOOL);
262 signals[COPY_CLIPBOARD] =
263 gtk_signal_new ("copy_clipboard",
264 GTK_RUN_LAST | GTK_RUN_ACTION,
265 GTK_CLASS_TYPE (object_class),
266 GTK_SIGNAL_OFFSET (GtkLabelClass, copy_clipboard),
267 _gtk_marshal_VOID__VOID,
270 signals[POPULATE_POPUP] =
271 gtk_signal_new ("populate_popup",
273 GTK_CLASS_TYPE (object_class),
274 GTK_SIGNAL_OFFSET (GtkLabelClass, populate_popup),
275 _gtk_marshal_VOID__OBJECT,
276 GTK_TYPE_NONE, 1, GTK_TYPE_MENU);
278 g_object_class_install_property (G_OBJECT_CLASS(object_class),
280 g_param_spec_string ("label",
282 _("The text of the label."),
285 g_object_class_install_property (gobject_class,
287 g_param_spec_boxed ("attributes",
289 _("A list of style attributes to apply to the text of the label."),
290 PANGO_TYPE_ATTR_LIST,
292 g_object_class_install_property (gobject_class,
294 g_param_spec_boolean ("use_markup",
296 _("The text of the label includes XML markup. See pango_parse_markup()."),
299 g_object_class_install_property (gobject_class,
301 g_param_spec_boolean ("use_underline",
303 _("If set, an underline in the text indicates the next character should be used for the mnemonic accelerator key"),
307 g_object_class_install_property (gobject_class,
309 g_param_spec_enum ("justify",
311 _("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."),
312 GTK_TYPE_JUSTIFICATION,
316 g_object_class_install_property (gobject_class,
318 g_param_spec_string ("pattern",
320 _("A string with _ characters in positions correspond to characters in the text to underline."),
324 g_object_class_install_property (gobject_class,
326 g_param_spec_boolean ("wrap",
328 _("If set, wrap lines if the text becomes too wide."),
331 g_object_class_install_property (gobject_class,
333 g_param_spec_boolean ("selectable",
335 _("Whether the label text can be selected with the mouse."),
338 g_object_class_install_property (gobject_class,
339 PROP_MNEMONIC_KEYVAL,
340 g_param_spec_uint ("mnemonic_keyval",
342 _("The mnemonic accelerator key for this label."),
347 g_object_class_install_property (gobject_class,
348 PROP_MNEMONIC_WIDGET,
349 g_param_spec_object ("mnemonic_widget",
350 _("Mnemonic widget"),
351 _("The widget to be activated when the label's mnemonic "
356 g_object_class_install_property (gobject_class,
357 PROP_CURSOR_POSITION,
358 g_param_spec_int ("cursor_position",
359 _("Cursor Position"),
360 _("The current position of the insertion cursor in chars."),
366 g_object_class_install_property (gobject_class,
367 PROP_SELECTION_BOUND,
368 g_param_spec_int ("selection_bound",
369 _("Selection Bound"),
370 _("The position of the opposite end of the selection from the cursor in chars."),
380 binding_set = gtk_binding_set_by_class (class);
382 /* Moving the insertion point */
383 add_move_binding (binding_set, GDK_Right, 0,
384 GTK_MOVEMENT_VISUAL_POSITIONS, 1);
386 add_move_binding (binding_set, GDK_Left, 0,
387 GTK_MOVEMENT_VISUAL_POSITIONS, -1);
389 add_move_binding (binding_set, GDK_KP_Right, 0,
390 GTK_MOVEMENT_VISUAL_POSITIONS, 1);
392 add_move_binding (binding_set, GDK_KP_Left, 0,
393 GTK_MOVEMENT_VISUAL_POSITIONS, -1);
395 add_move_binding (binding_set, GDK_f, GDK_CONTROL_MASK,
396 GTK_MOVEMENT_LOGICAL_POSITIONS, 1);
398 add_move_binding (binding_set, GDK_b, GDK_CONTROL_MASK,
399 GTK_MOVEMENT_LOGICAL_POSITIONS, -1);
401 add_move_binding (binding_set, GDK_Right, GDK_CONTROL_MASK,
402 GTK_MOVEMENT_WORDS, 1);
404 add_move_binding (binding_set, GDK_Left, GDK_CONTROL_MASK,
405 GTK_MOVEMENT_WORDS, -1);
407 add_move_binding (binding_set, GDK_KP_Right, GDK_CONTROL_MASK,
408 GTK_MOVEMENT_WORDS, 1);
410 add_move_binding (binding_set, GDK_KP_Left, GDK_CONTROL_MASK,
411 GTK_MOVEMENT_WORDS, -1);
413 add_move_binding (binding_set, GDK_a, GDK_CONTROL_MASK,
414 GTK_MOVEMENT_PARAGRAPH_ENDS, -1);
416 add_move_binding (binding_set, GDK_e, GDK_CONTROL_MASK,
417 GTK_MOVEMENT_PARAGRAPH_ENDS, 1);
419 add_move_binding (binding_set, GDK_f, GDK_MOD1_MASK,
420 GTK_MOVEMENT_WORDS, 1);
422 add_move_binding (binding_set, GDK_b, GDK_MOD1_MASK,
423 GTK_MOVEMENT_WORDS, -1);
425 add_move_binding (binding_set, GDK_Home, 0,
426 GTK_MOVEMENT_DISPLAY_LINE_ENDS, -1);
428 add_move_binding (binding_set, GDK_End, 0,
429 GTK_MOVEMENT_DISPLAY_LINE_ENDS, 1);
431 add_move_binding (binding_set, GDK_KP_Home, 0,
432 GTK_MOVEMENT_DISPLAY_LINE_ENDS, -1);
434 add_move_binding (binding_set, GDK_KP_End, 0,
435 GTK_MOVEMENT_DISPLAY_LINE_ENDS, 1);
437 add_move_binding (binding_set, GDK_Home, GDK_CONTROL_MASK,
438 GTK_MOVEMENT_BUFFER_ENDS, -1);
440 add_move_binding (binding_set, GDK_End, GDK_CONTROL_MASK,
441 GTK_MOVEMENT_BUFFER_ENDS, 1);
443 add_move_binding (binding_set, GDK_KP_Home, GDK_CONTROL_MASK,
444 GTK_MOVEMENT_BUFFER_ENDS, -1);
446 add_move_binding (binding_set, GDK_KP_End, GDK_CONTROL_MASK,
447 GTK_MOVEMENT_BUFFER_ENDS, 1);
450 gtk_binding_entry_add_signal (binding_set, GDK_c, GDK_CONTROL_MASK,
451 "copy_clipboard", 0);
455 gtk_label_set_property (GObject *object,
463 label = GTK_LABEL (object);
464 last_keyval = label->mnemonic_keyval;
469 gtk_label_set_label (label, g_value_get_string (value));
471 case PROP_ATTRIBUTES:
472 gtk_label_set_attributes (label, g_value_get_boxed (value));
474 case PROP_USE_MARKUP:
475 gtk_label_set_use_markup (label, g_value_get_boolean (value));
477 case PROP_USE_UNDERLINE:
478 gtk_label_set_use_underline (label, g_value_get_boolean (value));
481 gtk_label_set_justify (label, g_value_get_enum (value));
484 gtk_label_set_pattern (label, g_value_get_string (value));
487 gtk_label_set_line_wrap (label, g_value_get_boolean (value));
489 case PROP_SELECTABLE:
490 gtk_label_set_selectable (label, g_value_get_boolean (value));
492 case PROP_MNEMONIC_WIDGET:
493 gtk_label_set_mnemonic_widget (label, (GtkWidget*) g_value_get_object (value));
496 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
502 gtk_label_get_property (GObject *object,
509 label = GTK_LABEL (object);
514 g_value_set_string (value, label->label);
516 case PROP_ATTRIBUTES:
517 g_value_set_boxed (value, label->attrs);
519 case PROP_USE_MARKUP:
520 g_value_set_boolean (value, label->use_markup);
522 case PROP_USE_UNDERLINE:
523 g_value_set_boolean (value, label->use_underline);
526 g_value_set_enum (value, label->jtype);
529 g_value_set_boolean (value, label->wrap);
531 case PROP_SELECTABLE:
532 g_value_set_boolean (value, gtk_label_get_selectable (label));
534 case PROP_MNEMONIC_KEYVAL:
535 g_value_set_uint (value, label->mnemonic_keyval);
537 case PROP_MNEMONIC_WIDGET:
538 g_value_set_object (value, (GObject*) label->mnemonic_widget);
540 case PROP_CURSOR_POSITION:
541 if (label->select_info)
543 gint offset = g_utf8_pointer_to_offset (label->label,
544 label->label + label->select_info->selection_end);
545 g_value_set_int (value, offset);
548 g_value_set_int (value, 0);
550 case PROP_SELECTION_BOUND:
551 if (label->select_info)
553 gint offset = g_utf8_pointer_to_offset (label->label,
554 label->label + label->select_info->selection_anchor);
555 g_value_set_int (value, offset);
558 g_value_set_int (value, 0);
562 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
568 gtk_label_init (GtkLabel *label)
570 GTK_WIDGET_SET_FLAGS (label, GTK_NO_WINDOW);
574 label->jtype = GTK_JUSTIFY_LEFT;
577 label->use_underline = FALSE;
578 label->use_markup = FALSE;
580 label->mnemonic_keyval = GDK_VoidSymbol;
581 label->layout = NULL;
585 label->mnemonic_widget = NULL;
586 label->mnemonic_window = NULL;
588 gtk_label_set_text (label, "");
593 * @str: The text of the label
595 * Creates a new label with the given text inside it. You can
596 * pass %NULL to get an empty label widget.
598 * Return value: the new #GtkLabel
601 gtk_label_new (const gchar *str)
605 label = gtk_type_new (GTK_TYPE_LABEL);
608 gtk_label_set_text (label, str);
610 return GTK_WIDGET (label);
614 * gtk_label_new_with_mnemonic:
615 * @str: The text of the label, with an underscore in front of the
618 * Creates a new #GtkLabel, containing the text in @str.
620 * If characters in @str are preceded by an underscore, they are
621 * underlined. If you need a literal underscore character in a label, use
622 * '__' (two underscores). The first underlined character represents a
623 * keyboard accelerator called a mnemonic. The mnemonic key can be used
624 * to activate another widget, chosen automatically, or explicitly using
625 * gtk_label_set_mnemonic_widget().
627 * If gtk_label_set_mnemonic_widget()
628 * is not called, then the first activatable ancestor of the #GtkLabel
629 * will be chosen as the mnemonic widget. For instance, if the
630 * label is inside a button or menu item, the button or menu item will
631 * automatically become the mnemonic widget and be activated by
634 * Return value: the new #GtkLabel
637 gtk_label_new_with_mnemonic (const gchar *str)
641 label = gtk_type_new (GTK_TYPE_LABEL);
644 gtk_label_set_text_with_mnemonic (label, str);
646 return GTK_WIDGET (label);
650 gtk_label_mnemonic_activate (GtkWidget *widget,
651 gboolean group_cycling)
655 if (GTK_LABEL (widget)->mnemonic_widget)
656 return gtk_widget_mnemonic_activate (GTK_LABEL (widget)->mnemonic_widget, group_cycling);
658 /* Try to find the widget to activate by traversing the
661 parent = widget->parent;
663 if (parent && GTK_IS_NOTEBOOK (parent))
668 if (GTK_WIDGET_CAN_FOCUS (parent) ||
669 (!group_cycling && GTK_WIDGET_GET_CLASS (parent)->activate_signal) ||
670 (parent->parent && GTK_IS_NOTEBOOK (parent->parent)) ||
671 (GTK_IS_MENU_ITEM (parent)))
672 return gtk_widget_mnemonic_activate (parent, group_cycling);
673 parent = parent->parent;
676 /* barf if there was nothing to activate */
677 g_warning ("Couldn't find a target for a mnemonic activation.");
684 gtk_label_setup_mnemonic (GtkLabel *label,
689 if (last_key != GDK_VoidSymbol && label->mnemonic_window)
691 gtk_window_remove_mnemonic (label->mnemonic_window,
694 label->mnemonic_window = NULL;
697 if (label->mnemonic_keyval == GDK_VoidSymbol)
700 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (label));
701 if (GTK_WIDGET_TOPLEVEL (toplevel))
703 gtk_window_add_mnemonic (GTK_WINDOW (toplevel),
704 label->mnemonic_keyval,
706 label->mnemonic_window = GTK_WINDOW (toplevel);
711 gtk_label_hierarchy_changed (GtkWidget *widget,
712 GtkWidget *old_toplevel)
714 GtkLabel *label = GTK_LABEL (widget);
716 gtk_label_setup_mnemonic (label, label->mnemonic_keyval);
721 * gtk_label_set_mnemonic_widget:
722 * @label: a #GtkLabel
723 * @widget: the target #GtkWidget
725 * If the label has been set so that it has an mnemonic key (using
726 * i.e. gtk_label_set_markup_with_mnemonic(),
727 * gtk_label_set_text_with_mnemonic(), gtk_label_new_with_mnemonic()
728 * or the "use_underline" property) the label can be associated with a
729 * widget that is the target of the mnemonic. When the label is inside
730 * a widget (like a #GtkButton or a #GtkNotebook tab) it is
731 * automatically associated with the correct widget, but sometimes
732 * (i.e. when the target is a #GtkEntry next to the label) you need to
733 * set it explicitly using this function.
735 * The target widget will be accelerated by emitting "mnemonic_activate" on it.
736 * The default handler for this signal will activate the widget if there are no
737 * mnemonic collisions and toggle focus between the colliding widgets otherwise.
740 gtk_label_set_mnemonic_widget (GtkLabel *label,
743 g_return_if_fail (GTK_IS_LABEL (label));
745 g_return_if_fail (GTK_IS_WIDGET (widget));
747 if (label->mnemonic_widget)
748 gtk_widget_unref (label->mnemonic_widget);
749 label->mnemonic_widget = widget;
750 if (label->mnemonic_widget)
751 gtk_widget_ref (label->mnemonic_widget);
753 g_object_notify (G_OBJECT (label), "mnemonic_widget");
757 * gtk_label_get_mnemonic_widget:
758 * @label: a #GtkLabel
760 * Retrieves the target of the mnemonic (keyboard shortcut) of this
761 * label. See gtk_label_set_mnemonic_widget ().
763 * Return value: the target of the label's mnemonic, or %NULL if none
764 * has been set and the default algorithm will be used.
767 gtk_label_get_mnemonic_widget (GtkLabel *label)
769 g_return_val_if_fail (GTK_IS_LABEL (label), NULL);
771 return label->mnemonic_widget;
775 * gtk_label_get_mnemonic_keyval:
776 * @label: a #GtkLabel
778 * If the label has been set so that it has an mnemonic key this function
779 * returns the keyval used for the mnemonic accelerator. If there is no
780 * mnemonic set up it returns #GDK_VoidSymbol.
782 * Returns: GDK keyval usable for accelerators, or #GDK_VoidSymbol
785 gtk_label_get_mnemonic_keyval (GtkLabel *label)
787 g_return_val_if_fail (GTK_IS_LABEL (label), GDK_VoidSymbol);
789 return label->mnemonic_keyval;
793 gtk_label_set_text_internal (GtkLabel *label,
796 g_free (label->text);
800 gtk_label_select_region_index (label, 0, 0);
804 gtk_label_set_label_internal (GtkLabel *label,
807 g_free (label->label);
811 g_object_notify (G_OBJECT (label), "label");
815 gtk_label_set_use_markup_internal (GtkLabel *label,
819 if (label->use_markup != val)
821 g_object_notify (G_OBJECT (label), "use_markup");
822 label->use_markup = val;
827 gtk_label_set_use_underline_internal (GtkLabel *label,
831 if (label->use_underline != val)
833 g_object_notify (G_OBJECT (label), "use_underline");
834 label->use_underline = val;
839 gtk_label_set_attributes_internal (GtkLabel *label,
840 PangoAttrList *attrs)
843 pango_attr_list_ref (attrs);
846 pango_attr_list_unref (label->attrs);
848 if (!label->use_markup && !label->use_underline)
850 pango_attr_list_ref (attrs);
851 if (label->effective_attrs)
852 pango_attr_list_unref (label->effective_attrs);
853 label->effective_attrs = attrs;
856 label->attrs = attrs;
857 g_object_notify (G_OBJECT (label), "attributes");
861 /* Calculates text, attrs and mnemonic_keyval from
862 * label, use_underline and use_markup
865 gtk_label_recalculate (GtkLabel *label)
867 if (label->use_markup)
868 set_markup (label, label->label, label->use_underline);
871 if (label->use_underline)
872 gtk_label_set_uline_text_internal (label, label->label);
875 gtk_label_set_text_internal (label, g_strdup (label->label));
877 pango_attr_list_ref (label->attrs);
878 if (label->effective_attrs)
879 pango_attr_list_unref (label->effective_attrs);
880 label->effective_attrs = label->attrs;
884 if (!label->use_underline)
886 guint keyval = label->mnemonic_keyval;
888 label->mnemonic_keyval = GDK_VoidSymbol;
889 gtk_label_setup_mnemonic (label, keyval);
892 gtk_label_clear_layout (label);
893 gtk_widget_queue_resize (GTK_WIDGET (label));
897 * gtk_label_set_text:
898 * @label: a #GtkLabel
899 * @str: The text you want to set.
901 * Sets the text within the #GtkLabel widget. It overwrites any text that
904 * This will also clear any previously set mnemonic accelerators.
907 gtk_label_set_text (GtkLabel *label,
910 g_return_if_fail (GTK_IS_LABEL (label));
912 gtk_label_set_label_internal (label, g_strdup (str ? str : ""));
913 gtk_label_set_use_markup_internal (label, FALSE);
914 gtk_label_set_use_underline_internal (label, FALSE);
916 gtk_label_recalculate (label);
920 * gtk_label_set_attributes:
921 * @label: a #GtkLabel
922 * @attrs: a #PangoAttrList
924 * Sets a #PangoAttrList; the attributes in the list are applied to the
925 * label text. The attributes set with this function will be ignored
926 * if label->use_underline or label->use_markup is %TRUE.
929 gtk_label_set_attributes (GtkLabel *label,
930 PangoAttrList *attrs)
932 g_return_if_fail (GTK_IS_LABEL (label));
934 gtk_label_set_attributes_internal (label, attrs);
936 gtk_label_clear_layout (label);
937 gtk_widget_queue_resize (GTK_WIDGET (label));
941 * gtk_label_get_attributes:
942 * @label: a #GtkLabel
944 * Gets the attribute list that was set on the label using
945 * gtk_label_set_attributes(), if any. This function does
946 * not reflect attributes that come from the labels markup
947 * (see gtk_label_set_markup()). If you want to get the
948 * effective attributes for the label, use
949 * pango_layout_get_attribute (gtk_label_get_layout (label)).
951 * Return value: the attribute list, or %NULL if none was set.
954 gtk_label_get_attributes (GtkLabel *label)
956 g_return_val_if_fail (GTK_IS_LABEL (label), NULL);
962 * gtk_label_set_label:
963 * @label: a #GtkLabel
964 * @str: the new text to set for the label
966 * Sets the text of the label. The label is interpreted as
967 * including embedded underlines and/or Pango markup depending
968 * on the values of label->use_underline and label->use_markup.
971 gtk_label_set_label (GtkLabel *label,
976 g_return_if_fail (GTK_IS_LABEL (label));
977 g_return_if_fail (str != NULL);
979 last_keyval = label->mnemonic_keyval;
981 gtk_label_set_label_internal (label, g_strdup (str));
982 gtk_label_recalculate (label);
983 if (last_keyval != label->mnemonic_keyval)
984 gtk_label_setup_mnemonic (label, last_keyval);
988 * gtk_label_get_label:
989 * @label: a #GtkLabel
991 * Fetches the text from a label widget including any embedded
992 * underlines indicating mnemonics and Pango markup. (See
993 * gtk_label_get_text ()).
995 * Return value: the text of the label widget. This string is
996 * owned by the widget and must not be modified or freed.
998 G_CONST_RETURN gchar *
999 gtk_label_get_label (GtkLabel *label)
1001 g_return_val_if_fail (GTK_IS_LABEL (label), NULL);
1003 return label->label;
1007 set_markup (GtkLabel *label,
1009 gboolean with_uline)
1012 GError *error = NULL;
1013 PangoAttrList *attrs = NULL;
1014 gunichar accel_char = 0;
1016 if (!pango_parse_markup (str,
1018 with_uline ? '_' : 0,
1021 with_uline ? &accel_char : NULL,
1024 g_warning ("Failed to set label from markup due to error parsing markup: %s",
1026 g_error_free (error);
1031 gtk_label_set_text_internal (label, text);
1035 if (label->effective_attrs)
1036 pango_attr_list_unref (label->effective_attrs);
1037 label->effective_attrs = attrs;
1040 if (accel_char != 0)
1041 label->mnemonic_keyval = gdk_keyval_to_lower (gdk_unicode_to_keyval (accel_char));
1043 label->mnemonic_keyval = GDK_VoidSymbol;
1047 * gtk_label_set_markup:
1048 * @label: a #GtkLabel
1049 * @str: a markup string (see <link linkend="PangoMarkupFormat">Pango markup format</link>)
1051 * Parses @str which is marked up with the <link linkend="PangoMarkupFormat">Pango text markup language</link>,
1052 * setting the label's text and attribute list based on the parse results.
1055 gtk_label_set_markup (GtkLabel *label,
1058 g_return_if_fail (GTK_IS_LABEL (label));
1060 gtk_label_set_label_internal (label, g_strdup (str ? str : ""));
1061 gtk_label_set_use_markup_internal (label, TRUE);
1062 gtk_label_set_use_underline_internal (label, FALSE);
1064 gtk_label_recalculate (label);
1068 * gtk_label_set_markup_with_mnemonic:
1069 * @label: a #GtkLabel
1070 * @str: a markup string (see <link linkend="PangoMarkupFormat">Pango markup format</link>)
1072 * Parses @str which is marked up with the <link linkend="PangoMarkupFormat">Pango text markup language</link>,
1073 * setting the label's text and attribute list based on the parse results.
1074 * If characters in @str are preceded by an underscore, they are underlined
1075 * indicating that they represent a keyboard accelerator called a mnemonic.
1077 * The mnemonic key can be used to activate another widget, chosen automatically,
1078 * or explicitly using gtk_label_set_mnemonic_widget().
1081 gtk_label_set_markup_with_mnemonic (GtkLabel *label,
1085 g_return_if_fail (GTK_IS_LABEL (label));
1087 last_keyval = label->mnemonic_keyval;
1088 gtk_label_set_label_internal (label, g_strdup (str ? str : ""));
1089 gtk_label_set_use_markup_internal (label, TRUE);
1090 gtk_label_set_use_underline_internal (label, TRUE);
1092 gtk_label_recalculate (label);
1093 gtk_label_setup_mnemonic (label, last_keyval);
1097 * gtk_label_get_text:
1098 * @label: a #GtkLabel
1100 * Fetches the text from a label widget, as displayed on the
1101 * screen. This does not include any embedded underlines
1102 * indicating mnemonics or Pango markup. (See gtk_label_get_label())
1104 * Return value: the text in the label widget. This is the internal
1105 * string used by the label, and must not be modified.
1107 G_CONST_RETURN gchar *
1108 gtk_label_get_text (GtkLabel *label)
1110 g_return_val_if_fail (GTK_IS_LABEL (label), NULL);
1115 static PangoAttrList *
1116 gtk_label_pattern_to_attrs (GtkLabel *label,
1117 const gchar *pattern)
1120 const char *p = label->text;
1121 const char *q = pattern;
1122 PangoAttrList *attrs;
1124 attrs = pango_attr_list_new ();
1128 while (*p && *q && *q != '_')
1130 p = g_utf8_next_char (p);
1134 while (*p && *q && *q == '_')
1136 p = g_utf8_next_char (p);
1142 PangoAttribute *attr = pango_attr_underline_new (PANGO_UNDERLINE_LOW);
1143 attr->start_index = start - label->text;
1144 attr->end_index = p - label->text;
1146 pango_attr_list_insert (attrs, attr);
1156 gtk_label_set_pattern_internal (GtkLabel *label,
1157 const gchar *pattern)
1159 PangoAttrList *attrs;
1160 g_return_if_fail (GTK_IS_LABEL (label));
1162 attrs = gtk_label_pattern_to_attrs (label, pattern);
1164 if (label->effective_attrs)
1165 pango_attr_list_unref (label->effective_attrs);
1166 label->effective_attrs = attrs;
1170 gtk_label_set_pattern (GtkLabel *label,
1171 const gchar *pattern)
1173 g_return_if_fail (GTK_IS_LABEL (label));
1175 gtk_label_set_pattern_internal (label, pattern);
1177 gtk_label_clear_layout (label);
1178 gtk_widget_queue_resize (GTK_WIDGET (label));
1183 * gtk_label_set_justify:
1184 * @label: a #GtkLabel
1185 * @jtype: a #GtkJustification
1187 * Sets the alignment of the lines in the text of the label relative to
1188 * each other. %GTK_JUSTIFY_LEFT is the default value when the
1189 * widget is first created with gtk_label_new(). If you instead want
1190 * to set the alignment of the label as a whole, use
1191 * gtk_misc_set_alignment() instead. gtk_label_set_justify() has no
1192 * effect on labels containing only a single line.
1195 gtk_label_set_justify (GtkLabel *label,
1196 GtkJustification jtype)
1198 g_return_if_fail (GTK_IS_LABEL (label));
1199 g_return_if_fail (jtype >= GTK_JUSTIFY_LEFT && jtype <= GTK_JUSTIFY_FILL);
1201 if ((GtkJustification) label->jtype != jtype)
1203 label->jtype = jtype;
1205 /* No real need to be this drastic, but easier than duplicating the code */
1206 gtk_label_clear_layout (label);
1208 g_object_notify (G_OBJECT (label), "justify");
1209 gtk_widget_queue_resize (GTK_WIDGET (label));
1214 * gtk_label_get_justify:
1215 * @label: a #GtkLabel
1217 * Returns the justification of the label. See gtk_label_set_justify ().
1219 * Return value: #GtkJustification
1222 gtk_label_get_justify (GtkLabel *label)
1224 g_return_val_if_fail (GTK_IS_LABEL (label), 0);
1226 return label->jtype;
1230 * gtk_label_set_line_wrap:
1231 * @label: a #GtkLabel
1232 * @wrap: the setting
1234 * Toggles line wrapping within the #GtkLabel widget. %TRUE makes it break
1235 * lines if text exceeds the widget's size. %FALSE lets the text get cut off
1236 * by the edge of the widget if it exceeds the widget size.
1239 gtk_label_set_line_wrap (GtkLabel *label,
1242 g_return_if_fail (GTK_IS_LABEL (label));
1244 wrap = wrap != FALSE;
1246 if (label->wrap != wrap)
1249 g_object_notify (G_OBJECT (label), "wrap");
1251 gtk_widget_queue_resize (GTK_WIDGET (label));
1256 * gtk_label_get_line_wrap:
1257 * @label: a #GtkLabel
1259 * Returns whether lines in the label are automatically wrapped. See gtk_label_set_line_wrap ().
1261 * Return value: %TRUE if the lines of the label are automatically wrapped.
1264 gtk_label_get_line_wrap (GtkLabel *label)
1266 g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
1272 gtk_label_get (GtkLabel *label,
1275 g_return_if_fail (GTK_IS_LABEL (label));
1276 g_return_if_fail (str != NULL);
1282 gtk_label_destroy (GtkObject *object)
1284 GtkLabel *label = GTK_LABEL (object);
1286 gtk_label_set_mnemonic_widget (label, NULL);
1288 GTK_OBJECT_CLASS (parent_class)->destroy (object);
1292 gtk_label_finalize (GObject *object)
1296 g_return_if_fail (GTK_IS_LABEL (object));
1298 label = GTK_LABEL (object);
1300 g_free (label->label);
1301 g_free (label->text);
1304 g_object_unref (G_OBJECT (label->layout));
1307 pango_attr_list_unref (label->attrs);
1309 if (label->effective_attrs)
1310 pango_attr_list_unref (label->effective_attrs);
1312 g_free (label->select_info);
1314 G_OBJECT_CLASS (parent_class)->finalize (object);
1318 gtk_label_clear_layout (GtkLabel *label)
1322 g_object_unref (G_OBJECT (label->layout));
1323 label->layout = NULL;
1327 typedef struct _LabelWrapWidth LabelWrapWidth;
1328 struct _LabelWrapWidth
1331 PangoFontDescription *font_desc;
1335 label_wrap_width_free (gpointer data)
1337 LabelWrapWidth *wrap_width = data;
1338 pango_font_description_free (wrap_width->font_desc);
1339 g_free (wrap_width);
1343 get_label_wrap_width (GtkLabel *label)
1345 PangoLayout *layout;
1346 GtkStyle *style = GTK_WIDGET (label)->style;
1348 LabelWrapWidth *wrap_width = g_object_get_data (G_OBJECT (style), "gtk-label-wrap-width");
1351 wrap_width = g_new0 (LabelWrapWidth, 1);
1352 g_object_set_data_full (G_OBJECT (style), "gtk-label-wrap-width",
1353 wrap_width, label_wrap_width_free);
1356 if (wrap_width->font_desc && pango_font_description_equal (wrap_width->font_desc, style->font_desc))
1357 return wrap_width->width;
1359 if (wrap_width->font_desc)
1360 pango_font_description_free (wrap_width->font_desc);
1362 wrap_width->font_desc = pango_font_description_copy (style->font_desc);
1364 layout = gtk_widget_create_pango_layout (GTK_WIDGET (label),
1365 "This long string gives a good enough length for any line to have.");
1366 pango_layout_get_size (layout, &wrap_width->width, NULL);
1367 g_object_unref (layout);
1369 return wrap_width->width;
1373 gtk_label_ensure_layout (GtkLabel *label)
1376 PangoRectangle logical_rect;
1377 gint rwidth, rheight;
1379 widget = GTK_WIDGET (label);
1381 rwidth = label->misc.xpad * 2;
1382 rheight = label->misc.ypad * 2;
1386 PangoAlignment align = PANGO_ALIGN_LEFT; /* Quiet gcc */
1388 label->layout = gtk_widget_create_pango_layout (widget, label->text);
1390 if (label->effective_attrs)
1391 pango_layout_set_attributes (label->layout, label->effective_attrs);
1393 switch (label->jtype)
1395 case GTK_JUSTIFY_LEFT:
1396 align = PANGO_ALIGN_LEFT;
1398 case GTK_JUSTIFY_RIGHT:
1399 align = PANGO_ALIGN_RIGHT;
1401 case GTK_JUSTIFY_CENTER:
1402 align = PANGO_ALIGN_CENTER;
1404 case GTK_JUSTIFY_FILL:
1405 /* FIXME: This just doesn't work to do this */
1406 align = PANGO_ALIGN_LEFT;
1407 pango_layout_set_justify (label->layout, TRUE);
1410 g_assert_not_reached();
1413 pango_layout_set_alignment (label->layout, align);
1417 GtkWidgetAuxInfo *aux_info;
1418 gint longest_paragraph;
1421 aux_info = _gtk_widget_get_aux_info (widget, FALSE);
1422 if (aux_info && aux_info->width > 0)
1423 pango_layout_set_width (label->layout, aux_info->width * PANGO_SCALE);
1428 pango_layout_set_width (label->layout, -1);
1429 pango_layout_get_extents (label->layout, NULL, &logical_rect);
1431 width = logical_rect.width;
1433 /* Try to guess a reasonable maximum width */
1434 longest_paragraph = width;
1436 wrap_width = get_label_wrap_width (label);
1437 width = MIN (width, wrap_width);
1439 PANGO_SCALE * (gdk_screen_width () + 1) / 2);
1441 pango_layout_set_width (label->layout, width);
1442 pango_layout_get_extents (label->layout, NULL, &logical_rect);
1443 height = logical_rect.height;
1445 /* Unfortunately, the above may leave us with a very unbalanced looking paragraph,
1446 * so we try short search for a narrower width that leaves us with the same height
1448 if (longest_paragraph > 0)
1450 gint nlines, perfect_width;
1452 nlines = pango_layout_get_line_count (label->layout);
1453 perfect_width = (longest_paragraph + nlines - 1) / nlines;
1455 if (perfect_width < width)
1457 pango_layout_set_width (label->layout, perfect_width);
1458 pango_layout_get_extents (label->layout, NULL, &logical_rect);
1460 if (logical_rect.height <= height)
1461 width = perfect_width;
1464 gint mid_width = (perfect_width + width) / 2;
1466 if (mid_width > perfect_width)
1468 pango_layout_set_width (label->layout, mid_width);
1469 pango_layout_get_extents (label->layout, NULL, &logical_rect);
1471 if (logical_rect.height <= height)
1477 pango_layout_set_width (label->layout, width);
1480 else /* !label->wrap */
1481 pango_layout_set_width (label->layout, -1);
1486 gtk_label_size_request (GtkWidget *widget,
1487 GtkRequisition *requisition)
1491 PangoRectangle logical_rect;
1492 GtkWidgetAuxInfo *aux_info;
1494 g_return_if_fail (GTK_IS_LABEL (widget));
1495 g_return_if_fail (requisition != NULL);
1497 label = GTK_LABEL (widget);
1500 * If word wrapping is on, then the height requisition can depend
1503 * - Any width set on the widget via gtk_widget_set_usize().
1504 * - The padding of the widget (xpad, set by gtk_misc_set_padding)
1506 * Instead of trying to detect changes to these quantities, if we
1507 * are wrapping, we just rewrap for each size request. Since
1508 * size requisitions are cached by the GTK+ core, this is not
1513 gtk_label_clear_layout (label);
1515 gtk_label_ensure_layout (label);
1517 width = label->misc.xpad * 2;
1518 height = label->misc.ypad * 2;
1520 pango_layout_get_extents (label->layout, NULL, &logical_rect);
1522 aux_info = _gtk_widget_get_aux_info (widget, FALSE);
1523 if (label->wrap && aux_info && aux_info->width > 0)
1524 width += aux_info->width;
1526 width += PANGO_PIXELS (logical_rect.width);
1528 height += PANGO_PIXELS (logical_rect.height);
1530 requisition->width = width;
1531 requisition->height = height;
1535 gtk_label_size_allocate (GtkWidget *widget,
1536 GtkAllocation *allocation)
1540 label = GTK_LABEL (widget);
1542 (* GTK_WIDGET_CLASS (parent_class)->size_allocate) (widget, allocation);
1544 if (label->select_info && label->select_info->window)
1546 gdk_window_move_resize (label->select_info->window,
1550 allocation->height);
1555 gtk_label_state_changed (GtkWidget *widget,
1556 GtkStateType prev_state)
1560 label = GTK_LABEL (widget);
1562 if (label->select_info)
1563 gtk_label_select_region (label, 0, 0);
1565 if (GTK_WIDGET_CLASS (parent_class)->state_changed)
1566 GTK_WIDGET_CLASS (parent_class)->state_changed (widget, prev_state);
1570 gtk_label_style_set (GtkWidget *widget,
1571 GtkStyle *previous_style)
1575 g_return_if_fail (GTK_IS_LABEL (widget));
1577 label = GTK_LABEL (widget);
1579 /* We have to clear the layout, fonts etc. may have changed */
1580 gtk_label_clear_layout (label);
1584 gtk_label_direction_changed (GtkWidget *widget,
1585 GtkTextDirection previous_dir)
1587 GtkLabel *label = GTK_LABEL (widget);
1590 pango_layout_context_changed (label->layout);
1592 GTK_WIDGET_CLASS (parent_class)->direction_changed (widget, previous_dir);
1597 gtk_label_paint_word (GtkLabel *label,
1603 GtkWidget *widget = GTK_WIDGET (label);
1604 GtkLabelULine *uline;
1607 tmp_str = gdk_wcstombs (word->beginning);
1610 gtk_paint_string (widget->style, widget->window, widget->state,
1611 area, widget, "label",
1618 for (uline = word->uline; uline; uline = uline->next)
1619 gtk_paint_hline (widget->style, widget->window,
1620 widget->state, area,
1622 x + uline->x1, x + uline->x2, y + uline->y);
1627 get_layout_location (GtkLabel *label,
1636 misc = GTK_MISC (label);
1637 widget = GTK_WIDGET (label);
1639 if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
1640 xalign = misc->xalign;
1642 xalign = 1.0 - misc->xalign;
1644 x = floor (widget->allocation.x + (gint)misc->xpad
1645 + ((widget->allocation.width - widget->requisition.width) * xalign)
1648 y = floor (widget->allocation.y + (gint)misc->ypad
1649 + ((widget->allocation.height - widget->requisition.height) * misc->yalign)
1661 gtk_label_draw_cursor (GtkLabel *label, gint xoffset, gint yoffset)
1663 if (label->select_info == NULL)
1666 if (GTK_WIDGET_DRAWABLE (label))
1668 GtkWidget *widget = GTK_WIDGET (label);
1670 GtkTextDirection keymap_direction;
1671 GtkTextDirection widget_direction;
1672 PangoRectangle strong_pos, weak_pos;
1673 gboolean split_cursor;
1674 PangoRectangle *cursor1 = NULL;
1675 PangoRectangle *cursor2 = NULL;
1676 GdkRectangle cursor_location;
1677 GtkTextDirection dir1 = GTK_TEXT_DIR_NONE;
1678 GtkTextDirection dir2 = GTK_TEXT_DIR_NONE;
1683 (gdk_keymap_get_direction (gdk_keymap_get_default ()) == PANGO_DIRECTION_LTR) ?
1684 GTK_TEXT_DIR_LTR : GTK_TEXT_DIR_RTL;
1686 widget_direction = gtk_widget_get_direction (widget);
1688 gtk_label_ensure_layout (label);
1690 pango_layout_get_cursor_pos (label->layout, label->select_info->selection_end,
1691 &strong_pos, &weak_pos);
1693 g_object_get (gtk_widget_get_settings (widget),
1694 "gtk-split-cursor", &split_cursor,
1697 dir1 = widget_direction;
1701 gc1 = label->select_info->cursor_gc;
1702 cursor1 = &strong_pos;
1704 if (strong_pos.x != weak_pos.x ||
1705 strong_pos.y != weak_pos.y)
1707 dir2 = (widget_direction == GTK_TEXT_DIR_LTR) ? GTK_TEXT_DIR_RTL : GTK_TEXT_DIR_LTR;
1709 gc2 = widget->style->black_gc;
1710 cursor2 = &weak_pos;
1715 gc1 = label->select_info->cursor_gc;
1717 if (keymap_direction == widget_direction)
1718 cursor1 = &strong_pos;
1720 cursor1 = &weak_pos;
1723 cursor_location.x = xoffset + PANGO_PIXELS (cursor1->x);
1724 cursor_location.y = yoffset + PANGO_PIXELS (cursor1->y);
1725 cursor_location.width = 0;
1726 cursor_location.height = PANGO_PIXELS (cursor1->height);
1728 _gtk_draw_insertion_cursor (widget, widget->window, gc1,
1729 &cursor_location, dir1,
1730 dir2 != GTK_TEXT_DIR_NONE);
1732 if (dir2 != GTK_TEXT_DIR_NONE)
1734 cursor_location.x = xoffset + PANGO_PIXELS (cursor2->x);
1735 cursor_location.y = yoffset + PANGO_PIXELS (cursor2->y);
1736 cursor_location.width = 0;
1737 cursor_location.height = PANGO_PIXELS (cursor2->height);
1739 _gtk_draw_insertion_cursor (widget, widget->window, gc2,
1740 &cursor_location, dir2, TRUE);
1747 gtk_label_expose (GtkWidget *widget,
1748 GdkEventExpose *event)
1753 g_return_val_if_fail (GTK_IS_LABEL (widget), FALSE);
1754 g_return_val_if_fail (event != NULL, FALSE);
1756 label = GTK_LABEL (widget);
1758 gtk_label_ensure_layout (label);
1760 if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_MAPPED (widget) &&
1761 label->text && (*label->text != '\0'))
1763 get_layout_location (label, &x, &y);
1765 gtk_paint_layout (widget->style,
1767 GTK_WIDGET_STATE (widget),
1775 if (label->select_info &&
1776 (label->select_info->selection_anchor !=
1777 label->select_info->selection_end))
1783 range[0] = label->select_info->selection_anchor;
1784 range[1] = label->select_info->selection_end;
1786 if (range[0] > range[1])
1788 gint tmp = range[0];
1789 range[0] = range[1];
1793 clip = gdk_pango_layout_get_clip_region (label->layout,
1798 /* FIXME should use gtk_paint, but it can't use a clip
1802 gdk_gc_set_clip_region (widget->style->black_gc, clip);
1805 state = GTK_STATE_SELECTED;
1806 if (!GTK_WIDGET_HAS_FOCUS (widget))
1807 state = GTK_STATE_ACTIVE;
1809 gdk_draw_layout_with_colors (widget->window,
1810 widget->style->black_gc,
1813 &widget->style->text[state],
1814 &widget->style->base[state]);
1816 gdk_gc_set_clip_region (widget->style->black_gc, NULL);
1817 gdk_region_destroy (clip);
1819 else if (label->select_info && GTK_WIDGET_HAS_FOCUS (widget))
1820 gtk_label_draw_cursor (label, x, y);
1827 gtk_label_set_uline_text_internal (GtkLabel *label,
1830 guint accel_key = GDK_VoidSymbol;
1835 gchar *dest, *pattern_dest;
1836 gboolean underscore;
1838 g_return_if_fail (GTK_IS_LABEL (label));
1839 g_return_if_fail (str != NULL);
1841 /* Convert text to wide characters */
1843 new_str = g_new (gchar, strlen (str) + 1);
1844 pattern = g_new (gchar, g_utf8_strlen (str, -1) + 1);
1853 pattern_dest = pattern;
1860 c = g_utf8_get_char (src);
1861 if (c == (gunichar)-1)
1863 g_warning ("Invalid input string");
1868 next_src = g_utf8_next_char (src);
1873 *pattern_dest++ = ' ';
1876 *pattern_dest++ = '_';
1877 if (accel_key == GDK_VoidSymbol)
1878 accel_key = gdk_keyval_to_lower (gdk_unicode_to_keyval (c));
1881 while (src < next_src)
1895 while (src < next_src)
1898 *pattern_dest++ = ' ';
1905 gtk_label_set_text_internal (label, new_str);
1906 gtk_label_set_pattern_internal (label, pattern);
1910 label->mnemonic_keyval = accel_key;
1914 gtk_label_parse_uline (GtkLabel *label,
1920 g_return_val_if_fail (GTK_IS_LABEL (label), GDK_VoidSymbol);
1921 g_return_val_if_fail (str != NULL, GDK_VoidSymbol);
1923 orig_keyval = label->mnemonic_keyval;
1925 gtk_label_set_label_internal (label, g_strdup (str ? str : ""));
1926 gtk_label_set_use_markup_internal (label, FALSE);
1927 gtk_label_set_use_underline_internal (label, TRUE);
1929 gtk_label_recalculate (label);
1931 keyval = label->mnemonic_keyval;
1932 label->mnemonic_keyval = GDK_VoidSymbol;
1934 gtk_label_setup_mnemonic (label, orig_keyval);
1940 * gtk_label_set_text_with_mnemonic:
1941 * @label: a #GtkLabel
1944 * Sets the label's text from the string @str.
1945 * If characters in @str are preceded by an underscore, they are underlined
1946 * indicating that they represent a keyboard accelerator called a mnemonic.
1947 * The mnemonic key can be used to activate another widget, chosen automatically,
1948 * or explicitly using gtk_label_set_mnemonic_widget().
1951 gtk_label_set_text_with_mnemonic (GtkLabel *label,
1956 g_return_if_fail (GTK_IS_LABEL (label));
1957 g_return_if_fail (str != NULL);
1959 last_keyval = label->mnemonic_keyval;
1961 gtk_label_set_label_internal (label, g_strdup (str ? str : ""));
1962 gtk_label_set_use_markup_internal (label, FALSE);
1963 gtk_label_set_use_underline_internal (label, TRUE);
1965 gtk_label_recalculate (label);
1967 gtk_label_setup_mnemonic (label, last_keyval);
1971 gtk_label_realize_cursor_gc (GtkLabel *label)
1973 GdkColor *cursor_color;
1974 GdkColor red = {0, 0xffff, 0x0000, 0x0000};
1976 if (label->select_info == NULL)
1979 if (label->select_info->cursor_gc)
1980 gdk_gc_unref (label->select_info->cursor_gc);
1982 gtk_widget_style_get (GTK_WIDGET (label), "cursor-color", &cursor_color, NULL);
1983 label->select_info->cursor_gc = gdk_gc_new (GTK_WIDGET (label)->window);
1985 gdk_gc_set_rgb_fg_color (label->select_info->cursor_gc, cursor_color);
1987 gdk_gc_set_rgb_fg_color (label->select_info->cursor_gc, &red);
1991 gtk_label_realize (GtkWidget *widget)
1995 label = GTK_LABEL (widget);
1997 (* GTK_WIDGET_CLASS (parent_class)->realize) (widget);
1999 if (label->select_info)
2001 gtk_label_create_window (label);
2002 gtk_label_realize_cursor_gc (label);
2007 gtk_label_unrealize_cursor_gc (GtkLabel *label)
2009 if (label->select_info == NULL)
2012 if (label->select_info->cursor_gc)
2014 gdk_gc_unref (label->select_info->cursor_gc);
2015 label->select_info->cursor_gc = NULL;
2020 gtk_label_unrealize (GtkWidget *widget)
2024 label = GTK_LABEL (widget);
2026 if (label->select_info)
2028 gtk_label_unrealize_cursor_gc (label);
2029 gtk_label_destroy_window (label);
2032 (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
2036 gtk_label_map (GtkWidget *widget)
2040 label = GTK_LABEL (widget);
2042 (* GTK_WIDGET_CLASS (parent_class)->map) (widget);
2044 if (label->select_info)
2045 gdk_window_show (label->select_info->window);
2049 gtk_label_unmap (GtkWidget *widget)
2053 label = GTK_LABEL (widget);
2055 if (label->select_info)
2056 gdk_window_hide (label->select_info->window);
2058 (* GTK_WIDGET_CLASS (parent_class)->unmap) (widget);
2062 window_to_layout_coords (GtkLabel *label,
2069 widget = GTK_WIDGET (label);
2071 /* get layout location in widget->window coords */
2072 get_layout_location (label, &lx, &ly);
2076 *x += widget->allocation.x; /* go to widget->window */
2077 *x -= lx; /* go to layout */
2082 *y += widget->allocation.y; /* go to widget->window */
2083 *y -= ly; /* go to layout */
2089 layout_to_window_coords (GtkLabel *label,
2096 widget = GTK_WIDGET (label);
2098 /* get layout location in widget->window coords */
2099 get_layout_location (label, &lx, &ly);
2103 *x += lx; /* go to widget->window */
2104 *x -= widget->allocation.x; /* go to selection window */
2109 *y += ly; /* go to widget->window */
2110 *y -= widget->allocation.y; /* go to selection window */
2116 get_layout_index (GtkLabel *label,
2122 const gchar *cluster;
2123 const gchar *cluster_end;
2127 gtk_label_ensure_layout (label);
2129 window_to_layout_coords (label, &x, &y);
2134 pango_layout_xy_to_index (label->layout,
2139 cluster = label->text + *index;
2140 cluster_end = cluster;
2143 cluster_end = g_utf8_next_char (cluster_end);
2147 *index += (cluster_end - cluster);
2151 gtk_label_select_word (GtkLabel *label)
2155 gint start_index = gtk_label_move_backward_word (label, label->select_info->selection_end);
2156 gint end_index = gtk_label_move_forward_word (label, label->select_info->selection_end);
2158 min = MIN (label->select_info->selection_anchor,
2159 label->select_info->selection_end);
2160 max = MAX (label->select_info->selection_anchor,
2161 label->select_info->selection_end);
2163 min = MIN (min, start_index);
2164 max = MAX (max, end_index);
2166 gtk_label_select_region_index (label, min, max);
2170 gtk_label_button_press (GtkWidget *widget,
2171 GdkEventButton *event)
2176 label = GTK_LABEL (widget);
2178 if (label->select_info == NULL)
2181 if (event->button == 1)
2183 if (!GTK_WIDGET_HAS_FOCUS (widget))
2184 gtk_widget_grab_focus (widget);
2186 if (event->type == GDK_3BUTTON_PRESS)
2188 gtk_label_select_region_index (label, 0, strlen (label->label));
2192 if (event->type == GDK_2BUTTON_PRESS)
2194 gtk_label_select_word (label);
2198 get_layout_index (label, event->x, event->y, &index);
2200 if ((label->select_info->selection_anchor !=
2201 label->select_info->selection_end) &&
2202 (event->state & GDK_SHIFT_MASK))
2206 /* extend (same as motion) */
2207 min = MIN (label->select_info->selection_anchor,
2208 label->select_info->selection_end);
2209 max = MAX (label->select_info->selection_anchor,
2210 label->select_info->selection_end);
2212 min = MIN (min, index);
2213 max = MAX (max, index);
2215 /* ensure the anchor is opposite index */
2223 gtk_label_select_region_index (label, min, max);
2227 if (event->type == GDK_3BUTTON_PRESS)
2228 gtk_label_select_region_index (label, 0, strlen (label->label));
2229 else if (event->type == GDK_2BUTTON_PRESS)
2230 gtk_label_select_word (label);
2232 /* start a replacement */
2233 gtk_label_select_region_index (label, index, index);
2238 else if (event->button == 3 && event->type == GDK_BUTTON_PRESS)
2240 gtk_label_do_popup (label, event);
2249 gtk_label_button_release (GtkWidget *widget,
2250 GdkEventButton *event)
2255 label = GTK_LABEL (widget);
2257 if (label->select_info == NULL)
2260 if (event->button != 1)
2263 /* The goal here is to return TRUE iff we ate the
2264 * button press to start selecting.
2271 gtk_label_motion (GtkWidget *widget,
2272 GdkEventMotion *event)
2278 label = GTK_LABEL (widget);
2280 if (label->select_info == NULL)
2283 if ((event->state & GDK_BUTTON1_MASK) == 0)
2286 gdk_window_get_pointer (label->select_info->window,
2289 get_layout_index (label, x, y, &index);
2291 gtk_label_select_region_index (label,
2292 label->select_info->selection_anchor,
2299 gtk_label_create_window (GtkLabel *label)
2302 GdkWindowAttr attributes;
2303 gint attributes_mask;
2305 g_assert (label->select_info);
2306 g_assert (GTK_WIDGET_REALIZED (label));
2308 if (label->select_info->window)
2311 widget = GTK_WIDGET (label);
2313 attributes.x = widget->allocation.x;
2314 attributes.y = widget->allocation.y;
2315 attributes.width = widget->allocation.width;
2316 attributes.height = widget->allocation.height;
2317 attributes.window_type = GDK_WINDOW_TEMP;
2318 attributes.wclass = GDK_INPUT_ONLY;
2319 attributes.override_redirect = TRUE;
2320 attributes.cursor = gdk_cursor_new (GDK_XTERM);
2321 attributes.event_mask = gtk_widget_get_events (widget) |
2322 GDK_BUTTON_PRESS_MASK |
2323 GDK_BUTTON_RELEASE_MASK |
2324 GDK_BUTTON_MOTION_MASK;
2326 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_NOREDIR | GDK_WA_CURSOR;
2328 label->select_info->window = gdk_window_new (widget->window,
2329 &attributes, attributes_mask);
2330 gdk_window_set_user_data (label->select_info->window, widget);
2332 gdk_cursor_unref (attributes.cursor);
2336 gtk_label_destroy_window (GtkLabel *label)
2338 g_assert (label->select_info);
2340 if (label->select_info->window == NULL)
2343 gdk_window_set_user_data (label->select_info->window, NULL);
2344 gdk_window_destroy (label->select_info->window);
2345 label->select_info->window = NULL;
2349 * gtk_label_set_selectable:
2350 * @label: a #GtkLabel
2351 * @setting: %TRUE to allow selecting text in the label
2353 * Selectable labels allow the user to select text from the label, for
2358 gtk_label_set_selectable (GtkLabel *label,
2361 gboolean old_setting;
2363 g_return_if_fail (GTK_IS_LABEL (label));
2365 setting = setting != FALSE;
2366 old_setting = label->select_info != NULL;
2370 if (label->select_info == NULL)
2372 label->select_info = g_new0 (GtkLabelSelectionInfo, 1);
2374 GTK_WIDGET_SET_FLAGS (label, GTK_CAN_FOCUS);
2376 if (GTK_WIDGET_REALIZED (label))
2378 gtk_label_create_window (label);
2379 gtk_label_realize_cursor_gc (label);
2382 if (GTK_WIDGET_MAPPED (label))
2383 gdk_window_show (label->select_info->window);
2388 if (label->select_info)
2390 /* unselect, to give up the selection */
2391 gtk_label_select_region (label, 0, 0);
2393 gtk_label_unrealize_cursor_gc (label);
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_clipboard_get (GDK_SELECTION_PRIMARY);
2513 if (anchor_index != end_index)
2515 gtk_clipboard_set_with_owner (clipboard,
2517 G_N_ELEMENTS (targets),
2519 clear_text_callback,
2524 if (gtk_clipboard_get_owner (clipboard) == G_OBJECT (label))
2525 gtk_clipboard_clear (clipboard);
2528 gtk_widget_queue_draw (GTK_WIDGET (label));
2530 g_object_freeze_notify (G_OBJECT (label));
2531 g_object_notify (G_OBJECT (label), "cursor_position");
2532 g_object_notify (G_OBJECT (label), "selection_bound");
2533 g_object_thaw_notify (G_OBJECT (label));
2538 * gtk_label_select_region:
2539 * @label: a #GtkLabel
2540 * @start_offset: start offset (in characters not bytes)
2541 * @end_offset: end offset (in characters not bytes)
2543 * Selects a range of characters in the label, if the label is selectable.
2544 * See gtk_label_set_selectable(). If the label is not selectable,
2545 * this function has no effect. If @start_offset or
2546 * @end_offset are -1, then the end of the label will be substituted.
2550 gtk_label_select_region (GtkLabel *label,
2554 g_return_if_fail (GTK_IS_LABEL (label));
2556 if (label->text && label->select_info)
2558 if (start_offset < 0)
2559 start_offset = g_utf8_strlen (label->text, -1);
2562 end_offset = g_utf8_strlen (label->text, -1);
2564 gtk_label_select_region_index (label,
2565 g_utf8_offset_to_pointer (label->text, start_offset) - label->text,
2566 g_utf8_offset_to_pointer (label->text, end_offset) - label->text);
2571 * gtk_label_get_selection_bounds:
2572 * @label: a #GtkLabel
2573 * @start: return location for start of selection, as a character offset
2574 * @end: return location for end of selection, as a character offset
2576 * Gets the selected range of characters in the label, returning %TRUE
2577 * if there's a selection.
2579 * Return value: %TRUE if selection is non-empty
2582 gtk_label_get_selection_bounds (GtkLabel *label,
2586 g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
2588 if (label->select_info == NULL)
2590 /* not a selectable label */
2600 gint start_index, end_index;
2601 gint start_offset, end_offset;
2604 start_index = MIN (label->select_info->selection_anchor,
2605 label->select_info->selection_end);
2606 end_index = MAX (label->select_info->selection_anchor,
2607 label->select_info->selection_end);
2609 len = strlen (label->text);
2611 if (end_index > len)
2614 if (start_index > len)
2617 start_offset = g_utf8_strlen (label->text, start_index);
2618 end_offset = g_utf8_strlen (label->text, end_index);
2620 if (start_offset > end_offset)
2622 gint tmp = start_offset;
2623 start_offset = end_offset;
2628 *start = start_offset;
2633 return start_offset != end_offset;
2639 * gtk_label_get_layout:
2640 * @label: a #GtkLabel
2642 * Gets the #PangoLayout used to display the label.
2643 * The layout is useful to e.g. convert text positions to
2644 * pixel positions, in combination with gtk_label_get_layout_offsets().
2645 * The returned layout is owned by the label so need not be
2646 * freed by the caller.
2648 * Return value: the #PangoLayout for this label
2651 gtk_label_get_layout (GtkLabel *label)
2653 g_return_val_if_fail (GTK_IS_LABEL (label), NULL);
2655 gtk_label_ensure_layout (label);
2657 return label->layout;
2661 * gtk_label_get_layout_offsets:
2662 * @label: a #GtkLabel
2663 * @x: location to store X offset of layout, or %NULL
2664 * @y: location to store Y offset of layout, or %NULL
2666 * Obtains the coordinates where the label will draw the #PangoLayout
2667 * representing the text in the label; useful to convert mouse events
2668 * into coordinates inside the #PangoLayout, e.g. to take some action
2669 * if some part of the label is clicked. Of course you will need to
2670 * create a #GtkEventBox to receive the events, and pack the label
2671 * inside it, since labels are a #GTK_NO_WINDOW widget. Remember
2672 * when using the #PangoLayout functions you need to convert to
2673 * and from pixels using PANGO_PIXELS() or #PANGO_SCALE.
2677 gtk_label_get_layout_offsets (GtkLabel *label,
2681 g_return_if_fail (GTK_IS_LABEL (label));
2683 get_layout_location (label, x, y);
2687 * gtk_label_set_use_markup:
2688 * @label: a #GtkLabel
2689 * @setting: %TRUE if the label's text should be parsed for markup.
2691 * Sets whether the text of the label contains markup in <link
2692 * linkend="PangoMarkupFormat">Pango's text markup
2693 * language</link>. See gtk_label_set_markup().
2696 gtk_label_set_use_markup (GtkLabel *label,
2699 g_return_if_fail (GTK_IS_LABEL (label));
2701 gtk_label_set_use_markup_internal (label, setting);
2702 gtk_label_recalculate (label);
2706 * gtk_label_get_use_markup:
2707 * @label: a #GtkLabel
2709 * Returns whether the label's text is interpreted as marked up with
2710 * the <link linkend="PangoMarkupFormat">Pango text markup
2711 * language</link>. See gtk_label_set_use_markup ().
2713 * Return value: %TRUE if the label's text will be parsed for markup.
2716 gtk_label_get_use_markup (GtkLabel *label)
2718 g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
2720 return label->use_markup;
2724 * gtk_label_set_use_underline:
2725 * @label: a #GtkLabel
2726 * @setting: %TRUE if underlines in the text indicate mnemonics
2728 * If true, an underline in the text indicates the next character should be
2729 * used for the mnemonic accelerator key.
2732 gtk_label_set_use_underline (GtkLabel *label,
2735 g_return_if_fail (GTK_IS_LABEL (label));
2737 gtk_label_set_use_underline_internal (label, setting);
2738 gtk_label_recalculate (label);
2739 if (label->use_underline)
2740 gtk_label_setup_mnemonic (label, label->mnemonic_keyval);
2744 * gtk_label_get_use_underline:
2745 * @label: a #GtkLabel
2747 * Returns whether an embedded underline in the label indicates a
2748 * mnemonic. See gtk_label_set_use_underline ().
2750 * Return value: %TRUE whether an embedded underline in the label indicates
2751 * the mnemonic accelerator keys.
2754 gtk_label_get_use_underline (GtkLabel *label)
2756 g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
2758 return label->use_underline;
2762 gtk_label_focus (GtkWidget *widget,
2763 GtkDirectionType direction)
2765 /* We never want to be in the tab chain */
2769 /* Compute the X position for an offset that corresponds to the "more important
2770 * cursor position for that offset. We use this when trying to guess to which
2771 * end of the selection we should go to when the user hits the left or
2775 get_better_cursor (GtkLabel *label,
2780 GtkTextDirection keymap_direction =
2781 (gdk_keymap_get_direction (gdk_keymap_get_default ()) == PANGO_DIRECTION_LTR) ?
2782 GTK_TEXT_DIR_LTR : GTK_TEXT_DIR_RTL;
2783 GtkTextDirection widget_direction = gtk_widget_get_direction (GTK_WIDGET (label));
2784 gboolean split_cursor;
2785 PangoRectangle strong_pos, weak_pos;
2787 g_object_get (gtk_widget_get_settings (GTK_WIDGET (label)),
2788 "gtk-split-cursor", &split_cursor,
2791 gtk_label_ensure_layout (label);
2793 pango_layout_get_cursor_pos (label->layout, index,
2794 &strong_pos, &weak_pos);
2798 *x = strong_pos.x / PANGO_SCALE;
2799 *y = strong_pos.y / PANGO_SCALE;
2803 if (keymap_direction == widget_direction)
2805 *x = strong_pos.x / PANGO_SCALE;
2806 *y = strong_pos.y / PANGO_SCALE;
2810 *x = weak_pos.x / PANGO_SCALE;
2811 *y = weak_pos.y / PANGO_SCALE;
2818 gtk_label_move_logically (GtkLabel *label,
2822 gint offset = g_utf8_pointer_to_offset (label->label,
2823 label->label + start);
2827 PangoLogAttr *log_attrs;
2831 gtk_label_ensure_layout (label);
2833 length = g_utf8_strlen (label->label, -1);
2835 pango_layout_get_log_attrs (label->layout, &log_attrs, &n_attrs);
2837 while (count > 0 && offset < length)
2841 while (offset < length && !log_attrs[offset].is_cursor_position);
2845 while (count < 0 && offset > 0)
2849 while (offset > 0 && !log_attrs[offset].is_cursor_position);
2857 return g_utf8_offset_to_pointer (label->label, offset) - label->label;
2861 gtk_label_move_visually (GtkLabel *label,
2871 int new_index, new_trailing;
2872 gboolean split_cursor;
2875 gtk_label_ensure_layout (label);
2877 g_object_get (gtk_widget_get_settings (GTK_WIDGET (label)),
2878 "gtk-split-cursor", &split_cursor,
2885 GtkTextDirection keymap_direction =
2886 (gdk_keymap_get_direction (gdk_keymap_get_default ()) == PANGO_DIRECTION_LTR) ?
2887 GTK_TEXT_DIR_LTR : GTK_TEXT_DIR_RTL;
2889 strong = keymap_direction == gtk_widget_get_direction (GTK_WIDGET (label));
2894 pango_layout_move_cursor_visually (label->layout, strong, index, 0, 1, &new_index, &new_trailing);
2899 pango_layout_move_cursor_visually (label->layout, strong, index, 0, -1, &new_index, &new_trailing);
2903 if (new_index < 0 || new_index == G_MAXINT)
2908 while (new_trailing--)
2909 index = g_utf8_next_char (label->label + new_index) - label->label;
2916 gtk_label_move_forward_word (GtkLabel *label,
2919 gint new_pos = g_utf8_pointer_to_offset (label->label,
2920 label->label + start);
2923 length = g_utf8_strlen (label->label, -1);
2924 if (new_pos < length)
2926 PangoLogAttr *log_attrs;
2929 gtk_label_ensure_layout (label);
2931 pango_layout_get_log_attrs (label->layout, &log_attrs, &n_attrs);
2933 /* Find the next word end */
2935 while (new_pos < n_attrs && !log_attrs[new_pos].is_word_end)
2941 return g_utf8_offset_to_pointer (label->label, new_pos) - label->label;
2946 gtk_label_move_backward_word (GtkLabel *label,
2949 gint new_pos = g_utf8_pointer_to_offset (label->label,
2950 label->label + start);
2953 length = g_utf8_strlen (label->label, -1);
2957 PangoLogAttr *log_attrs;
2960 gtk_label_ensure_layout (label);
2962 pango_layout_get_log_attrs (label->layout, &log_attrs, &n_attrs);
2966 /* Find the previous word beginning */
2967 while (new_pos > 0 && !log_attrs[new_pos].is_word_start)
2973 return g_utf8_offset_to_pointer (label->label, new_pos) - label->label;
2977 gtk_label_move_cursor (GtkLabel *label,
2978 GtkMovementStep step,
2980 gboolean extend_selection)
2984 if (label->select_info == NULL)
2987 new_pos = label->select_info->selection_end;
2989 if (label->select_info->selection_end != label->select_info->selection_anchor &&
2992 /* If we have a current selection and aren't extending it, move to the
2993 * start/or end of the selection as appropriate
2997 case GTK_MOVEMENT_VISUAL_POSITIONS:
3000 gint anchor_x, anchor_y;
3001 gboolean end_is_left;
3003 get_better_cursor (label, label->select_info->selection_end, &end_x, &end_y);
3004 get_better_cursor (label, label->select_info->selection_anchor, &anchor_x, &anchor_y);
3006 end_is_left = (end_y < anchor_y) || (end_y == anchor_y && end_x < anchor_x);
3009 new_pos = end_is_left ? label->select_info->selection_end : label->select_info->selection_anchor;
3011 new_pos = !end_is_left ? label->select_info->selection_end : label->select_info->selection_anchor;
3015 case GTK_MOVEMENT_LOGICAL_POSITIONS:
3016 case GTK_MOVEMENT_WORDS:
3018 new_pos = MIN (label->select_info->selection_end, label->select_info->selection_anchor);
3020 new_pos = MAX (label->select_info->selection_end, label->select_info->selection_anchor);
3022 case GTK_MOVEMENT_DISPLAY_LINE_ENDS:
3023 case GTK_MOVEMENT_PARAGRAPH_ENDS:
3024 case GTK_MOVEMENT_BUFFER_ENDS:
3025 /* FIXME: Can do better here */
3026 new_pos = count < 0 ? 0 : strlen (label->label);
3028 case GTK_MOVEMENT_DISPLAY_LINES:
3029 case GTK_MOVEMENT_PARAGRAPHS:
3030 case GTK_MOVEMENT_PAGES:
3038 case GTK_MOVEMENT_LOGICAL_POSITIONS:
3039 new_pos = gtk_label_move_logically (label, new_pos, count);
3041 case GTK_MOVEMENT_VISUAL_POSITIONS:
3042 new_pos = gtk_label_move_visually (label, new_pos, count);
3044 case GTK_MOVEMENT_WORDS:
3047 new_pos = gtk_label_move_forward_word (label, new_pos);
3052 new_pos = gtk_label_move_backward_word (label, new_pos);
3056 case GTK_MOVEMENT_DISPLAY_LINE_ENDS:
3057 case GTK_MOVEMENT_PARAGRAPH_ENDS:
3058 case GTK_MOVEMENT_BUFFER_ENDS:
3059 /* FIXME: Can do better here */
3060 new_pos = count < 0 ? 0 : strlen (label->label);
3062 case GTK_MOVEMENT_DISPLAY_LINES:
3063 case GTK_MOVEMENT_PARAGRAPHS:
3064 case GTK_MOVEMENT_PAGES:
3069 if (extend_selection)
3070 gtk_label_select_region_index (label,
3071 label->select_info->selection_anchor,
3074 gtk_label_select_region_index (label, new_pos, new_pos);
3078 gtk_label_copy_clipboard (GtkLabel *label)
3080 if (label->text && label->select_info)
3085 start = MIN (label->select_info->selection_anchor,
3086 label->select_info->selection_end);
3087 end = MAX (label->select_info->selection_anchor,
3088 label->select_info->selection_end);
3090 len = strlen (label->text);
3099 gtk_clipboard_set_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
3100 label->text + start, end - start);
3105 gtk_label_select_all (GtkLabel *label)
3107 gtk_label_select_region_index (label, 0, strlen (label->label));
3110 /* Quick hack of a popup menu
3113 activate_cb (GtkWidget *menuitem,
3116 const gchar *signal = gtk_object_get_data (GTK_OBJECT (menuitem), "gtk-signal");
3117 gtk_signal_emit_by_name (GTK_OBJECT (label), signal);
3121 append_action_signal (GtkLabel *label,
3123 const gchar *stock_id,
3124 const gchar *signal,
3127 GtkWidget *menuitem = gtk_image_menu_item_new_from_stock (stock_id, NULL);
3129 gtk_object_set_data (GTK_OBJECT (menuitem), "gtk-signal", (char *)signal);
3130 gtk_signal_connect (GTK_OBJECT (menuitem), "activate",
3131 GTK_SIGNAL_FUNC (activate_cb), label);
3133 gtk_widget_set_sensitive (menuitem, sensitive);
3135 gtk_widget_show (menuitem);
3136 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
3140 popup_menu_detach (GtkWidget *attach_widget,
3144 label = GTK_LABEL (attach_widget);
3146 if (label->select_info)
3147 label->select_info->popup_menu = NULL;
3151 popup_position_func (GtkMenu *menu,
3161 label = GTK_LABEL (user_data);
3162 widget = GTK_WIDGET (label);
3164 if (label->select_info == NULL)
3167 g_return_if_fail (GTK_WIDGET_REALIZED (label));
3169 gdk_window_get_origin (widget->window, x, y);
3171 gtk_widget_size_request (label->select_info->popup_menu, &req);
3173 *x += widget->allocation.width / 2;
3174 *y += widget->allocation.height;
3176 *x = CLAMP (*x, 0, MAX (0, gdk_screen_width () - req.width));
3177 *y = CLAMP (*y, 0, MAX (0, gdk_screen_height () - req.height));
3182 gtk_label_do_popup (GtkLabel *label,
3183 GdkEventButton *event)
3185 GtkWidget *menuitem;
3186 gboolean have_selection;
3188 if (label->select_info == NULL)
3191 if (label->select_info->popup_menu)
3192 gtk_widget_destroy (label->select_info->popup_menu);
3194 label->select_info->popup_menu = gtk_menu_new ();
3196 gtk_menu_attach_to_widget (GTK_MENU (label->select_info->popup_menu),
3201 label->select_info->selection_anchor != label->select_info->selection_end;
3204 append_action_signal (label, label->select_info->popup_menu, GTK_STOCK_CUT, "cut_clipboard",
3206 append_action_signal (label, label->select_info->popup_menu, GTK_STOCK_COPY, "copy_clipboard",
3208 append_action_signal (label, label->select_info->popup_menu, GTK_STOCK_PASTE, "paste_clipboard",
3211 menuitem = gtk_menu_item_new_with_label (_("Select All"));
3212 gtk_signal_connect_object (GTK_OBJECT (menuitem), "activate",
3213 GTK_SIGNAL_FUNC (gtk_label_select_all), label);
3214 gtk_widget_show (menuitem);
3215 gtk_menu_shell_append (GTK_MENU_SHELL (label->select_info->popup_menu), menuitem);
3217 menuitem = gtk_separator_menu_item_new ();
3218 gtk_widget_show (menuitem);
3219 gtk_menu_shell_append (GTK_MENU_SHELL (label->select_info->popup_menu), menuitem);
3221 menuitem = gtk_menu_item_new_with_label (_("Input Methods"));
3222 gtk_widget_show (menuitem);
3223 gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), gtk_menu_new ());
3224 gtk_widget_set_sensitive (menuitem, FALSE);
3225 gtk_menu_shell_append (GTK_MENU_SHELL (label->select_info->popup_menu), menuitem);
3227 gtk_signal_emit (GTK_OBJECT (label),
3228 signals[POPULATE_POPUP],
3229 label->select_info->popup_menu);
3232 gtk_menu_popup (GTK_MENU (label->select_info->popup_menu), NULL, NULL,
3234 event->button, event->time);
3236 gtk_menu_popup (GTK_MENU (label->select_info->popup_menu), NULL, NULL,
3237 popup_position_func, label,
3238 0, gtk_get_current_event_time ());