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);
133 static void gtk_label_screen_changed (GtkWidget *widget,
134 GdkScreen *old_screen);
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 GType 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",
197 add_move_binding (GtkBindingSet *binding_set,
200 GtkMovementStep step,
203 g_return_if_fail ((modmask & GDK_SHIFT_MASK) == 0);
205 gtk_binding_entry_add_signal (binding_set, keyval, modmask,
209 G_TYPE_BOOLEAN, FALSE);
211 /* Selection-extending version */
212 gtk_binding_entry_add_signal (binding_set, keyval, modmask | GDK_SHIFT_MASK,
216 G_TYPE_BOOLEAN, TRUE);
220 gtk_label_class_init (GtkLabelClass *class)
222 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
223 GtkObjectClass *object_class = GTK_OBJECT_CLASS (class);
224 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
225 GtkBindingSet *binding_set;
227 parent_class = g_type_class_peek_parent (class);
229 gobject_class->set_property = gtk_label_set_property;
230 gobject_class->get_property = gtk_label_get_property;
231 gobject_class->finalize = gtk_label_finalize;
233 object_class->destroy = gtk_label_destroy;
235 widget_class->size_request = gtk_label_size_request;
236 widget_class->size_allocate = gtk_label_size_allocate;
237 widget_class->state_changed = gtk_label_state_changed;
238 widget_class->style_set = gtk_label_style_set;
239 widget_class->direction_changed = gtk_label_direction_changed;
240 widget_class->expose_event = gtk_label_expose;
241 widget_class->realize = gtk_label_realize;
242 widget_class->unrealize = gtk_label_unrealize;
243 widget_class->map = gtk_label_map;
244 widget_class->unmap = gtk_label_unmap;
245 widget_class->button_press_event = gtk_label_button_press;
246 widget_class->button_release_event = gtk_label_button_release;
247 widget_class->motion_notify_event = gtk_label_motion;
248 widget_class->hierarchy_changed = gtk_label_hierarchy_changed;
249 widget_class->screen_changed = gtk_label_screen_changed;
250 widget_class->mnemonic_activate = gtk_label_mnemonic_activate;
251 widget_class->focus = gtk_label_focus;
253 class->move_cursor = gtk_label_move_cursor;
254 class->copy_clipboard = gtk_label_copy_clipboard;
256 signals[MOVE_CURSOR] =
257 g_signal_new ("move_cursor",
258 G_OBJECT_CLASS_TYPE (gobject_class),
259 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
260 G_STRUCT_OFFSET (GtkLabelClass, move_cursor),
262 _gtk_marshal_VOID__ENUM_INT_BOOLEAN,
264 GTK_TYPE_MOVEMENT_STEP,
268 signals[COPY_CLIPBOARD] =
269 g_signal_new ("copy_clipboard",
270 G_OBJECT_CLASS_TYPE (gobject_class),
271 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
272 G_STRUCT_OFFSET (GtkLabelClass, copy_clipboard),
274 _gtk_marshal_VOID__VOID,
277 signals[POPULATE_POPUP] =
278 g_signal_new ("populate_popup",
279 G_OBJECT_CLASS_TYPE (gobject_class),
281 G_STRUCT_OFFSET (GtkLabelClass, populate_popup),
283 _gtk_marshal_VOID__OBJECT,
287 g_object_class_install_property (gobject_class,
289 g_param_spec_string ("label",
291 _("The text of the label"),
294 g_object_class_install_property (gobject_class,
296 g_param_spec_boxed ("attributes",
298 _("A list of style attributes to apply to the text of the label"),
299 PANGO_TYPE_ATTR_LIST,
301 g_object_class_install_property (gobject_class,
303 g_param_spec_boolean ("use_markup",
305 _("The text of the label includes XML markup. See pango_parse_markup()"),
308 g_object_class_install_property (gobject_class,
310 g_param_spec_boolean ("use_underline",
312 _("If set, an underline in the text indicates the next character should be used for the mnemonic accelerator key"),
316 g_object_class_install_property (gobject_class,
318 g_param_spec_enum ("justify",
320 _("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"),
321 GTK_TYPE_JUSTIFICATION,
325 g_object_class_install_property (gobject_class,
327 g_param_spec_string ("pattern",
329 _("A string with _ characters in positions correspond to characters in the text to underline"),
333 g_object_class_install_property (gobject_class,
335 g_param_spec_boolean ("wrap",
337 _("If set, wrap lines if the text becomes too wide"),
340 g_object_class_install_property (gobject_class,
342 g_param_spec_boolean ("selectable",
344 _("Whether the label text can be selected with the mouse"),
347 g_object_class_install_property (gobject_class,
348 PROP_MNEMONIC_KEYVAL,
349 g_param_spec_uint ("mnemonic_keyval",
351 _("The mnemonic accelerator key for this label"),
356 g_object_class_install_property (gobject_class,
357 PROP_MNEMONIC_WIDGET,
358 g_param_spec_object ("mnemonic_widget",
359 _("Mnemonic widget"),
360 _("The widget to be activated when the label's mnemonic "
365 g_object_class_install_property (gobject_class,
366 PROP_CURSOR_POSITION,
367 g_param_spec_int ("cursor_position",
368 _("Cursor Position"),
369 _("The current position of the insertion cursor in chars"),
375 g_object_class_install_property (gobject_class,
376 PROP_SELECTION_BOUND,
377 g_param_spec_int ("selection_bound",
378 _("Selection Bound"),
379 _("The position of the opposite end of the selection from the cursor in chars"),
389 binding_set = gtk_binding_set_by_class (class);
391 /* Moving the insertion point */
392 add_move_binding (binding_set, GDK_Right, 0,
393 GTK_MOVEMENT_VISUAL_POSITIONS, 1);
395 add_move_binding (binding_set, GDK_Left, 0,
396 GTK_MOVEMENT_VISUAL_POSITIONS, -1);
398 add_move_binding (binding_set, GDK_KP_Right, 0,
399 GTK_MOVEMENT_VISUAL_POSITIONS, 1);
401 add_move_binding (binding_set, GDK_KP_Left, 0,
402 GTK_MOVEMENT_VISUAL_POSITIONS, -1);
404 add_move_binding (binding_set, GDK_f, GDK_CONTROL_MASK,
405 GTK_MOVEMENT_LOGICAL_POSITIONS, 1);
407 add_move_binding (binding_set, GDK_b, GDK_CONTROL_MASK,
408 GTK_MOVEMENT_LOGICAL_POSITIONS, -1);
410 add_move_binding (binding_set, GDK_Right, GDK_CONTROL_MASK,
411 GTK_MOVEMENT_WORDS, 1);
413 add_move_binding (binding_set, GDK_Left, GDK_CONTROL_MASK,
414 GTK_MOVEMENT_WORDS, -1);
416 add_move_binding (binding_set, GDK_KP_Right, GDK_CONTROL_MASK,
417 GTK_MOVEMENT_WORDS, 1);
419 add_move_binding (binding_set, GDK_KP_Left, GDK_CONTROL_MASK,
420 GTK_MOVEMENT_WORDS, -1);
422 add_move_binding (binding_set, GDK_a, GDK_CONTROL_MASK,
423 GTK_MOVEMENT_PARAGRAPH_ENDS, -1);
425 add_move_binding (binding_set, GDK_e, GDK_CONTROL_MASK,
426 GTK_MOVEMENT_PARAGRAPH_ENDS, 1);
428 add_move_binding (binding_set, GDK_f, GDK_MOD1_MASK,
429 GTK_MOVEMENT_WORDS, 1);
431 add_move_binding (binding_set, GDK_b, GDK_MOD1_MASK,
432 GTK_MOVEMENT_WORDS, -1);
434 add_move_binding (binding_set, GDK_Home, 0,
435 GTK_MOVEMENT_DISPLAY_LINE_ENDS, -1);
437 add_move_binding (binding_set, GDK_End, 0,
438 GTK_MOVEMENT_DISPLAY_LINE_ENDS, 1);
440 add_move_binding (binding_set, GDK_KP_Home, 0,
441 GTK_MOVEMENT_DISPLAY_LINE_ENDS, -1);
443 add_move_binding (binding_set, GDK_KP_End, 0,
444 GTK_MOVEMENT_DISPLAY_LINE_ENDS, 1);
446 add_move_binding (binding_set, GDK_Home, GDK_CONTROL_MASK,
447 GTK_MOVEMENT_BUFFER_ENDS, -1);
449 add_move_binding (binding_set, GDK_End, GDK_CONTROL_MASK,
450 GTK_MOVEMENT_BUFFER_ENDS, 1);
452 add_move_binding (binding_set, GDK_KP_Home, GDK_CONTROL_MASK,
453 GTK_MOVEMENT_BUFFER_ENDS, -1);
455 add_move_binding (binding_set, GDK_KP_End, GDK_CONTROL_MASK,
456 GTK_MOVEMENT_BUFFER_ENDS, 1);
459 gtk_binding_entry_add_signal (binding_set, GDK_c, GDK_CONTROL_MASK,
460 "copy_clipboard", 0);
464 gtk_label_set_property (GObject *object,
472 label = GTK_LABEL (object);
473 last_keyval = label->mnemonic_keyval;
478 gtk_label_set_label (label, g_value_get_string (value));
480 case PROP_ATTRIBUTES:
481 gtk_label_set_attributes (label, g_value_get_boxed (value));
483 case PROP_USE_MARKUP:
484 gtk_label_set_use_markup (label, g_value_get_boolean (value));
486 case PROP_USE_UNDERLINE:
487 gtk_label_set_use_underline (label, g_value_get_boolean (value));
490 gtk_label_set_justify (label, g_value_get_enum (value));
493 gtk_label_set_pattern (label, g_value_get_string (value));
496 gtk_label_set_line_wrap (label, g_value_get_boolean (value));
498 case PROP_SELECTABLE:
499 gtk_label_set_selectable (label, g_value_get_boolean (value));
501 case PROP_MNEMONIC_WIDGET:
502 gtk_label_set_mnemonic_widget (label, (GtkWidget*) g_value_get_object (value));
505 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
511 gtk_label_get_property (GObject *object,
518 label = GTK_LABEL (object);
523 g_value_set_string (value, label->label);
525 case PROP_ATTRIBUTES:
526 g_value_set_boxed (value, label->attrs);
528 case PROP_USE_MARKUP:
529 g_value_set_boolean (value, label->use_markup);
531 case PROP_USE_UNDERLINE:
532 g_value_set_boolean (value, label->use_underline);
535 g_value_set_enum (value, label->jtype);
538 g_value_set_boolean (value, label->wrap);
540 case PROP_SELECTABLE:
541 g_value_set_boolean (value, gtk_label_get_selectable (label));
543 case PROP_MNEMONIC_KEYVAL:
544 g_value_set_uint (value, label->mnemonic_keyval);
546 case PROP_MNEMONIC_WIDGET:
547 g_value_set_object (value, (GObject*) label->mnemonic_widget);
549 case PROP_CURSOR_POSITION:
550 if (label->select_info)
552 gint offset = g_utf8_pointer_to_offset (label->text,
553 label->text + label->select_info->selection_end);
554 g_value_set_int (value, offset);
557 g_value_set_int (value, 0);
559 case PROP_SELECTION_BOUND:
560 if (label->select_info)
562 gint offset = g_utf8_pointer_to_offset (label->text,
563 label->text + label->select_info->selection_anchor);
564 g_value_set_int (value, offset);
567 g_value_set_int (value, 0);
571 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
577 gtk_label_init (GtkLabel *label)
579 GTK_WIDGET_SET_FLAGS (label, GTK_NO_WINDOW);
583 label->jtype = GTK_JUSTIFY_LEFT;
586 label->use_underline = FALSE;
587 label->use_markup = FALSE;
589 label->mnemonic_keyval = GDK_VoidSymbol;
590 label->layout = NULL;
594 label->mnemonic_widget = NULL;
595 label->mnemonic_window = NULL;
597 gtk_label_set_text (label, "");
602 * @str: The text of the label
604 * Creates a new label with the given text inside it. You can
605 * pass %NULL to get an empty label widget.
607 * Return value: the new #GtkLabel
610 gtk_label_new (const gchar *str)
614 label = g_object_new (GTK_TYPE_LABEL, NULL);
617 gtk_label_set_text (label, str);
619 return GTK_WIDGET (label);
623 * gtk_label_new_with_mnemonic:
624 * @str: The text of the label, with an underscore in front of the
627 * Creates a new #GtkLabel, containing the text in @str.
629 * If characters in @str are preceded by an underscore, they are
630 * underlined. If you need a literal underscore character in a label, use
631 * '__' (two underscores). The first underlined character represents a
632 * keyboard accelerator called a mnemonic. The mnemonic key can be used
633 * to activate another widget, chosen automatically, or explicitly using
634 * gtk_label_set_mnemonic_widget().
636 * If gtk_label_set_mnemonic_widget()
637 * is not called, then the first activatable ancestor of the #GtkLabel
638 * will be chosen as the mnemonic widget. For instance, if the
639 * label is inside a button or menu item, the button or menu item will
640 * automatically become the mnemonic widget and be activated by
643 * Return value: the new #GtkLabel
646 gtk_label_new_with_mnemonic (const gchar *str)
650 label = g_object_new (GTK_TYPE_LABEL, NULL);
653 gtk_label_set_text_with_mnemonic (label, str);
655 return GTK_WIDGET (label);
659 gtk_label_mnemonic_activate (GtkWidget *widget,
660 gboolean group_cycling)
664 if (GTK_LABEL (widget)->mnemonic_widget)
665 return gtk_widget_mnemonic_activate (GTK_LABEL (widget)->mnemonic_widget, group_cycling);
667 /* Try to find the widget to activate by traversing the
670 parent = widget->parent;
672 if (parent && GTK_IS_NOTEBOOK (parent))
677 if (GTK_WIDGET_CAN_FOCUS (parent) ||
678 (!group_cycling && GTK_WIDGET_GET_CLASS (parent)->activate_signal) ||
679 (parent->parent && GTK_IS_NOTEBOOK (parent->parent)) ||
680 (GTK_IS_MENU_ITEM (parent)))
681 return gtk_widget_mnemonic_activate (parent, group_cycling);
682 parent = parent->parent;
685 /* barf if there was nothing to activate */
686 g_warning ("Couldn't find a target for a mnemonic activation.");
687 gdk_display_beep (gtk_widget_get_display (widget));
693 gtk_label_setup_mnemonic (GtkLabel *label,
698 if (last_key != GDK_VoidSymbol && label->mnemonic_window)
700 gtk_window_remove_mnemonic (label->mnemonic_window,
703 label->mnemonic_window = NULL;
706 if (label->mnemonic_keyval == GDK_VoidSymbol)
709 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (label));
710 if (GTK_WIDGET_TOPLEVEL (toplevel))
712 gtk_window_add_mnemonic (GTK_WINDOW (toplevel),
713 label->mnemonic_keyval,
715 label->mnemonic_window = GTK_WINDOW (toplevel);
720 gtk_label_hierarchy_changed (GtkWidget *widget,
721 GtkWidget *old_toplevel)
723 GtkLabel *label = GTK_LABEL (widget);
725 gtk_label_setup_mnemonic (label, label->mnemonic_keyval);
729 gtk_label_screen_changed (GtkWidget *widget,
730 GdkScreen *old_screen)
732 gtk_label_clear_layout (GTK_LABEL (widget));
736 label_mnemonic_widget_weak_notify (gpointer data,
737 GObject *where_the_object_was)
739 GtkLabel *label = data;
741 label->mnemonic_widget = NULL;
742 g_object_notify (G_OBJECT (label), "mnemonic_widget");
746 * gtk_label_set_mnemonic_widget:
747 * @label: a #GtkLabel
748 * @widget: the target #GtkWidget
750 * If the label has been set so that it has an mnemonic key (using
751 * i.e. gtk_label_set_markup_with_mnemonic(),
752 * gtk_label_set_text_with_mnemonic(), gtk_label_new_with_mnemonic()
753 * or the "use_underline" property) the label can be associated with a
754 * widget that is the target of the mnemonic. When the label is inside
755 * a widget (like a #GtkButton or a #GtkNotebook tab) it is
756 * automatically associated with the correct widget, but sometimes
757 * (i.e. when the target is a #GtkEntry next to the label) you need to
758 * set it explicitly using this function.
760 * The target widget will be accelerated by emitting "mnemonic_activate" on it.
761 * The default handler for this signal will activate the widget if there are no
762 * mnemonic collisions and toggle focus between the colliding widgets otherwise.
765 gtk_label_set_mnemonic_widget (GtkLabel *label,
768 g_return_if_fail (GTK_IS_LABEL (label));
770 g_return_if_fail (GTK_IS_WIDGET (widget));
772 if (label->mnemonic_widget)
773 g_object_weak_unref (G_OBJECT (label->mnemonic_widget),
774 label_mnemonic_widget_weak_notify,
776 label->mnemonic_widget = widget;
777 if (label->mnemonic_widget)
778 g_object_weak_ref (G_OBJECT (label->mnemonic_widget),
779 label_mnemonic_widget_weak_notify,
782 g_object_notify (G_OBJECT (label), "mnemonic_widget");
786 * gtk_label_get_mnemonic_widget:
787 * @label: a #GtkLabel
789 * Retrieves the target of the mnemonic (keyboard shortcut) of this
790 * label. See gtk_label_set_mnemonic_widget ().
792 * Return value: the target of the label's mnemonic, or %NULL if none
793 * has been set and the default algorithm will be used.
796 gtk_label_get_mnemonic_widget (GtkLabel *label)
798 g_return_val_if_fail (GTK_IS_LABEL (label), NULL);
800 return label->mnemonic_widget;
804 * gtk_label_get_mnemonic_keyval:
805 * @label: a #GtkLabel
807 * If the label has been set so that it has an mnemonic key this function
808 * returns the keyval used for the mnemonic accelerator. If there is no
809 * mnemonic set up it returns #GDK_VoidSymbol.
811 * Returns: GDK keyval usable for accelerators, or #GDK_VoidSymbol
814 gtk_label_get_mnemonic_keyval (GtkLabel *label)
816 g_return_val_if_fail (GTK_IS_LABEL (label), GDK_VoidSymbol);
818 return label->mnemonic_keyval;
822 gtk_label_set_text_internal (GtkLabel *label,
825 g_free (label->text);
829 gtk_label_select_region_index (label, 0, 0);
833 gtk_label_set_label_internal (GtkLabel *label,
836 g_free (label->label);
840 g_object_notify (G_OBJECT (label), "label");
844 gtk_label_set_use_markup_internal (GtkLabel *label,
848 if (label->use_markup != val)
850 g_object_notify (G_OBJECT (label), "use_markup");
851 label->use_markup = val;
856 gtk_label_set_use_underline_internal (GtkLabel *label,
860 if (label->use_underline != val)
862 g_object_notify (G_OBJECT (label), "use_underline");
863 label->use_underline = val;
868 gtk_label_set_attributes_internal (GtkLabel *label,
869 PangoAttrList *attrs)
872 pango_attr_list_ref (attrs);
875 pango_attr_list_unref (label->attrs);
877 if (!label->use_markup && !label->use_underline)
879 pango_attr_list_ref (attrs);
880 if (label->effective_attrs)
881 pango_attr_list_unref (label->effective_attrs);
882 label->effective_attrs = attrs;
885 label->attrs = attrs;
886 g_object_notify (G_OBJECT (label), "attributes");
890 /* Calculates text, attrs and mnemonic_keyval from
891 * label, use_underline and use_markup
894 gtk_label_recalculate (GtkLabel *label)
896 if (label->use_markup)
897 set_markup (label, label->label, label->use_underline);
900 if (label->use_underline)
901 gtk_label_set_uline_text_internal (label, label->label);
904 gtk_label_set_text_internal (label, g_strdup (label->label));
906 pango_attr_list_ref (label->attrs);
907 if (label->effective_attrs)
908 pango_attr_list_unref (label->effective_attrs);
909 label->effective_attrs = label->attrs;
913 if (!label->use_underline)
915 guint keyval = label->mnemonic_keyval;
917 label->mnemonic_keyval = GDK_VoidSymbol;
918 gtk_label_setup_mnemonic (label, keyval);
921 gtk_label_clear_layout (label);
922 gtk_widget_queue_resize (GTK_WIDGET (label));
926 * gtk_label_set_text:
927 * @label: a #GtkLabel
928 * @str: The text you want to set.
930 * Sets the text within the #GtkLabel widget. It overwrites any text that
933 * This will also clear any previously set mnemonic accelerators.
936 gtk_label_set_text (GtkLabel *label,
939 g_return_if_fail (GTK_IS_LABEL (label));
941 g_object_freeze_notify (G_OBJECT (label));
943 gtk_label_set_label_internal (label, g_strdup (str ? str : ""));
944 gtk_label_set_use_markup_internal (label, FALSE);
945 gtk_label_set_use_underline_internal (label, FALSE);
947 gtk_label_recalculate (label);
949 g_object_thaw_notify (G_OBJECT (label));
953 * gtk_label_set_attributes:
954 * @label: a #GtkLabel
955 * @attrs: a #PangoAttrList
957 * Sets a #PangoAttrList; the attributes in the list are applied to the
958 * label text. The attributes set with this function will be ignored
959 * if the "use_underline" property or the "use_markup" property
963 gtk_label_set_attributes (GtkLabel *label,
964 PangoAttrList *attrs)
966 g_return_if_fail (GTK_IS_LABEL (label));
968 gtk_label_set_attributes_internal (label, attrs);
970 gtk_label_clear_layout (label);
971 gtk_widget_queue_resize (GTK_WIDGET (label));
975 * gtk_label_get_attributes:
976 * @label: a #GtkLabel
978 * Gets the attribute list that was set on the label using
979 * gtk_label_set_attributes(), if any. This function does
980 * not reflect attributes that come from the labels markup
981 * (see gtk_label_set_markup()). If you want to get the
982 * effective attributes for the label, use
983 * pango_layout_get_attribute (gtk_label_get_layout (label)).
985 * Return value: the attribute list, or %NULL if none was set.
988 gtk_label_get_attributes (GtkLabel *label)
990 g_return_val_if_fail (GTK_IS_LABEL (label), NULL);
996 * gtk_label_set_label:
997 * @label: a #GtkLabel
998 * @str: the new text to set for the label
1000 * Sets the text of the label. The label is interpreted as
1001 * including embedded underlines and/or Pango markup depending
1002 * on the values of label->use_underline and label->use_markup.
1005 gtk_label_set_label (GtkLabel *label,
1010 g_return_if_fail (GTK_IS_LABEL (label));
1011 g_return_if_fail (str != NULL);
1013 last_keyval = label->mnemonic_keyval;
1015 gtk_label_set_label_internal (label, g_strdup (str));
1016 gtk_label_recalculate (label);
1017 if (last_keyval != label->mnemonic_keyval)
1018 gtk_label_setup_mnemonic (label, last_keyval);
1022 * gtk_label_get_label:
1023 * @label: a #GtkLabel
1025 * Fetches the text from a label widget including any embedded
1026 * underlines indicating mnemonics and Pango markup. (See
1027 * gtk_label_get_text ()).
1029 * Return value: the text of the label widget. This string is
1030 * owned by the widget and must not be modified or freed.
1032 G_CONST_RETURN gchar *
1033 gtk_label_get_label (GtkLabel *label)
1035 g_return_val_if_fail (GTK_IS_LABEL (label), NULL);
1037 return label->label;
1041 set_markup (GtkLabel *label,
1043 gboolean with_uline)
1046 GError *error = NULL;
1047 PangoAttrList *attrs = NULL;
1048 gunichar accel_char = 0;
1050 if (!pango_parse_markup (str,
1052 with_uline ? '_' : 0,
1055 with_uline ? &accel_char : NULL,
1058 g_warning ("Failed to set label from markup due to error parsing markup: %s",
1060 g_error_free (error);
1065 gtk_label_set_text_internal (label, text);
1069 if (label->effective_attrs)
1070 pango_attr_list_unref (label->effective_attrs);
1071 label->effective_attrs = attrs;
1074 if (accel_char != 0)
1075 label->mnemonic_keyval = gdk_keyval_to_lower (gdk_unicode_to_keyval (accel_char));
1077 label->mnemonic_keyval = GDK_VoidSymbol;
1081 * gtk_label_set_markup:
1082 * @label: a #GtkLabel
1083 * @str: a markup string (see <link linkend="PangoMarkupFormat">Pango markup format</link>)
1085 * Parses @str which is marked up with the <link linkend="PangoMarkupFormat">Pango text markup language</link>,
1086 * setting the label's text and attribute list based on the parse results.
1089 gtk_label_set_markup (GtkLabel *label,
1092 g_return_if_fail (GTK_IS_LABEL (label));
1094 gtk_label_set_label_internal (label, g_strdup (str ? str : ""));
1095 gtk_label_set_use_markup_internal (label, TRUE);
1096 gtk_label_set_use_underline_internal (label, FALSE);
1098 gtk_label_recalculate (label);
1102 * gtk_label_set_markup_with_mnemonic:
1103 * @label: a #GtkLabel
1104 * @str: a markup string (see <link linkend="PangoMarkupFormat">Pango markup format</link>)
1106 * Parses @str which is marked up with the <link linkend="PangoMarkupFormat">Pango text markup language</link>,
1107 * setting the label's text and attribute list based on the parse results.
1108 * If characters in @str are preceded by an underscore, they are underlined
1109 * indicating that they represent a keyboard accelerator called a mnemonic.
1111 * The mnemonic key can be used to activate another widget, chosen automatically,
1112 * or explicitly using gtk_label_set_mnemonic_widget().
1115 gtk_label_set_markup_with_mnemonic (GtkLabel *label,
1119 g_return_if_fail (GTK_IS_LABEL (label));
1121 last_keyval = label->mnemonic_keyval;
1122 gtk_label_set_label_internal (label, g_strdup (str ? str : ""));
1123 gtk_label_set_use_markup_internal (label, TRUE);
1124 gtk_label_set_use_underline_internal (label, TRUE);
1126 gtk_label_recalculate (label);
1127 gtk_label_setup_mnemonic (label, last_keyval);
1131 * gtk_label_get_text:
1132 * @label: a #GtkLabel
1134 * Fetches the text from a label widget, as displayed on the
1135 * screen. This does not include any embedded underlines
1136 * indicating mnemonics or Pango markup. (See gtk_label_get_label())
1138 * Return value: the text in the label widget. This is the internal
1139 * string used by the label, and must not be modified.
1141 G_CONST_RETURN gchar *
1142 gtk_label_get_text (GtkLabel *label)
1144 g_return_val_if_fail (GTK_IS_LABEL (label), NULL);
1149 static PangoAttrList *
1150 gtk_label_pattern_to_attrs (GtkLabel *label,
1151 const gchar *pattern)
1154 const char *p = label->text;
1155 const char *q = pattern;
1156 PangoAttrList *attrs;
1158 attrs = pango_attr_list_new ();
1162 while (*p && *q && *q != '_')
1164 p = g_utf8_next_char (p);
1168 while (*p && *q && *q == '_')
1170 p = g_utf8_next_char (p);
1176 PangoAttribute *attr = pango_attr_underline_new (PANGO_UNDERLINE_LOW);
1177 attr->start_index = start - label->text;
1178 attr->end_index = p - label->text;
1180 pango_attr_list_insert (attrs, attr);
1190 gtk_label_set_pattern_internal (GtkLabel *label,
1191 const gchar *pattern)
1193 PangoAttrList *attrs;
1194 g_return_if_fail (GTK_IS_LABEL (label));
1196 attrs = gtk_label_pattern_to_attrs (label, pattern);
1198 if (label->effective_attrs)
1199 pango_attr_list_unref (label->effective_attrs);
1200 label->effective_attrs = attrs;
1204 gtk_label_set_pattern (GtkLabel *label,
1205 const gchar *pattern)
1207 g_return_if_fail (GTK_IS_LABEL (label));
1209 gtk_label_set_pattern_internal (label, pattern);
1211 gtk_label_clear_layout (label);
1212 gtk_widget_queue_resize (GTK_WIDGET (label));
1217 * gtk_label_set_justify:
1218 * @label: a #GtkLabel
1219 * @jtype: a #GtkJustification
1221 * Sets the alignment of the lines in the text of the label relative to
1222 * each other. %GTK_JUSTIFY_LEFT is the default value when the
1223 * widget is first created with gtk_label_new(). If you instead want
1224 * to set the alignment of the label as a whole, use
1225 * gtk_misc_set_alignment() instead. gtk_label_set_justify() has no
1226 * effect on labels containing only a single line.
1229 gtk_label_set_justify (GtkLabel *label,
1230 GtkJustification jtype)
1232 g_return_if_fail (GTK_IS_LABEL (label));
1233 g_return_if_fail (jtype >= GTK_JUSTIFY_LEFT && jtype <= GTK_JUSTIFY_FILL);
1235 if ((GtkJustification) label->jtype != jtype)
1237 label->jtype = jtype;
1239 /* No real need to be this drastic, but easier than duplicating the code */
1240 gtk_label_clear_layout (label);
1242 g_object_notify (G_OBJECT (label), "justify");
1243 gtk_widget_queue_resize (GTK_WIDGET (label));
1248 * gtk_label_get_justify:
1249 * @label: a #GtkLabel
1251 * Returns the justification of the label. See gtk_label_set_justify ().
1253 * Return value: #GtkJustification
1256 gtk_label_get_justify (GtkLabel *label)
1258 g_return_val_if_fail (GTK_IS_LABEL (label), 0);
1260 return label->jtype;
1264 * gtk_label_set_line_wrap:
1265 * @label: a #GtkLabel
1266 * @wrap: the setting
1268 * Toggles line wrapping within the #GtkLabel widget. %TRUE makes it break
1269 * lines if text exceeds the widget's size. %FALSE lets the text get cut off
1270 * by the edge of the widget if it exceeds the widget size.
1273 gtk_label_set_line_wrap (GtkLabel *label,
1276 g_return_if_fail (GTK_IS_LABEL (label));
1278 wrap = wrap != FALSE;
1280 if (label->wrap != wrap)
1283 g_object_notify (G_OBJECT (label), "wrap");
1285 gtk_widget_queue_resize (GTK_WIDGET (label));
1290 * gtk_label_get_line_wrap:
1291 * @label: a #GtkLabel
1293 * Returns whether lines in the label are automatically wrapped. See gtk_label_set_line_wrap ().
1295 * Return value: %TRUE if the lines of the label are automatically wrapped.
1298 gtk_label_get_line_wrap (GtkLabel *label)
1300 g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
1306 gtk_label_get (GtkLabel *label,
1309 g_return_if_fail (GTK_IS_LABEL (label));
1310 g_return_if_fail (str != NULL);
1316 gtk_label_destroy (GtkObject *object)
1318 GtkLabel *label = GTK_LABEL (object);
1320 gtk_label_set_mnemonic_widget (label, NULL);
1322 GTK_OBJECT_CLASS (parent_class)->destroy (object);
1326 gtk_label_finalize (GObject *object)
1330 g_return_if_fail (GTK_IS_LABEL (object));
1332 label = GTK_LABEL (object);
1334 g_free (label->label);
1335 g_free (label->text);
1338 g_object_unref (label->layout);
1341 pango_attr_list_unref (label->attrs);
1343 if (label->effective_attrs)
1344 pango_attr_list_unref (label->effective_attrs);
1346 g_free (label->select_info);
1348 G_OBJECT_CLASS (parent_class)->finalize (object);
1352 gtk_label_clear_layout (GtkLabel *label)
1356 g_object_unref (label->layout);
1357 label->layout = NULL;
1361 typedef struct _LabelWrapWidth LabelWrapWidth;
1362 struct _LabelWrapWidth
1365 PangoFontDescription *font_desc;
1369 label_wrap_width_free (gpointer data)
1371 LabelWrapWidth *wrap_width = data;
1372 pango_font_description_free (wrap_width->font_desc);
1373 g_free (wrap_width);
1377 get_label_wrap_width (GtkLabel *label)
1379 PangoLayout *layout;
1380 GtkStyle *style = GTK_WIDGET (label)->style;
1382 LabelWrapWidth *wrap_width = g_object_get_data (G_OBJECT (style), "gtk-label-wrap-width");
1385 wrap_width = g_new0 (LabelWrapWidth, 1);
1386 g_object_set_data_full (G_OBJECT (style), "gtk-label-wrap-width",
1387 wrap_width, label_wrap_width_free);
1390 if (wrap_width->font_desc && pango_font_description_equal (wrap_width->font_desc, style->font_desc))
1391 return wrap_width->width;
1393 if (wrap_width->font_desc)
1394 pango_font_description_free (wrap_width->font_desc);
1396 wrap_width->font_desc = pango_font_description_copy (style->font_desc);
1398 layout = gtk_widget_create_pango_layout (GTK_WIDGET (label),
1399 "This long string gives a good enough length for any line to have.");
1400 pango_layout_get_size (layout, &wrap_width->width, NULL);
1401 g_object_unref (layout);
1403 return wrap_width->width;
1407 gtk_label_ensure_layout (GtkLabel *label)
1410 PangoRectangle logical_rect;
1411 gint rwidth, rheight;
1413 widget = GTK_WIDGET (label);
1415 rwidth = label->misc.xpad * 2;
1416 rheight = label->misc.ypad * 2;
1420 PangoAlignment align = PANGO_ALIGN_LEFT; /* Quiet gcc */
1422 label->layout = gtk_widget_create_pango_layout (widget, label->text);
1424 if (label->effective_attrs)
1425 pango_layout_set_attributes (label->layout, label->effective_attrs);
1427 switch (label->jtype)
1429 case GTK_JUSTIFY_LEFT:
1430 align = PANGO_ALIGN_LEFT;
1432 case GTK_JUSTIFY_RIGHT:
1433 align = PANGO_ALIGN_RIGHT;
1435 case GTK_JUSTIFY_CENTER:
1436 align = PANGO_ALIGN_CENTER;
1438 case GTK_JUSTIFY_FILL:
1439 /* FIXME: This just doesn't work to do this */
1440 align = PANGO_ALIGN_LEFT;
1441 pango_layout_set_justify (label->layout, TRUE);
1444 g_assert_not_reached();
1447 pango_layout_set_alignment (label->layout, align);
1451 GtkWidgetAuxInfo *aux_info;
1452 gint longest_paragraph;
1455 aux_info = _gtk_widget_get_aux_info (widget, FALSE);
1456 if (aux_info && aux_info->width > 0)
1457 pango_layout_set_width (label->layout, aux_info->width * PANGO_SCALE);
1460 GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET (label));
1463 pango_layout_set_width (label->layout, -1);
1464 pango_layout_get_extents (label->layout, NULL, &logical_rect);
1466 width = logical_rect.width;
1468 /* Try to guess a reasonable maximum width */
1469 longest_paragraph = width;
1471 wrap_width = get_label_wrap_width (label);
1472 width = MIN (width, wrap_width);
1474 PANGO_SCALE * (gdk_screen_get_width (screen) + 1) / 2);
1476 pango_layout_set_width (label->layout, width);
1477 pango_layout_get_extents (label->layout, NULL, &logical_rect);
1478 width = logical_rect.width;
1479 height = logical_rect.height;
1481 /* Unfortunately, the above may leave us with a very unbalanced looking paragraph,
1482 * so we try short search for a narrower width that leaves us with the same height
1484 if (longest_paragraph > 0)
1486 gint nlines, perfect_width;
1488 nlines = pango_layout_get_line_count (label->layout);
1489 perfect_width = (longest_paragraph + nlines - 1) / nlines;
1491 if (perfect_width < width)
1493 pango_layout_set_width (label->layout, perfect_width);
1494 pango_layout_get_extents (label->layout, NULL, &logical_rect);
1496 if (logical_rect.height <= height)
1497 width = logical_rect.width;
1500 gint mid_width = (perfect_width + width) / 2;
1502 if (mid_width > perfect_width)
1504 pango_layout_set_width (label->layout, mid_width);
1505 pango_layout_get_extents (label->layout, NULL, &logical_rect);
1507 if (logical_rect.height <= height)
1508 width = logical_rect.width;
1513 pango_layout_set_width (label->layout, width);
1516 else /* !label->wrap */
1517 pango_layout_set_width (label->layout, -1);
1522 gtk_label_size_request (GtkWidget *widget,
1523 GtkRequisition *requisition)
1527 PangoRectangle logical_rect;
1528 GtkWidgetAuxInfo *aux_info;
1530 g_return_if_fail (GTK_IS_LABEL (widget));
1531 g_return_if_fail (requisition != NULL);
1533 label = GTK_LABEL (widget);
1536 * If word wrapping is on, then the height requisition can depend
1539 * - Any width set on the widget via gtk_widget_set_usize().
1540 * - The padding of the widget (xpad, set by gtk_misc_set_padding)
1542 * Instead of trying to detect changes to these quantities, if we
1543 * are wrapping, we just rewrap for each size request. Since
1544 * size requisitions are cached by the GTK+ core, this is not
1549 gtk_label_clear_layout (label);
1551 gtk_label_ensure_layout (label);
1553 width = label->misc.xpad * 2;
1554 height = label->misc.ypad * 2;
1556 pango_layout_get_extents (label->layout, NULL, &logical_rect);
1558 aux_info = _gtk_widget_get_aux_info (widget, FALSE);
1559 if (label->wrap && aux_info && aux_info->width > 0)
1560 width += aux_info->width;
1562 width += PANGO_PIXELS (logical_rect.width);
1564 height += PANGO_PIXELS (logical_rect.height);
1566 requisition->width = width;
1567 requisition->height = height;
1571 gtk_label_size_allocate (GtkWidget *widget,
1572 GtkAllocation *allocation)
1576 label = GTK_LABEL (widget);
1578 (* GTK_WIDGET_CLASS (parent_class)->size_allocate) (widget, allocation);
1580 if (label->select_info && label->select_info->window)
1582 gdk_window_move_resize (label->select_info->window,
1586 allocation->height);
1591 gtk_label_state_changed (GtkWidget *widget,
1592 GtkStateType prev_state)
1596 label = GTK_LABEL (widget);
1598 if (label->select_info)
1599 gtk_label_select_region (label, 0, 0);
1601 if (GTK_WIDGET_CLASS (parent_class)->state_changed)
1602 GTK_WIDGET_CLASS (parent_class)->state_changed (widget, prev_state);
1606 gtk_label_style_set (GtkWidget *widget,
1607 GtkStyle *previous_style)
1611 g_return_if_fail (GTK_IS_LABEL (widget));
1613 label = GTK_LABEL (widget);
1615 /* We have to clear the layout, fonts etc. may have changed */
1616 gtk_label_clear_layout (label);
1620 gtk_label_direction_changed (GtkWidget *widget,
1621 GtkTextDirection previous_dir)
1623 GtkLabel *label = GTK_LABEL (widget);
1626 pango_layout_context_changed (label->layout);
1628 GTK_WIDGET_CLASS (parent_class)->direction_changed (widget, previous_dir);
1633 gtk_label_paint_word (GtkLabel *label,
1639 GtkWidget *widget = GTK_WIDGET (label);
1640 GtkLabelULine *uline;
1643 tmp_str = gdk_wcstombs (word->beginning);
1646 gtk_paint_string (widget->style, widget->window, widget->state,
1647 area, widget, "label",
1654 for (uline = word->uline; uline; uline = uline->next)
1655 gtk_paint_hline (widget->style, widget->window,
1656 widget->state, area,
1658 x + uline->x1, x + uline->x2, y + uline->y);
1663 get_layout_location (GtkLabel *label,
1672 misc = GTK_MISC (label);
1673 widget = GTK_WIDGET (label);
1675 if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
1676 xalign = misc->xalign;
1678 xalign = 1.0 - misc->xalign;
1680 x = floor (widget->allocation.x + (gint)misc->xpad +
1681 xalign * (widget->allocation.width - widget->requisition.width)
1684 if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
1685 x = MAX (x, widget->allocation.x + misc->xpad);
1688 widget->allocation.x + widget->allocation.width -
1689 widget->requisition.width - misc->xpad);
1691 y = floor (widget->allocation.y + (gint)misc->ypad
1692 + MAX (((widget->allocation.height - widget->requisition.height) * misc->yalign)
1703 gtk_label_draw_cursor (GtkLabel *label, gint xoffset, gint yoffset)
1705 if (label->select_info == NULL)
1708 if (GTK_WIDGET_DRAWABLE (label))
1710 GtkWidget *widget = GTK_WIDGET (label);
1712 GtkTextDirection keymap_direction;
1713 GtkTextDirection widget_direction;
1714 PangoRectangle strong_pos, weak_pos;
1715 gboolean split_cursor;
1716 PangoRectangle *cursor1 = NULL;
1717 PangoRectangle *cursor2 = NULL;
1718 GdkRectangle cursor_location;
1719 GtkTextDirection dir1 = GTK_TEXT_DIR_NONE;
1720 GtkTextDirection dir2 = GTK_TEXT_DIR_NONE;
1724 (gdk_keymap_get_direction (gdk_keymap_get_for_display (gtk_widget_get_display (widget))) == PANGO_DIRECTION_LTR) ?
1725 GTK_TEXT_DIR_LTR : GTK_TEXT_DIR_RTL;
1727 widget_direction = gtk_widget_get_direction (widget);
1729 gtk_label_ensure_layout (label);
1731 pango_layout_get_cursor_pos (label->layout, label->select_info->selection_end,
1732 &strong_pos, &weak_pos);
1734 g_object_get (gtk_widget_get_settings (widget),
1735 "gtk-split-cursor", &split_cursor,
1738 dir1 = widget_direction;
1742 cursor1 = &strong_pos;
1744 if (strong_pos.x != weak_pos.x ||
1745 strong_pos.y != weak_pos.y)
1747 dir2 = (widget_direction == GTK_TEXT_DIR_LTR) ? GTK_TEXT_DIR_RTL : GTK_TEXT_DIR_LTR;
1748 cursor2 = &weak_pos;
1753 if (keymap_direction == widget_direction)
1754 cursor1 = &strong_pos;
1756 cursor1 = &weak_pos;
1759 cursor_location.x = xoffset + PANGO_PIXELS (cursor1->x);
1760 cursor_location.y = yoffset + PANGO_PIXELS (cursor1->y);
1761 cursor_location.width = 0;
1762 cursor_location.height = PANGO_PIXELS (cursor1->height);
1764 gc = _gtk_get_insertion_cursor_gc (widget, TRUE);
1765 _gtk_draw_insertion_cursor (widget, widget->window, gc,
1766 &cursor_location, dir1,
1767 dir2 != GTK_TEXT_DIR_NONE);
1768 g_object_unref (gc);
1770 if (dir2 != GTK_TEXT_DIR_NONE)
1772 cursor_location.x = xoffset + PANGO_PIXELS (cursor2->x);
1773 cursor_location.y = yoffset + PANGO_PIXELS (cursor2->y);
1774 cursor_location.width = 0;
1775 cursor_location.height = PANGO_PIXELS (cursor2->height);
1777 gc = _gtk_get_insertion_cursor_gc (widget, FALSE);
1778 _gtk_draw_insertion_cursor (widget, widget->window, gc,
1779 &cursor_location, dir2, TRUE);
1780 g_object_unref (gc);
1787 gtk_label_expose (GtkWidget *widget,
1788 GdkEventExpose *event)
1793 g_return_val_if_fail (GTK_IS_LABEL (widget), FALSE);
1794 g_return_val_if_fail (event != NULL, FALSE);
1796 label = GTK_LABEL (widget);
1798 gtk_label_ensure_layout (label);
1800 if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_MAPPED (widget) &&
1801 label->text && (*label->text != '\0'))
1803 get_layout_location (label, &x, &y);
1805 gtk_paint_layout (widget->style,
1807 GTK_WIDGET_STATE (widget),
1815 if (label->select_info &&
1816 (label->select_info->selection_anchor !=
1817 label->select_info->selection_end))
1823 range[0] = label->select_info->selection_anchor;
1824 range[1] = label->select_info->selection_end;
1826 if (range[0] > range[1])
1828 gint tmp = range[0];
1829 range[0] = range[1];
1833 clip = gdk_pango_layout_get_clip_region (label->layout,
1838 /* FIXME should use gtk_paint, but it can't use a clip
1842 gdk_gc_set_clip_region (widget->style->black_gc, clip);
1845 state = GTK_STATE_SELECTED;
1846 if (!GTK_WIDGET_HAS_FOCUS (widget))
1847 state = GTK_STATE_ACTIVE;
1849 gdk_draw_layout_with_colors (widget->window,
1850 widget->style->black_gc,
1853 &widget->style->text[state],
1854 &widget->style->base[state]);
1856 gdk_gc_set_clip_region (widget->style->black_gc, NULL);
1857 gdk_region_destroy (clip);
1859 else if (label->select_info && GTK_WIDGET_HAS_FOCUS (widget))
1860 gtk_label_draw_cursor (label, x, y);
1867 gtk_label_set_uline_text_internal (GtkLabel *label,
1870 guint accel_key = GDK_VoidSymbol;
1875 gchar *dest, *pattern_dest;
1876 gboolean underscore;
1878 g_return_if_fail (GTK_IS_LABEL (label));
1879 g_return_if_fail (str != NULL);
1881 /* Split text into the base text and a separate pattern
1885 new_str = g_new (gchar, strlen (str) + 1);
1886 pattern = g_new (gchar, g_utf8_strlen (str, -1) + 1);
1895 pattern_dest = pattern;
1902 c = g_utf8_get_char (src);
1903 if (c == (gunichar)-1)
1905 g_warning ("Invalid input string");
1910 next_src = g_utf8_next_char (src);
1915 *pattern_dest++ = ' ';
1918 *pattern_dest++ = '_';
1919 if (accel_key == GDK_VoidSymbol)
1920 accel_key = gdk_keyval_to_lower (gdk_unicode_to_keyval (c));
1923 while (src < next_src)
1937 while (src < next_src)
1940 *pattern_dest++ = ' ';
1947 gtk_label_set_text_internal (label, new_str);
1948 gtk_label_set_pattern_internal (label, pattern);
1952 label->mnemonic_keyval = accel_key;
1956 gtk_label_parse_uline (GtkLabel *label,
1962 g_return_val_if_fail (GTK_IS_LABEL (label), GDK_VoidSymbol);
1963 g_return_val_if_fail (str != NULL, GDK_VoidSymbol);
1965 orig_keyval = label->mnemonic_keyval;
1967 g_object_freeze_notify (G_OBJECT (label));
1969 gtk_label_set_label_internal (label, g_strdup (str ? str : ""));
1970 gtk_label_set_use_markup_internal (label, FALSE);
1971 gtk_label_set_use_underline_internal (label, TRUE);
1973 gtk_label_recalculate (label);
1975 keyval = label->mnemonic_keyval;
1976 label->mnemonic_keyval = GDK_VoidSymbol;
1978 gtk_label_setup_mnemonic (label, orig_keyval);
1980 g_object_thaw_notify (G_OBJECT (label));
1986 * gtk_label_set_text_with_mnemonic:
1987 * @label: a #GtkLabel
1990 * Sets the label's text from the string @str.
1991 * If characters in @str are preceded by an underscore, they are underlined
1992 * indicating that they represent a keyboard accelerator called a mnemonic.
1993 * The mnemonic key can be used to activate another widget, chosen automatically,
1994 * or explicitly using gtk_label_set_mnemonic_widget().
1997 gtk_label_set_text_with_mnemonic (GtkLabel *label,
2002 g_return_if_fail (GTK_IS_LABEL (label));
2003 g_return_if_fail (str != NULL);
2005 last_keyval = label->mnemonic_keyval;
2007 g_object_freeze_notify (G_OBJECT (label));
2009 gtk_label_set_label_internal (label, g_strdup (str ? str : ""));
2010 gtk_label_set_use_markup_internal (label, FALSE);
2011 gtk_label_set_use_underline_internal (label, TRUE);
2013 gtk_label_recalculate (label);
2015 gtk_label_setup_mnemonic (label, last_keyval);
2017 g_object_thaw_notify (G_OBJECT (label));
2021 gtk_label_realize (GtkWidget *widget)
2025 label = GTK_LABEL (widget);
2027 (* GTK_WIDGET_CLASS (parent_class)->realize) (widget);
2029 if (label->select_info)
2030 gtk_label_create_window (label);
2034 gtk_label_unrealize (GtkWidget *widget)
2038 label = GTK_LABEL (widget);
2040 if (label->select_info)
2041 gtk_label_destroy_window (label);
2043 (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
2047 gtk_label_map (GtkWidget *widget)
2051 label = GTK_LABEL (widget);
2053 (* GTK_WIDGET_CLASS (parent_class)->map) (widget);
2055 if (label->select_info)
2056 gdk_window_show (label->select_info->window);
2060 gtk_label_unmap (GtkWidget *widget)
2064 label = GTK_LABEL (widget);
2066 if (label->select_info)
2067 gdk_window_hide (label->select_info->window);
2069 (* GTK_WIDGET_CLASS (parent_class)->unmap) (widget);
2073 window_to_layout_coords (GtkLabel *label,
2080 widget = GTK_WIDGET (label);
2082 /* get layout location in widget->window coords */
2083 get_layout_location (label, &lx, &ly);
2087 *x += widget->allocation.x; /* go to widget->window */
2088 *x -= lx; /* go to layout */
2093 *y += widget->allocation.y; /* go to widget->window */
2094 *y -= ly; /* go to layout */
2100 layout_to_window_coords (GtkLabel *label,
2107 widget = GTK_WIDGET (label);
2109 /* get layout location in widget->window coords */
2110 get_layout_location (label, &lx, &ly);
2114 *x += lx; /* go to widget->window */
2115 *x -= widget->allocation.x; /* go to selection window */
2120 *y += ly; /* go to widget->window */
2121 *y -= widget->allocation.y; /* go to selection window */
2127 get_layout_index (GtkLabel *label,
2133 const gchar *cluster;
2134 const gchar *cluster_end;
2138 gtk_label_ensure_layout (label);
2140 window_to_layout_coords (label, &x, &y);
2145 pango_layout_xy_to_index (label->layout,
2150 cluster = label->text + *index;
2151 cluster_end = cluster;
2154 cluster_end = g_utf8_next_char (cluster_end);
2158 *index += (cluster_end - cluster);
2162 gtk_label_select_word (GtkLabel *label)
2166 gint start_index = gtk_label_move_backward_word (label, label->select_info->selection_end);
2167 gint end_index = gtk_label_move_forward_word (label, label->select_info->selection_end);
2169 min = MIN (label->select_info->selection_anchor,
2170 label->select_info->selection_end);
2171 max = MAX (label->select_info->selection_anchor,
2172 label->select_info->selection_end);
2174 min = MIN (min, start_index);
2175 max = MAX (max, end_index);
2177 gtk_label_select_region_index (label, min, max);
2181 gtk_label_button_press (GtkWidget *widget,
2182 GdkEventButton *event)
2187 label = GTK_LABEL (widget);
2189 if (label->select_info == NULL)
2192 if (event->button == 1)
2194 if (!GTK_WIDGET_HAS_FOCUS (widget))
2195 gtk_widget_grab_focus (widget);
2197 if (event->type == GDK_3BUTTON_PRESS)
2199 gtk_label_select_region_index (label, 0, strlen (label->text));
2203 if (event->type == GDK_2BUTTON_PRESS)
2205 gtk_label_select_word (label);
2209 get_layout_index (label, event->x, event->y, &index);
2211 if ((label->select_info->selection_anchor !=
2212 label->select_info->selection_end) &&
2213 (event->state & GDK_SHIFT_MASK))
2217 /* extend (same as motion) */
2218 min = MIN (label->select_info->selection_anchor,
2219 label->select_info->selection_end);
2220 max = MAX (label->select_info->selection_anchor,
2221 label->select_info->selection_end);
2223 min = MIN (min, index);
2224 max = MAX (max, index);
2226 /* ensure the anchor is opposite index */
2234 gtk_label_select_region_index (label, min, max);
2238 if (event->type == GDK_3BUTTON_PRESS)
2239 gtk_label_select_region_index (label, 0, strlen (label->text));
2240 else if (event->type == GDK_2BUTTON_PRESS)
2241 gtk_label_select_word (label);
2243 /* start a replacement */
2244 gtk_label_select_region_index (label, index, index);
2249 else if (event->button == 3 && event->type == GDK_BUTTON_PRESS)
2251 gtk_label_do_popup (label, event);
2260 gtk_label_button_release (GtkWidget *widget,
2261 GdkEventButton *event)
2266 label = GTK_LABEL (widget);
2268 if (label->select_info == NULL)
2271 if (event->button != 1)
2274 /* The goal here is to return TRUE iff we ate the
2275 * button press to start selecting.
2282 gtk_label_motion (GtkWidget *widget,
2283 GdkEventMotion *event)
2289 label = GTK_LABEL (widget);
2291 if (label->select_info == NULL)
2294 if ((event->state & GDK_BUTTON1_MASK) == 0)
2297 gdk_window_get_pointer (label->select_info->window,
2300 get_layout_index (label, x, y, &index);
2302 gtk_label_select_region_index (label,
2303 label->select_info->selection_anchor,
2310 gtk_label_create_window (GtkLabel *label)
2313 GdkWindowAttr attributes;
2314 gint attributes_mask;
2316 g_assert (label->select_info);
2317 g_assert (GTK_WIDGET_REALIZED (label));
2319 if (label->select_info->window)
2322 widget = GTK_WIDGET (label);
2324 attributes.x = widget->allocation.x;
2325 attributes.y = widget->allocation.y;
2326 attributes.width = widget->allocation.width;
2327 attributes.height = widget->allocation.height;
2328 attributes.window_type = GDK_WINDOW_TEMP;
2329 attributes.wclass = GDK_INPUT_ONLY;
2330 attributes.override_redirect = TRUE;
2331 attributes.cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget),
2333 attributes.event_mask = gtk_widget_get_events (widget) |
2334 GDK_BUTTON_PRESS_MASK |
2335 GDK_BUTTON_RELEASE_MASK |
2336 GDK_BUTTON_MOTION_MASK;
2338 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_NOREDIR | GDK_WA_CURSOR;
2340 label->select_info->window = gdk_window_new (widget->window,
2341 &attributes, attributes_mask);
2342 gdk_window_set_user_data (label->select_info->window, widget);
2344 gdk_cursor_unref (attributes.cursor);
2348 gtk_label_destroy_window (GtkLabel *label)
2350 g_assert (label->select_info);
2352 if (label->select_info->window == NULL)
2355 gdk_window_set_user_data (label->select_info->window, NULL);
2356 gdk_window_destroy (label->select_info->window);
2357 label->select_info->window = NULL;
2361 * gtk_label_set_selectable:
2362 * @label: a #GtkLabel
2363 * @setting: %TRUE to allow selecting text in the label
2365 * Selectable labels allow the user to select text from the label, for
2370 gtk_label_set_selectable (GtkLabel *label,
2373 gboolean old_setting;
2375 g_return_if_fail (GTK_IS_LABEL (label));
2377 setting = setting != FALSE;
2378 old_setting = label->select_info != NULL;
2382 if (label->select_info == NULL)
2384 label->select_info = g_new0 (GtkLabelSelectionInfo, 1);
2386 GTK_WIDGET_SET_FLAGS (label, GTK_CAN_FOCUS);
2388 if (GTK_WIDGET_REALIZED (label))
2389 gtk_label_create_window (label);
2391 if (GTK_WIDGET_MAPPED (label))
2392 gdk_window_show (label->select_info->window);
2397 if (label->select_info)
2399 /* unselect, to give up the selection */
2400 gtk_label_select_region (label, 0, 0);
2402 if (label->select_info->window)
2404 gtk_label_destroy_window (label);
2407 g_free (label->select_info);
2409 label->select_info = NULL;
2411 GTK_WIDGET_UNSET_FLAGS (label, GTK_CAN_FOCUS);
2414 if (setting != old_setting)
2416 g_object_freeze_notify (G_OBJECT (label));
2417 g_object_notify (G_OBJECT (label), "selectable");
2418 g_object_notify (G_OBJECT (label), "cursor_position");
2419 g_object_notify (G_OBJECT (label), "selection_bound");
2420 g_object_thaw_notify (G_OBJECT (label));
2421 gtk_widget_queue_draw (GTK_WIDGET (label));
2426 * gtk_label_get_selectable:
2427 * @label: a #GtkLabel
2429 * Gets the value set by gtk_label_set_selectable().
2431 * Return value: %TRUE if the user can copy text from the label
2434 gtk_label_get_selectable (GtkLabel *label)
2436 g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
2438 return label->select_info != NULL;
2442 get_text_callback (GtkClipboard *clipboard,
2443 GtkSelectionData *selection_data,
2445 gpointer user_data_or_owner)
2449 label = GTK_LABEL (user_data_or_owner);
2451 if ((label->select_info->selection_anchor !=
2452 label->select_info->selection_end) &&
2458 start = MIN (label->select_info->selection_anchor,
2459 label->select_info->selection_end);
2460 end = MAX (label->select_info->selection_anchor,
2461 label->select_info->selection_end);
2463 len = strlen (label->text);
2471 gtk_selection_data_set_text (selection_data,
2472 label->text + start,
2478 clear_text_callback (GtkClipboard *clipboard,
2479 gpointer user_data_or_owner)
2483 label = GTK_LABEL (user_data_or_owner);
2485 if (label->select_info)
2487 label->select_info->selection_anchor = label->select_info->selection_end;
2489 gtk_widget_queue_draw (GTK_WIDGET (label));
2494 gtk_label_select_region_index (GtkLabel *label,
2498 static const GtkTargetEntry targets[] = {
2501 { "COMPOUND_TEXT", 0, 0 },
2502 { "UTF8_STRING", 0, 0 }
2505 g_return_if_fail (GTK_IS_LABEL (label));
2507 if (label->select_info)
2509 GtkClipboard *clipboard;
2511 if (label->select_info->selection_anchor == anchor_index &&
2512 label->select_info->selection_end == end_index)
2515 label->select_info->selection_anchor = anchor_index;
2516 label->select_info->selection_end = end_index;
2518 clipboard = gtk_widget_get_clipboard (GTK_WIDGET (label),
2519 GDK_SELECTION_PRIMARY);
2521 if (anchor_index != end_index)
2523 gtk_clipboard_set_with_owner (clipboard,
2525 G_N_ELEMENTS (targets),
2527 clear_text_callback,
2532 if (gtk_clipboard_get_owner (clipboard) == G_OBJECT (label))
2533 gtk_clipboard_clear (clipboard);
2536 gtk_widget_queue_draw (GTK_WIDGET (label));
2538 g_object_freeze_notify (G_OBJECT (label));
2539 g_object_notify (G_OBJECT (label), "cursor_position");
2540 g_object_notify (G_OBJECT (label), "selection_bound");
2541 g_object_thaw_notify (G_OBJECT (label));
2546 * gtk_label_select_region:
2547 * @label: a #GtkLabel
2548 * @start_offset: start offset (in characters not bytes)
2549 * @end_offset: end offset (in characters not bytes)
2551 * Selects a range of characters in the label, if the label is selectable.
2552 * See gtk_label_set_selectable(). If the label is not selectable,
2553 * this function has no effect. If @start_offset or
2554 * @end_offset are -1, then the end of the label will be substituted.
2558 gtk_label_select_region (GtkLabel *label,
2562 g_return_if_fail (GTK_IS_LABEL (label));
2564 if (label->text && label->select_info)
2566 if (start_offset < 0)
2567 start_offset = g_utf8_strlen (label->text, -1);
2570 end_offset = g_utf8_strlen (label->text, -1);
2572 gtk_label_select_region_index (label,
2573 g_utf8_offset_to_pointer (label->text, start_offset) - label->text,
2574 g_utf8_offset_to_pointer (label->text, end_offset) - label->text);
2579 * gtk_label_get_selection_bounds:
2580 * @label: a #GtkLabel
2581 * @start: return location for start of selection, as a character offset
2582 * @end: return location for end of selection, as a character offset
2584 * Gets the selected range of characters in the label, returning %TRUE
2585 * if there's a selection.
2587 * Return value: %TRUE if selection is non-empty
2590 gtk_label_get_selection_bounds (GtkLabel *label,
2594 g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
2596 if (label->select_info == NULL)
2598 /* not a selectable label */
2608 gint start_index, end_index;
2609 gint start_offset, end_offset;
2612 start_index = MIN (label->select_info->selection_anchor,
2613 label->select_info->selection_end);
2614 end_index = MAX (label->select_info->selection_anchor,
2615 label->select_info->selection_end);
2617 len = strlen (label->text);
2619 if (end_index > len)
2622 if (start_index > len)
2625 start_offset = g_utf8_strlen (label->text, start_index);
2626 end_offset = g_utf8_strlen (label->text, end_index);
2628 if (start_offset > end_offset)
2630 gint tmp = start_offset;
2631 start_offset = end_offset;
2636 *start = start_offset;
2641 return start_offset != end_offset;
2647 * gtk_label_get_layout:
2648 * @label: a #GtkLabel
2650 * Gets the #PangoLayout used to display the label.
2651 * The layout is useful to e.g. convert text positions to
2652 * pixel positions, in combination with gtk_label_get_layout_offsets().
2653 * The returned layout is owned by the label so need not be
2654 * freed by the caller.
2656 * Return value: the #PangoLayout for this label
2659 gtk_label_get_layout (GtkLabel *label)
2661 g_return_val_if_fail (GTK_IS_LABEL (label), NULL);
2663 gtk_label_ensure_layout (label);
2665 return label->layout;
2669 * gtk_label_get_layout_offsets:
2670 * @label: a #GtkLabel
2671 * @x: location to store X offset of layout, or %NULL
2672 * @y: location to store Y offset of layout, or %NULL
2674 * Obtains the coordinates where the label will draw the #PangoLayout
2675 * representing the text in the label; useful to convert mouse events
2676 * into coordinates inside the #PangoLayout, e.g. to take some action
2677 * if some part of the label is clicked. Of course you will need to
2678 * create a #GtkEventBox to receive the events, and pack the label
2679 * inside it, since labels are a #GTK_NO_WINDOW widget. Remember
2680 * when using the #PangoLayout functions you need to convert to
2681 * and from pixels using PANGO_PIXELS() or #PANGO_SCALE.
2685 gtk_label_get_layout_offsets (GtkLabel *label,
2689 g_return_if_fail (GTK_IS_LABEL (label));
2691 get_layout_location (label, x, y);
2695 * gtk_label_set_use_markup:
2696 * @label: a #GtkLabel
2697 * @setting: %TRUE if the label's text should be parsed for markup.
2699 * Sets whether the text of the label contains markup in <link
2700 * linkend="PangoMarkupFormat">Pango's text markup
2701 * language</link>. See gtk_label_set_markup().
2704 gtk_label_set_use_markup (GtkLabel *label,
2707 g_return_if_fail (GTK_IS_LABEL (label));
2709 gtk_label_set_use_markup_internal (label, setting);
2710 gtk_label_recalculate (label);
2714 * gtk_label_get_use_markup:
2715 * @label: a #GtkLabel
2717 * Returns whether the label's text is interpreted as marked up with
2718 * the <link linkend="PangoMarkupFormat">Pango text markup
2719 * language</link>. See gtk_label_set_use_markup ().
2721 * Return value: %TRUE if the label's text will be parsed for markup.
2724 gtk_label_get_use_markup (GtkLabel *label)
2726 g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
2728 return label->use_markup;
2732 * gtk_label_set_use_underline:
2733 * @label: a #GtkLabel
2734 * @setting: %TRUE if underlines in the text indicate mnemonics
2736 * If true, an underline in the text indicates the next character should be
2737 * used for the mnemonic accelerator key.
2740 gtk_label_set_use_underline (GtkLabel *label,
2743 g_return_if_fail (GTK_IS_LABEL (label));
2745 gtk_label_set_use_underline_internal (label, setting);
2746 gtk_label_recalculate (label);
2747 if (label->use_underline)
2748 gtk_label_setup_mnemonic (label, label->mnemonic_keyval);
2752 * gtk_label_get_use_underline:
2753 * @label: a #GtkLabel
2755 * Returns whether an embedded underline in the label indicates a
2756 * mnemonic. See gtk_label_set_use_underline ().
2758 * Return value: %TRUE whether an embedded underline in the label indicates
2759 * the mnemonic accelerator keys.
2762 gtk_label_get_use_underline (GtkLabel *label)
2764 g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
2766 return label->use_underline;
2770 gtk_label_focus (GtkWidget *widget,
2771 GtkDirectionType direction)
2773 /* We never want to be in the tab chain */
2777 /* Compute the X position for an offset that corresponds to the "more important
2778 * cursor position for that offset. We use this when trying to guess to which
2779 * end of the selection we should go to when the user hits the left or
2783 get_better_cursor (GtkLabel *label,
2788 GdkKeymap *keymap = gdk_keymap_get_for_display (gtk_widget_get_display (GTK_WIDGET (label)));
2789 GtkTextDirection keymap_direction =
2790 (gdk_keymap_get_direction (keymap) == PANGO_DIRECTION_LTR) ?
2791 GTK_TEXT_DIR_LTR : GTK_TEXT_DIR_RTL;
2792 GtkTextDirection widget_direction = gtk_widget_get_direction (GTK_WIDGET (label));
2793 gboolean split_cursor;
2794 PangoRectangle strong_pos, weak_pos;
2796 g_object_get (gtk_widget_get_settings (GTK_WIDGET (label)),
2797 "gtk-split-cursor", &split_cursor,
2800 gtk_label_ensure_layout (label);
2802 pango_layout_get_cursor_pos (label->layout, index,
2803 &strong_pos, &weak_pos);
2807 *x = strong_pos.x / PANGO_SCALE;
2808 *y = strong_pos.y / PANGO_SCALE;
2812 if (keymap_direction == widget_direction)
2814 *x = strong_pos.x / PANGO_SCALE;
2815 *y = strong_pos.y / PANGO_SCALE;
2819 *x = weak_pos.x / PANGO_SCALE;
2820 *y = weak_pos.y / PANGO_SCALE;
2827 gtk_label_move_logically (GtkLabel *label,
2831 gint offset = g_utf8_pointer_to_offset (label->text,
2832 label->text + start);
2836 PangoLogAttr *log_attrs;
2840 gtk_label_ensure_layout (label);
2842 length = g_utf8_strlen (label->text, -1);
2844 pango_layout_get_log_attrs (label->layout, &log_attrs, &n_attrs);
2846 while (count > 0 && offset < length)
2850 while (offset < length && !log_attrs[offset].is_cursor_position);
2854 while (count < 0 && offset > 0)
2858 while (offset > 0 && !log_attrs[offset].is_cursor_position);
2866 return g_utf8_offset_to_pointer (label->text, offset) - label->text;
2870 gtk_label_move_visually (GtkLabel *label,
2880 int new_index, new_trailing;
2881 gboolean split_cursor;
2884 gtk_label_ensure_layout (label);
2886 g_object_get (gtk_widget_get_settings (GTK_WIDGET (label)),
2887 "gtk-split-cursor", &split_cursor,
2894 GdkKeymap *keymap = gdk_keymap_get_for_display (gtk_widget_get_display (GTK_WIDGET (label)));
2895 GtkTextDirection keymap_direction =
2896 (gdk_keymap_get_direction (keymap) == PANGO_DIRECTION_LTR) ?
2897 GTK_TEXT_DIR_LTR : GTK_TEXT_DIR_RTL;
2899 strong = keymap_direction == gtk_widget_get_direction (GTK_WIDGET (label));
2904 pango_layout_move_cursor_visually (label->layout, strong, index, 0, 1, &new_index, &new_trailing);
2909 pango_layout_move_cursor_visually (label->layout, strong, index, 0, -1, &new_index, &new_trailing);
2913 if (new_index < 0 || new_index == G_MAXINT)
2918 while (new_trailing--)
2919 index = g_utf8_next_char (label->text + new_index) - label->text;
2926 gtk_label_move_forward_word (GtkLabel *label,
2929 gint new_pos = g_utf8_pointer_to_offset (label->text,
2930 label->text + start);
2933 length = g_utf8_strlen (label->text, -1);
2934 if (new_pos < length)
2936 PangoLogAttr *log_attrs;
2939 gtk_label_ensure_layout (label);
2941 pango_layout_get_log_attrs (label->layout, &log_attrs, &n_attrs);
2943 /* Find the next word end */
2945 while (new_pos < n_attrs && !log_attrs[new_pos].is_word_end)
2951 return g_utf8_offset_to_pointer (label->text, new_pos) - label->text;
2956 gtk_label_move_backward_word (GtkLabel *label,
2959 gint new_pos = g_utf8_pointer_to_offset (label->text,
2960 label->text + start);
2963 length = g_utf8_strlen (label->text, -1);
2967 PangoLogAttr *log_attrs;
2970 gtk_label_ensure_layout (label);
2972 pango_layout_get_log_attrs (label->layout, &log_attrs, &n_attrs);
2976 /* Find the previous word beginning */
2977 while (new_pos > 0 && !log_attrs[new_pos].is_word_start)
2983 return g_utf8_offset_to_pointer (label->text, new_pos) - label->text;
2987 gtk_label_move_cursor (GtkLabel *label,
2988 GtkMovementStep step,
2990 gboolean extend_selection)
2994 if (label->select_info == NULL)
2997 new_pos = label->select_info->selection_end;
2999 if (label->select_info->selection_end != label->select_info->selection_anchor &&
3002 /* If we have a current selection and aren't extending it, move to the
3003 * start/or end of the selection as appropriate
3007 case GTK_MOVEMENT_VISUAL_POSITIONS:
3010 gint anchor_x, anchor_y;
3011 gboolean end_is_left;
3013 get_better_cursor (label, label->select_info->selection_end, &end_x, &end_y);
3014 get_better_cursor (label, label->select_info->selection_anchor, &anchor_x, &anchor_y);
3016 end_is_left = (end_y < anchor_y) || (end_y == anchor_y && end_x < anchor_x);
3019 new_pos = end_is_left ? label->select_info->selection_end : label->select_info->selection_anchor;
3021 new_pos = !end_is_left ? label->select_info->selection_end : label->select_info->selection_anchor;
3025 case GTK_MOVEMENT_LOGICAL_POSITIONS:
3026 case GTK_MOVEMENT_WORDS:
3028 new_pos = MIN (label->select_info->selection_end, label->select_info->selection_anchor);
3030 new_pos = MAX (label->select_info->selection_end, label->select_info->selection_anchor);
3032 case GTK_MOVEMENT_DISPLAY_LINE_ENDS:
3033 case GTK_MOVEMENT_PARAGRAPH_ENDS:
3034 case GTK_MOVEMENT_BUFFER_ENDS:
3035 /* FIXME: Can do better here */
3036 new_pos = count < 0 ? 0 : strlen (label->text);
3038 case GTK_MOVEMENT_DISPLAY_LINES:
3039 case GTK_MOVEMENT_PARAGRAPHS:
3040 case GTK_MOVEMENT_PAGES:
3048 case GTK_MOVEMENT_LOGICAL_POSITIONS:
3049 new_pos = gtk_label_move_logically (label, new_pos, count);
3051 case GTK_MOVEMENT_VISUAL_POSITIONS:
3052 new_pos = gtk_label_move_visually (label, new_pos, count);
3054 case GTK_MOVEMENT_WORDS:
3057 new_pos = gtk_label_move_forward_word (label, new_pos);
3062 new_pos = gtk_label_move_backward_word (label, new_pos);
3066 case GTK_MOVEMENT_DISPLAY_LINE_ENDS:
3067 case GTK_MOVEMENT_PARAGRAPH_ENDS:
3068 case GTK_MOVEMENT_BUFFER_ENDS:
3069 /* FIXME: Can do better here */
3070 new_pos = count < 0 ? 0 : strlen (label->text);
3072 case GTK_MOVEMENT_DISPLAY_LINES:
3073 case GTK_MOVEMENT_PARAGRAPHS:
3074 case GTK_MOVEMENT_PAGES:
3079 if (extend_selection)
3080 gtk_label_select_region_index (label,
3081 label->select_info->selection_anchor,
3084 gtk_label_select_region_index (label, new_pos, new_pos);
3088 gtk_label_copy_clipboard (GtkLabel *label)
3090 if (label->text && label->select_info)
3095 start = MIN (label->select_info->selection_anchor,
3096 label->select_info->selection_end);
3097 end = MAX (label->select_info->selection_anchor,
3098 label->select_info->selection_end);
3100 len = strlen (label->text);
3109 gtk_clipboard_set_text (gtk_widget_get_clipboard (GTK_WIDGET (label),
3110 GDK_SELECTION_CLIPBOARD),
3111 label->text + start, end - start);
3116 gtk_label_select_all (GtkLabel *label)
3118 gtk_label_select_region_index (label, 0, strlen (label->text));
3121 /* Quick hack of a popup menu
3124 activate_cb (GtkWidget *menuitem,
3127 const gchar *signal = g_object_get_data (G_OBJECT (menuitem), "gtk-signal");
3128 g_signal_emit_by_name (label, signal);
3132 append_action_signal (GtkLabel *label,
3134 const gchar *stock_id,
3135 const gchar *signal,
3138 GtkWidget *menuitem = gtk_image_menu_item_new_from_stock (stock_id, NULL);
3140 g_object_set_data (G_OBJECT (menuitem), "gtk-signal", (char *)signal);
3141 g_signal_connect (menuitem, "activate",
3142 G_CALLBACK (activate_cb), label);
3144 gtk_widget_set_sensitive (menuitem, sensitive);
3146 gtk_widget_show (menuitem);
3147 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
3151 popup_menu_detach (GtkWidget *attach_widget,
3155 label = GTK_LABEL (attach_widget);
3157 if (label->select_info)
3158 label->select_info->popup_menu = NULL;
3162 popup_position_func (GtkMenu *menu,
3173 label = GTK_LABEL (user_data);
3174 widget = GTK_WIDGET (label);
3176 if (label->select_info == NULL)
3179 g_return_if_fail (GTK_WIDGET_REALIZED (label));
3181 screen = gtk_widget_get_screen (widget);
3182 gdk_window_get_origin (widget->window, x, y);
3184 gtk_widget_size_request (label->select_info->popup_menu, &req);
3186 *x += widget->allocation.width / 2;
3187 *y += widget->allocation.height;
3189 *x = CLAMP (*x, 0, MAX (0, gdk_screen_get_width (screen) - req.width));
3190 *y = CLAMP (*y, 0, MAX (0, gdk_screen_get_height (screen) - req.height));
3195 gtk_label_do_popup (GtkLabel *label,
3196 GdkEventButton *event)
3198 GtkWidget *menuitem;
3199 gboolean have_selection;
3201 if (label->select_info == NULL)
3204 if (label->select_info->popup_menu)
3205 gtk_widget_destroy (label->select_info->popup_menu);
3207 label->select_info->popup_menu = gtk_menu_new ();
3209 gtk_menu_attach_to_widget (GTK_MENU (label->select_info->popup_menu),
3214 label->select_info->selection_anchor != label->select_info->selection_end;
3217 append_action_signal (label, label->select_info->popup_menu, GTK_STOCK_CUT, "cut_clipboard",
3219 append_action_signal (label, label->select_info->popup_menu, GTK_STOCK_COPY, "copy_clipboard",
3221 append_action_signal (label, label->select_info->popup_menu, GTK_STOCK_PASTE, "paste_clipboard",
3224 menuitem = gtk_menu_item_new_with_label (_("Select All"));
3225 g_signal_connect_swapped (menuitem, "activate",
3226 G_CALLBACK (gtk_label_select_all), label);
3227 gtk_widget_show (menuitem);
3228 gtk_menu_shell_append (GTK_MENU_SHELL (label->select_info->popup_menu), menuitem);
3230 menuitem = gtk_separator_menu_item_new ();
3231 gtk_widget_show (menuitem);
3232 gtk_menu_shell_append (GTK_MENU_SHELL (label->select_info->popup_menu), menuitem);
3234 menuitem = gtk_menu_item_new_with_label (_("Input Methods"));
3235 gtk_widget_show (menuitem);
3236 gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), gtk_menu_new ());
3237 gtk_widget_set_sensitive (menuitem, FALSE);
3238 gtk_menu_shell_append (GTK_MENU_SHELL (label->select_info->popup_menu), menuitem);
3240 g_signal_emit (label,
3241 signals[POPULATE_POPUP],
3243 label->select_info->popup_menu);
3246 gtk_menu_popup (GTK_MENU (label->select_info->popup_menu), NULL, NULL,
3248 event->button, event->time);
3250 gtk_menu_popup (GTK_MENU (label->select_info->popup_menu), NULL, NULL,
3251 popup_position_func, label,
3252 0, gtk_get_current_event_time ());