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 "gdk/gdki18n.h"
36 #include <pango/pango.h>
37 #include "gtkimagemenuitem.h"
39 #include "gtkseparatormenuitem.h"
40 #include "gtkmenuitem.h"
41 #include "gtknotebook.h"
43 #include "gtkbindings.h"
45 struct _GtkLabelSelectionInfo
48 gint selection_anchor;
51 GtkWidget *popup_menu;
77 static guint signals[LAST_SIGNAL] = { 0 };
79 static void gtk_label_class_init (GtkLabelClass *klass);
80 static void gtk_label_init (GtkLabel *label);
81 static void gtk_label_set_property (GObject *object,
85 static void gtk_label_get_property (GObject *object,
89 static void gtk_label_destroy (GtkObject *object);
90 static void gtk_label_finalize (GObject *object);
91 static void gtk_label_size_request (GtkWidget *widget,
92 GtkRequisition *requisition);
93 static void gtk_label_size_allocate (GtkWidget *widget,
94 GtkAllocation *allocation);
95 static void gtk_label_state_changed (GtkWidget *widget,
97 static void gtk_label_style_set (GtkWidget *widget,
98 GtkStyle *previous_style);
99 static void gtk_label_direction_changed (GtkWidget *widget,
100 GtkTextDirection previous_dir);
101 static gint gtk_label_expose (GtkWidget *widget,
102 GdkEventExpose *event);
104 static void gtk_label_realize (GtkWidget *widget);
105 static void gtk_label_unrealize (GtkWidget *widget);
106 static void gtk_label_map (GtkWidget *widget);
107 static void gtk_label_unmap (GtkWidget *widget);
108 static gint gtk_label_button_press (GtkWidget *widget,
109 GdkEventButton *event);
110 static gint gtk_label_button_release (GtkWidget *widget,
111 GdkEventButton *event);
112 static gint gtk_label_motion (GtkWidget *widget,
113 GdkEventMotion *event);
116 static void gtk_label_set_text_internal (GtkLabel *label,
118 static void gtk_label_set_label_internal (GtkLabel *label,
120 static void gtk_label_set_use_markup_internal (GtkLabel *label,
122 static void gtk_label_set_use_underline_internal (GtkLabel *label,
124 static void gtk_label_set_attributes_internal (GtkLabel *label,
125 PangoAttrList *attrs);
126 static void gtk_label_set_uline_text_internal (GtkLabel *label,
128 static void gtk_label_set_pattern_internal (GtkLabel *label,
129 const gchar *pattern);
130 static void set_markup (GtkLabel *label,
132 gboolean with_uline);
133 static void gtk_label_recalculate (GtkLabel *label);
134 static void gtk_label_hierarchy_changed (GtkWidget *widget,
135 GtkWidget *old_toplevel);
137 static void gtk_label_create_window (GtkLabel *label);
138 static void gtk_label_destroy_window (GtkLabel *label);
139 static void gtk_label_clear_layout (GtkLabel *label);
140 static void gtk_label_ensure_layout (GtkLabel *label);
141 static void gtk_label_select_region_index (GtkLabel *label,
145 static gboolean gtk_label_mnemonic_activate (GtkWidget *widget,
146 gboolean group_cycling);
147 static void gtk_label_setup_mnemonic (GtkLabel *label,
149 static gboolean gtk_label_focus (GtkWidget *widget,
150 GtkDirectionType direction);
152 /* For selectable lables: */
153 static void gtk_label_move_cursor (GtkLabel *label,
154 GtkMovementStep step,
156 gboolean extend_selection);
157 static void gtk_label_copy_clipboard (GtkLabel *label);
158 static void gtk_label_select_all (GtkLabel *label);
159 static void gtk_label_do_popup (GtkLabel *label,
160 GdkEventButton *event);
162 static gint gtk_label_move_forward_word (GtkLabel *label,
164 static gint gtk_label_move_backward_word (GtkLabel *label,
167 static GtkMiscClass *parent_class = NULL;
171 gtk_label_get_type (void)
173 static GtkType label_type = 0;
177 static const GTypeInfo label_info =
179 sizeof (GtkLabelClass),
180 NULL, /* base_init */
181 NULL, /* base_finalize */
182 (GClassInitFunc) gtk_label_class_init,
183 NULL, /* class_finalize */
184 NULL, /* class_data */
186 32, /* n_preallocs */
187 (GInstanceInitFunc) gtk_label_init,
190 label_type = g_type_register_static (GTK_TYPE_MISC, "GtkLabel", &label_info, 0);
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 = gtk_type_class (GTK_TYPE_MISC);
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->mnemonic_activate = gtk_label_mnemonic_activate;
250 widget_class->focus = gtk_label_focus;
252 class->move_cursor = gtk_label_move_cursor;
253 class->copy_clipboard = gtk_label_copy_clipboard;
255 signals[MOVE_CURSOR] =
256 gtk_signal_new ("move_cursor",
257 GTK_RUN_LAST | GTK_RUN_ACTION,
258 GTK_CLASS_TYPE (object_class),
259 GTK_SIGNAL_OFFSET (GtkLabelClass, move_cursor),
260 _gtk_marshal_VOID__ENUM_INT_BOOLEAN,
261 GTK_TYPE_NONE, 3, GTK_TYPE_MOVEMENT_STEP, GTK_TYPE_INT, GTK_TYPE_BOOL);
263 signals[COPY_CLIPBOARD] =
264 gtk_signal_new ("copy_clipboard",
265 GTK_RUN_LAST | GTK_RUN_ACTION,
266 GTK_CLASS_TYPE (object_class),
267 GTK_SIGNAL_OFFSET (GtkLabelClass, copy_clipboard),
268 _gtk_marshal_VOID__VOID,
271 signals[POPULATE_POPUP] =
272 gtk_signal_new ("populate_popup",
274 GTK_CLASS_TYPE (object_class),
275 GTK_SIGNAL_OFFSET (GtkLabelClass, populate_popup),
276 _gtk_marshal_VOID__OBJECT,
277 GTK_TYPE_NONE, 1, GTK_TYPE_MENU);
279 g_object_class_install_property (G_OBJECT_CLASS(object_class),
281 g_param_spec_string ("label",
283 _("The text of the label."),
286 g_object_class_install_property (gobject_class,
288 g_param_spec_boxed ("attributes",
290 _("A list of style attributes to apply to the text of the label."),
291 PANGO_TYPE_ATTR_LIST,
293 g_object_class_install_property (gobject_class,
295 g_param_spec_boolean ("use_markup",
297 _("The text of the label includes XML markup. See pango_parse_markup()."),
300 g_object_class_install_property (gobject_class,
302 g_param_spec_boolean ("use_underline",
304 _("If set, an underline in the text indicates the next character should be used for the mnemonic accelerator key"),
308 g_object_class_install_property (gobject_class,
310 g_param_spec_enum ("justify",
312 _("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."),
313 GTK_TYPE_JUSTIFICATION,
317 g_object_class_install_property (gobject_class,
319 g_param_spec_string ("pattern",
321 _("A string with _ characters in positions correspond to characters in the text to underline."),
325 g_object_class_install_property (gobject_class,
327 g_param_spec_boolean ("wrap",
329 _("If set, wrap lines if the text becomes too wide."),
332 g_object_class_install_property (gobject_class,
334 g_param_spec_boolean ("selectable",
336 _("Whether the label text can be selected with the mouse."),
339 g_object_class_install_property (gobject_class,
340 PROP_MNEMONIC_KEYVAL,
341 g_param_spec_uint ("mnemonic_keyval",
343 _("The mnemonic accelerator key for this label."),
348 g_object_class_install_property (gobject_class,
349 PROP_MNEMONIC_WIDGET,
350 g_param_spec_object ("mnemonic_widget",
351 _("Mnemonic widget"),
352 _("The widget to be activated when the label's mnemonic "
357 g_object_class_install_property (gobject_class,
358 PROP_CURSOR_POSITION,
359 g_param_spec_int ("cursor_position",
360 _("Cursor Position"),
361 _("The current position of the insertion cursor in chars."),
367 g_object_class_install_property (gobject_class,
368 PROP_SELECTION_BOUND,
369 g_param_spec_int ("selection_bound",
370 _("Selection Bound"),
371 _("The position of the opposite end of the selection from the cursor in chars."),
377 gtk_widget_class_install_style_property (widget_class,
378 g_param_spec_boxed ("cursor_color",
380 _("Color with which to draw insertion cursor"),
388 binding_set = gtk_binding_set_by_class (class);
390 /* Moving the insertion point */
391 add_move_binding (binding_set, GDK_Right, 0,
392 GTK_MOVEMENT_VISUAL_POSITIONS, 1);
394 add_move_binding (binding_set, GDK_Left, 0,
395 GTK_MOVEMENT_VISUAL_POSITIONS, -1);
397 add_move_binding (binding_set, GDK_KP_Right, 0,
398 GTK_MOVEMENT_VISUAL_POSITIONS, 1);
400 add_move_binding (binding_set, GDK_KP_Left, 0,
401 GTK_MOVEMENT_VISUAL_POSITIONS, -1);
403 add_move_binding (binding_set, GDK_f, GDK_CONTROL_MASK,
404 GTK_MOVEMENT_LOGICAL_POSITIONS, 1);
406 add_move_binding (binding_set, GDK_b, GDK_CONTROL_MASK,
407 GTK_MOVEMENT_LOGICAL_POSITIONS, -1);
409 add_move_binding (binding_set, GDK_Right, GDK_CONTROL_MASK,
410 GTK_MOVEMENT_WORDS, 1);
412 add_move_binding (binding_set, GDK_Left, GDK_CONTROL_MASK,
413 GTK_MOVEMENT_WORDS, -1);
415 add_move_binding (binding_set, GDK_KP_Right, GDK_CONTROL_MASK,
416 GTK_MOVEMENT_WORDS, 1);
418 add_move_binding (binding_set, GDK_KP_Left, GDK_CONTROL_MASK,
419 GTK_MOVEMENT_WORDS, -1);
421 add_move_binding (binding_set, GDK_a, GDK_CONTROL_MASK,
422 GTK_MOVEMENT_PARAGRAPH_ENDS, -1);
424 add_move_binding (binding_set, GDK_e, GDK_CONTROL_MASK,
425 GTK_MOVEMENT_PARAGRAPH_ENDS, 1);
427 add_move_binding (binding_set, GDK_f, GDK_MOD1_MASK,
428 GTK_MOVEMENT_WORDS, 1);
430 add_move_binding (binding_set, GDK_b, GDK_MOD1_MASK,
431 GTK_MOVEMENT_WORDS, -1);
433 add_move_binding (binding_set, GDK_Home, 0,
434 GTK_MOVEMENT_DISPLAY_LINE_ENDS, -1);
436 add_move_binding (binding_set, GDK_End, 0,
437 GTK_MOVEMENT_DISPLAY_LINE_ENDS, 1);
439 add_move_binding (binding_set, GDK_KP_Home, 0,
440 GTK_MOVEMENT_DISPLAY_LINE_ENDS, -1);
442 add_move_binding (binding_set, GDK_KP_End, 0,
443 GTK_MOVEMENT_DISPLAY_LINE_ENDS, 1);
445 add_move_binding (binding_set, GDK_Home, GDK_CONTROL_MASK,
446 GTK_MOVEMENT_BUFFER_ENDS, -1);
448 add_move_binding (binding_set, GDK_End, GDK_CONTROL_MASK,
449 GTK_MOVEMENT_BUFFER_ENDS, 1);
451 add_move_binding (binding_set, GDK_KP_Home, GDK_CONTROL_MASK,
452 GTK_MOVEMENT_BUFFER_ENDS, -1);
454 add_move_binding (binding_set, GDK_KP_End, GDK_CONTROL_MASK,
455 GTK_MOVEMENT_BUFFER_ENDS, 1);
458 gtk_binding_entry_add_signal (binding_set, GDK_c, GDK_CONTROL_MASK,
459 "copy_clipboard", 0);
463 gtk_label_set_property (GObject *object,
471 label = GTK_LABEL (object);
472 last_keyval = label->mnemonic_keyval;
477 gtk_label_set_label (label, g_value_get_string (value));
479 case PROP_ATTRIBUTES:
480 gtk_label_set_attributes (label, g_value_get_boxed (value));
482 case PROP_USE_MARKUP:
483 gtk_label_set_use_markup (label, g_value_get_boolean (value));
485 case PROP_USE_UNDERLINE:
486 gtk_label_set_use_underline (label, g_value_get_boolean (value));
489 gtk_label_set_justify (label, g_value_get_enum (value));
492 gtk_label_set_pattern (label, g_value_get_string (value));
495 gtk_label_set_line_wrap (label, g_value_get_boolean (value));
497 case PROP_SELECTABLE:
498 gtk_label_set_selectable (label, g_value_get_boolean (value));
500 case PROP_MNEMONIC_WIDGET:
501 gtk_label_set_mnemonic_widget (label, (GtkWidget*) g_value_get_object (value));
504 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
510 gtk_label_get_property (GObject *object,
517 label = GTK_LABEL (object);
522 g_value_set_string (value, label->label);
524 case PROP_ATTRIBUTES:
525 g_value_set_boxed (value, label->attrs);
527 case PROP_USE_MARKUP:
528 g_value_set_boolean (value, label->use_markup);
530 case PROP_USE_UNDERLINE:
531 g_value_set_boolean (value, label->use_underline);
534 g_value_set_enum (value, label->jtype);
537 g_value_set_boolean (value, label->wrap);
539 case PROP_SELECTABLE:
540 g_value_set_boolean (value, gtk_label_get_selectable (label));
542 case PROP_MNEMONIC_KEYVAL:
543 g_value_set_uint (value, label->mnemonic_keyval);
545 case PROP_MNEMONIC_WIDGET:
546 g_value_set_object (value, (GObject*) label->mnemonic_widget);
548 case PROP_CURSOR_POSITION:
549 if (label->select_info)
551 gint offset = g_utf8_pointer_to_offset (label->label,
552 label->label + label->select_info->selection_end);
553 g_value_set_int (value, offset);
556 g_value_set_int (value, 0);
558 case PROP_SELECTION_BOUND:
559 if (label->select_info)
561 gint offset = g_utf8_pointer_to_offset (label->label,
562 label->label + label->select_info->selection_anchor);
563 g_value_set_int (value, offset);
566 g_value_set_int (value, 0);
570 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
576 gtk_label_init (GtkLabel *label)
578 GTK_WIDGET_SET_FLAGS (label, GTK_NO_WINDOW);
582 label->jtype = GTK_JUSTIFY_CENTER;
585 label->use_underline = FALSE;
586 label->use_markup = FALSE;
588 label->mnemonic_keyval = GDK_VoidSymbol;
589 label->layout = NULL;
593 label->mnemonic_widget = NULL;
594 label->mnemonic_window = NULL;
596 gtk_label_set_text (label, "");
601 * @str: The text of the label
603 * Creates a new #GtkLabel, containing the text in @str.
605 * Return value: the new #GtkLabel
608 gtk_label_new (const gchar *str)
612 label = gtk_type_new (GTK_TYPE_LABEL);
615 gtk_label_set_text (label, str);
617 return GTK_WIDGET (label);
621 * gtk_label_new_with_mnemonic:
622 * @str: The text of the label, with an underscore in front of the
625 * Creates a new #GtkLabel, containing the text in @str.
627 * If characters in @str are preceded by an underscore, they are
628 * underlined indicating that they represent a keyboard accelerator
629 * called a mnemonic. The mnemonic key can be used to activate
630 * another widget, chosen automatically, or explicitly using
631 * gtk_label_set_mnemonic_widget().
633 * If gtk_label_set_mnemonic_widget()
634 * is not called, then the first activatable ancestor of the #GtkLabel
635 * will be chosen as the mnemonic widget. For instance, if the
636 * label is inside a button or menu item, the button or menu item will
637 * automatically become the mnemonic widget and be activated by
640 * Return value: the new #GtkLabel
643 gtk_label_new_with_mnemonic (const gchar *str)
647 label = gtk_type_new (GTK_TYPE_LABEL);
650 gtk_label_set_text_with_mnemonic (label, str);
652 return GTK_WIDGET (label);
656 gtk_label_mnemonic_activate (GtkWidget *widget,
657 gboolean group_cycling)
661 if (GTK_LABEL (widget)->mnemonic_widget)
662 return gtk_widget_mnemonic_activate (GTK_LABEL (widget)->mnemonic_widget, group_cycling);
664 /* Try to find the widget to activate by traversing the
667 parent = widget->parent;
670 if (GTK_WIDGET_CAN_FOCUS (parent) ||
671 (!group_cycling && GTK_WIDGET_GET_CLASS (parent)->activate_signal) ||
672 (parent->parent && GTK_IS_NOTEBOOK (parent->parent)) ||
673 (GTK_IS_MENU_ITEM (parent)))
674 return gtk_widget_mnemonic_activate (parent, group_cycling);
675 parent = parent->parent;
678 /* barf if there was nothing to activate */
679 g_warning ("Couldn't find a target for a mnemonic activation.");
686 gtk_label_setup_mnemonic (GtkLabel *label,
691 if (last_key != GDK_VoidSymbol && label->mnemonic_window)
693 gtk_window_remove_mnemonic (label->mnemonic_window,
696 label->mnemonic_window = NULL;
699 if (label->mnemonic_keyval == GDK_VoidSymbol)
702 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (label));
703 if (GTK_WIDGET_TOPLEVEL (toplevel))
705 gtk_window_add_mnemonic (GTK_WINDOW (toplevel),
706 label->mnemonic_keyval,
708 label->mnemonic_window = GTK_WINDOW (toplevel);
713 gtk_label_hierarchy_changed (GtkWidget *widget,
714 GtkWidget *old_toplevel)
716 GtkLabel *label = GTK_LABEL (widget);
718 gtk_label_setup_mnemonic (label, label->mnemonic_keyval);
723 * gtk_label_set_mnemonic_widget:
724 * @label: a #GtkLabel
725 * @widget: the target #GtkWidget
727 * If the label has been set so that it has an mnemonic key (using
728 * i.e. gtk_label_set_markup_with_mnemonic(),
729 * gtk_label_set_text_with_mnemonic(), gtk_label_new_with_mnemonic()
730 * or the "use_underline" property) the label can be associated with a
731 * widget that is the target of the mnemonic. When the label is inside
732 * a widget (like a #GtkButton or a #GtkNotebook tab) it is
733 * automatically associated with the correct widget, but sometimes
734 * (i.e. when the target is a #GtkEntry next to the label) you need to
735 * set it explicitly using this function.
737 * The target widget will be accelerated by emitting "mnemonic_activate" on it.
738 * The default handler for this signal will activate the widget if there are no
739 * mnemonic collisions and toggle focus between the colliding widgets otherwise.
742 gtk_label_set_mnemonic_widget (GtkLabel *label,
745 g_return_if_fail (GTK_IS_LABEL (label));
747 g_return_if_fail (GTK_IS_WIDGET (widget));
749 if (label->mnemonic_widget)
750 gtk_widget_unref (label->mnemonic_widget);
751 label->mnemonic_widget = widget;
752 if (label->mnemonic_widget)
753 gtk_widget_ref (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
901 * Sets the text of the label to @str.
903 * This will also clear any previously set mnemonic accelerators.
906 gtk_label_set_text (GtkLabel *label,
909 g_return_if_fail (GTK_IS_LABEL (label));
911 gtk_label_set_label_internal (label, g_strdup (str ? str : ""));
912 gtk_label_set_use_markup_internal (label, FALSE);
913 gtk_label_set_use_underline_internal (label, FALSE);
915 gtk_label_recalculate (label);
919 * gtk_label_set_attributes:
920 * @label: a #GtkLabel
921 * @attrs: a #PangoAttrList
923 * Sets a #PangoAttrList; the attributes in the list are applied to the
924 * label text. The attributes set with this function will be ignored
925 * if label->use_underline or label->use_markup is %TRUE.
928 gtk_label_set_attributes (GtkLabel *label,
929 PangoAttrList *attrs)
931 g_return_if_fail (GTK_IS_LABEL (label));
933 gtk_label_set_attributes_internal (label, attrs);
935 gtk_label_clear_layout (label);
936 gtk_widget_queue_resize (GTK_WIDGET (label));
940 * gtk_label_get_attributes:
941 * @label: a #GtkLabel
943 * Gets the attribute list that was set on the label using
944 * gtk_label_set_attributes(), if any. This function does
945 * not reflect attributes that come from the labels markup
946 * (see gtk_label_set_markup()). If you want to get the
947 * effective attributes for the label, use
948 * pango_layout_get_attribute (gtk_label_get_layout (label)).
950 * Return value: the attribute list, or %NULL if none was set.
953 gtk_label_get_attributes (GtkLabel *label)
955 g_return_val_if_fail (GTK_IS_LABEL (label), NULL);
961 * gtk_label_set_label:
962 * @label: a #GtkLabel
963 * @str: the new text to set for the label
965 * Sets the text of the label. The label is interpreted as
966 * including embedded underlines and/or Pango markup depending
967 * on the values of label->use_underline and label->use_markup.
970 gtk_label_set_label (GtkLabel *label,
975 g_return_if_fail (GTK_IS_LABEL (label));
976 g_return_if_fail (str != NULL);
978 last_keyval = label->mnemonic_keyval;
980 gtk_label_set_label_internal (label, g_strdup (str));
981 gtk_label_recalculate (label);
982 if (last_keyval != label->mnemonic_keyval)
983 gtk_label_setup_mnemonic (label, last_keyval);
987 * gtk_label_get_label:
988 * @label: a #GtkLabel
990 * Fetches the text from a label widget including any embedded
991 * underlines indicating mnemonics and Pango markup. (See
992 * gtk_label_get_text ()).
994 * Return value: the text of the label widget. This string is
995 * owned by the widget and must not be modified or freed.
997 G_CONST_RETURN gchar *
998 gtk_label_get_label (GtkLabel *label)
1000 g_return_val_if_fail (GTK_IS_LABEL (label), NULL);
1002 return label->label;
1006 set_markup (GtkLabel *label,
1008 gboolean with_uline)
1011 GError *error = NULL;
1012 PangoAttrList *attrs = NULL;
1013 gunichar accel_char = 0;
1015 if (!pango_parse_markup (str,
1017 with_uline ? '_' : 0,
1020 with_uline ? &accel_char : NULL,
1023 g_warning ("Failed to set label from markup due to error parsing markup: %s",
1025 g_error_free (error);
1030 gtk_label_set_text_internal (label, text);
1034 if (label->effective_attrs)
1035 pango_attr_list_unref (label->effective_attrs);
1036 label->effective_attrs = attrs;
1039 if (accel_char != 0)
1040 label->mnemonic_keyval = gdk_keyval_to_lower (gdk_unicode_to_keyval (accel_char));
1042 label->mnemonic_keyval = GDK_VoidSymbol;
1046 * gtk_label_set_markup:
1047 * @label: a #GtkLabel
1048 * @str: a markup string (see <link linkend="PangoMarkupFormat">Pango markup format</link>)
1050 * Parses @str which is marked up with the Pango text markup language,
1051 * setting the label's text and attribute list based on the parse results.
1054 gtk_label_set_markup (GtkLabel *label,
1057 g_return_if_fail (GTK_IS_LABEL (label));
1059 gtk_label_set_label_internal (label, g_strdup (str ? str : ""));
1060 gtk_label_set_use_markup_internal (label, TRUE);
1061 gtk_label_set_use_underline_internal (label, FALSE);
1063 gtk_label_recalculate (label);
1067 * gtk_label_set_markup_with_mnemonic:
1068 * @label: a #GtkLabel
1069 * @str: a markup string (see <link linkend="PangoMarkupFormat">Pango markup format</link>)
1071 * Parses @str which is marked up with the Pango text markup language,
1072 * setting the label's text and attribute list based on the parse results.
1073 * If characters in @str are preceded by an underscore, they are underlined
1074 * indicating that they represent a keyboard accelerator called a mnemonic.
1076 * The mnemonic key can be used to activate another widget, chosen automatically,
1077 * or explicitly using gtk_label_set_mnemonic_widget().
1080 gtk_label_set_markup_with_mnemonic (GtkLabel *label,
1084 g_return_if_fail (GTK_IS_LABEL (label));
1086 last_keyval = label->mnemonic_keyval;
1087 gtk_label_set_label_internal (label, g_strdup (str ? str : ""));
1088 gtk_label_set_use_markup_internal (label, TRUE);
1089 gtk_label_set_use_underline_internal (label, TRUE);
1091 gtk_label_recalculate (label);
1092 gtk_label_setup_mnemonic (label, last_keyval);
1096 * gtk_label_get_text:
1097 * @label: a #GtkLabel
1099 * Fetches the text from a label widget, as displayed on the
1100 * screen. This does not include any embedded underlines
1101 * indicating mnemonics or Pango markup. (See gtk_label_get_label())
1103 * Return value: the text in the label widget. This is the internal
1104 * string used by the label, and must not be modified.
1106 G_CONST_RETURN gchar *
1107 gtk_label_get_text (GtkLabel *label)
1109 g_return_val_if_fail (GTK_IS_LABEL (label), NULL);
1114 static PangoAttrList *
1115 gtk_label_pattern_to_attrs (GtkLabel *label,
1116 const gchar *pattern)
1119 const char *p = label->text;
1120 const char *q = pattern;
1121 PangoAttrList *attrs;
1123 attrs = pango_attr_list_new ();
1127 while (*p && *q && *q != '_')
1129 p = g_utf8_next_char (p);
1133 while (*p && *q && *q == '_')
1135 p = g_utf8_next_char (p);
1141 PangoAttribute *attr = pango_attr_underline_new (PANGO_UNDERLINE_LOW);
1142 attr->start_index = start - label->text;
1143 attr->end_index = p - label->text;
1145 pango_attr_list_insert (attrs, attr);
1155 gtk_label_set_pattern_internal (GtkLabel *label,
1156 const gchar *pattern)
1158 PangoAttrList *attrs;
1159 g_return_if_fail (GTK_IS_LABEL (label));
1161 attrs = gtk_label_pattern_to_attrs (label, pattern);
1163 if (label->effective_attrs)
1164 pango_attr_list_unref (label->effective_attrs);
1165 label->effective_attrs = attrs;
1169 gtk_label_set_pattern (GtkLabel *label,
1170 const gchar *pattern)
1172 g_return_if_fail (GTK_IS_LABEL (label));
1174 gtk_label_set_pattern_internal (label, pattern);
1176 gtk_label_clear_layout (label);
1177 gtk_widget_queue_resize (GTK_WIDGET (label));
1182 * gtk_label_set_justify:
1183 * @label: a #GtkLabel
1184 * @jtype: a #GtkJustification
1186 * Sets the alignment of the lines in the text of the label relative to
1190 gtk_label_set_justify (GtkLabel *label,
1191 GtkJustification jtype)
1193 g_return_if_fail (GTK_IS_LABEL (label));
1194 g_return_if_fail (jtype >= GTK_JUSTIFY_LEFT && jtype <= GTK_JUSTIFY_FILL);
1196 if ((GtkJustification) label->jtype != jtype)
1198 label->jtype = jtype;
1200 /* No real need to be this drastic, but easier than duplicating the code */
1201 gtk_label_clear_layout (label);
1203 g_object_notify (G_OBJECT (label), "justify");
1204 gtk_widget_queue_resize (GTK_WIDGET (label));
1209 * gtk_label_get_justify:
1210 * @label: a #GtkLabel
1212 * Returns the justification of the label. See gtk_label_set_justify ().
1214 * Return value: #GtkJustification
1217 gtk_label_get_justify (GtkLabel *label)
1219 g_return_val_if_fail (GTK_IS_LABEL (label), 0);
1221 return label->jtype;
1225 * gtk_label_set_line_wrap:
1226 * @label: a #GtkLabel
1227 * @wrap: the setting
1229 * If true, the lines will be wrapped if the text becomes too wide.
1232 gtk_label_set_line_wrap (GtkLabel *label,
1235 g_return_if_fail (GTK_IS_LABEL (label));
1237 wrap = wrap != FALSE;
1239 if (label->wrap != wrap)
1242 g_object_notify (G_OBJECT (label), "wrap");
1244 gtk_widget_queue_resize (GTK_WIDGET (label));
1249 * gtk_label_get_line_wrap:
1250 * @label: a #GtkLabel
1252 * Returns whether lines in the label are automatically wrapped. See gtk_label_set_line_wrap ().
1254 * Return value: %TRUE if the lines of the label are automatically wrapped.
1257 gtk_label_get_line_wrap (GtkLabel *label)
1259 g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
1265 gtk_label_get (GtkLabel *label,
1268 g_return_if_fail (GTK_IS_LABEL (label));
1269 g_return_if_fail (str != NULL);
1275 gtk_label_destroy (GtkObject *object)
1277 GtkLabel *label = GTK_LABEL (object);
1279 gtk_label_set_mnemonic_widget (label, NULL);
1281 GTK_OBJECT_CLASS (parent_class)->destroy (object);
1285 gtk_label_finalize (GObject *object)
1289 g_return_if_fail (GTK_IS_LABEL (object));
1291 label = GTK_LABEL (object);
1293 g_free (label->label);
1294 g_free (label->text);
1297 g_object_unref (G_OBJECT (label->layout));
1300 pango_attr_list_unref (label->attrs);
1302 if (label->effective_attrs)
1303 pango_attr_list_unref (label->effective_attrs);
1305 g_free (label->select_info);
1307 G_OBJECT_CLASS (parent_class)->finalize (object);
1311 gtk_label_clear_layout (GtkLabel *label)
1315 g_object_unref (G_OBJECT (label->layout));
1316 label->layout = NULL;
1321 gtk_label_ensure_layout (GtkLabel *label)
1324 PangoRectangle logical_rect;
1325 gint rwidth, rheight;
1327 widget = GTK_WIDGET (label);
1329 rwidth = label->misc.xpad * 2;
1330 rheight = label->misc.ypad * 2;
1334 PangoAlignment align = PANGO_ALIGN_LEFT; /* Quiet gcc */
1336 label->layout = gtk_widget_create_pango_layout (widget, label->text);
1338 if (label->effective_attrs)
1339 pango_layout_set_attributes (label->layout, label->effective_attrs);
1341 switch (label->jtype)
1343 case GTK_JUSTIFY_LEFT:
1344 align = PANGO_ALIGN_LEFT;
1346 case GTK_JUSTIFY_RIGHT:
1347 align = PANGO_ALIGN_RIGHT;
1349 case GTK_JUSTIFY_CENTER:
1350 align = PANGO_ALIGN_CENTER;
1352 case GTK_JUSTIFY_FILL:
1353 /* FIXME: This just doesn't work to do this */
1354 align = PANGO_ALIGN_LEFT;
1355 pango_layout_set_justify (label->layout, TRUE);
1358 g_assert_not_reached();
1361 pango_layout_set_alignment (label->layout, align);
1365 GtkWidgetAuxInfo *aux_info;
1366 gint longest_paragraph;
1369 aux_info = _gtk_widget_get_aux_info (widget, FALSE);
1370 if (aux_info && aux_info->width > 0)
1371 pango_layout_set_width (label->layout, aux_info->width * PANGO_SCALE);
1374 pango_layout_set_width (label->layout, -1);
1375 pango_layout_get_extents (label->layout, NULL, &logical_rect);
1377 width = logical_rect.width;
1379 /* Try to guess a reasonable maximum width */
1380 longest_paragraph = width;
1383 PANGO_SCALE * gdk_string_width (gtk_style_get_font (GTK_WIDGET (label)->style),
1384 "This long string gives a good enough length for any line to have."));
1386 PANGO_SCALE * (gdk_screen_width () + 1) / 2);
1388 pango_layout_set_width (label->layout, width);
1389 pango_layout_get_extents (label->layout, NULL, &logical_rect);
1390 height = logical_rect.height;
1392 /* Unfortunately, the above may leave us with a very unbalanced looking paragraph,
1393 * so we try short search for a narrower width that leaves us with the same height
1395 if (longest_paragraph > 0)
1397 gint nlines, perfect_width;
1399 nlines = pango_layout_get_line_count (label->layout);
1400 perfect_width = (longest_paragraph + nlines - 1) / nlines;
1402 if (perfect_width < width)
1404 pango_layout_set_width (label->layout, perfect_width);
1405 pango_layout_get_extents (label->layout, NULL, &logical_rect);
1407 if (logical_rect.height <= height)
1408 width = perfect_width;
1411 gint mid_width = (perfect_width + width) / 2;
1413 if (mid_width > perfect_width)
1415 pango_layout_set_width (label->layout, mid_width);
1416 pango_layout_get_extents (label->layout, NULL, &logical_rect);
1418 if (logical_rect.height <= height)
1424 pango_layout_set_width (label->layout, width);
1427 else /* !label->wrap */
1428 pango_layout_set_width (label->layout, -1);
1433 gtk_label_size_request (GtkWidget *widget,
1434 GtkRequisition *requisition)
1438 PangoRectangle logical_rect;
1439 GtkWidgetAuxInfo *aux_info;
1441 g_return_if_fail (GTK_IS_LABEL (widget));
1442 g_return_if_fail (requisition != NULL);
1444 label = GTK_LABEL (widget);
1447 * If word wrapping is on, then the height requisition can depend
1450 * - Any width set on the widget via gtk_widget_set_usize().
1451 * - The padding of the widget (xpad, set by gtk_misc_set_padding)
1453 * Instead of trying to detect changes to these quantities, if we
1454 * are wrapping, we just rewrap for each size request. Since
1455 * size requisitions are cached by the GTK+ core, this is not
1460 gtk_label_clear_layout (label);
1462 gtk_label_ensure_layout (label);
1464 width = label->misc.xpad * 2;
1465 height = label->misc.ypad * 2;
1467 pango_layout_get_extents (label->layout, NULL, &logical_rect);
1469 aux_info = _gtk_widget_get_aux_info (widget, FALSE);
1470 if (label->wrap && aux_info && aux_info->width > 0)
1471 width += aux_info->width;
1473 width += PANGO_PIXELS (logical_rect.width);
1475 height += PANGO_PIXELS (logical_rect.height);
1477 requisition->width = width;
1478 requisition->height = height;
1482 gtk_label_size_allocate (GtkWidget *widget,
1483 GtkAllocation *allocation)
1487 label = GTK_LABEL (widget);
1489 (* GTK_WIDGET_CLASS (parent_class)->size_allocate) (widget, allocation);
1491 if (label->select_info && label->select_info->window)
1493 gdk_window_move_resize (label->select_info->window,
1497 allocation->height);
1502 gtk_label_state_changed (GtkWidget *widget,
1503 GtkStateType prev_state)
1507 label = GTK_LABEL (widget);
1509 if (label->select_info)
1510 gtk_label_select_region (label, 0, 0);
1512 if (GTK_WIDGET_CLASS (parent_class)->state_changed)
1513 GTK_WIDGET_CLASS (parent_class)->state_changed (widget, prev_state);
1517 gtk_label_style_set (GtkWidget *widget,
1518 GtkStyle *previous_style)
1522 g_return_if_fail (GTK_IS_LABEL (widget));
1524 label = GTK_LABEL (widget);
1526 /* We have to clear the layout, fonts etc. may have changed */
1527 gtk_label_clear_layout (label);
1531 gtk_label_direction_changed (GtkWidget *widget,
1532 GtkTextDirection previous_dir)
1534 GtkLabel *label = GTK_LABEL (widget);
1537 pango_layout_context_changed (label->layout);
1539 GTK_WIDGET_CLASS (parent_class)->direction_changed (widget, previous_dir);
1544 gtk_label_paint_word (GtkLabel *label,
1550 GtkWidget *widget = GTK_WIDGET (label);
1551 GtkLabelULine *uline;
1554 tmp_str = gdk_wcstombs (word->beginning);
1557 gtk_paint_string (widget->style, widget->window, widget->state,
1558 area, widget, "label",
1565 for (uline = word->uline; uline; uline = uline->next)
1566 gtk_paint_hline (widget->style, widget->window,
1567 widget->state, area,
1569 x + uline->x1, x + uline->x2, y + uline->y);
1574 get_layout_location (GtkLabel *label,
1583 misc = GTK_MISC (label);
1584 widget = GTK_WIDGET (label);
1586 if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
1587 xalign = misc->xalign;
1589 xalign = 1.0 - misc->xalign;
1591 x = floor (widget->allocation.x + (gint)misc->xpad
1592 + ((widget->allocation.width - widget->requisition.width) * xalign)
1595 y = floor (widget->allocation.y + (gint)misc->ypad
1596 + ((widget->allocation.height - widget->requisition.height) * misc->yalign)
1608 gtk_label_draw_cursor (GtkLabel *label, gint xoffset, gint yoffset)
1610 if (label->select_info == NULL)
1613 if (GTK_WIDGET_DRAWABLE (label))
1615 GtkWidget *widget = GTK_WIDGET (label);
1617 GtkTextDirection keymap_direction;
1618 GtkTextDirection widget_direction;
1619 PangoRectangle strong_pos, weak_pos;
1620 gboolean split_cursor;
1621 PangoRectangle *cursor1 = NULL;
1622 PangoRectangle *cursor2 = NULL;
1623 GdkRectangle cursor_location;
1624 GtkTextDirection dir1 = GTK_TEXT_DIR_NONE;
1625 GtkTextDirection dir2 = GTK_TEXT_DIR_NONE;
1630 (gdk_keymap_get_direction (gdk_keymap_get_default ()) == PANGO_DIRECTION_LTR) ?
1631 GTK_TEXT_DIR_LTR : GTK_TEXT_DIR_RTL;
1633 widget_direction = gtk_widget_get_direction (widget);
1635 gtk_label_ensure_layout (label);
1637 pango_layout_get_cursor_pos (label->layout, label->select_info->selection_end,
1638 &strong_pos, &weak_pos);
1640 g_object_get (gtk_widget_get_settings (widget),
1641 "gtk-split-cursor", &split_cursor,
1646 gc1 = label->select_info->cursor_gc;
1647 cursor1 = &strong_pos;
1649 if (strong_pos.x != weak_pos.x ||
1650 strong_pos.y != weak_pos.y)
1652 dir1 = widget_direction;
1653 dir2 = (widget_direction == GTK_TEXT_DIR_LTR) ? GTK_TEXT_DIR_RTL : GTK_TEXT_DIR_LTR;
1655 gc2 = widget->style->black_gc;
1656 cursor2 = &weak_pos;
1661 gc1 = label->select_info->cursor_gc;
1663 if (keymap_direction == widget_direction)
1664 cursor1 = &strong_pos;
1666 cursor1 = &weak_pos;
1669 cursor_location.x = xoffset + PANGO_PIXELS (cursor1->x);
1670 cursor_location.y = yoffset + PANGO_PIXELS (cursor1->y);
1671 cursor_location.width = 0;
1672 cursor_location.height = PANGO_PIXELS (cursor1->height);
1674 _gtk_draw_insertion_cursor (widget->window, gc1,
1675 &cursor_location, dir1);
1679 cursor_location.x = xoffset + PANGO_PIXELS (cursor2->x);
1680 cursor_location.y = yoffset + PANGO_PIXELS (cursor2->y);
1681 cursor_location.width = 0;
1682 cursor_location.height = PANGO_PIXELS (cursor2->height);
1684 _gtk_draw_insertion_cursor (widget->window, gc2,
1685 &cursor_location, dir2);
1692 gtk_label_expose (GtkWidget *widget,
1693 GdkEventExpose *event)
1698 g_return_val_if_fail (GTK_IS_LABEL (widget), FALSE);
1699 g_return_val_if_fail (event != NULL, FALSE);
1701 label = GTK_LABEL (widget);
1703 gtk_label_ensure_layout (label);
1705 if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_MAPPED (widget) &&
1706 label->text && (*label->text != '\0'))
1708 get_layout_location (label, &x, &y);
1710 gtk_paint_layout (widget->style,
1712 GTK_WIDGET_STATE (widget),
1720 if (label->select_info &&
1721 (label->select_info->selection_anchor !=
1722 label->select_info->selection_end))
1728 range[0] = label->select_info->selection_anchor;
1729 range[1] = label->select_info->selection_end;
1731 if (range[0] > range[1])
1733 gint tmp = range[0];
1734 range[0] = range[1];
1738 clip = gdk_pango_layout_get_clip_region (label->layout,
1743 /* FIXME should use gtk_paint, but it can't use a clip
1747 gdk_gc_set_clip_region (widget->style->black_gc, clip);
1750 state = GTK_STATE_SELECTED;
1751 if (!GTK_WIDGET_HAS_FOCUS (widget))
1752 state = GTK_STATE_ACTIVE;
1754 gdk_draw_layout_with_colors (widget->window,
1755 widget->style->black_gc,
1758 &widget->style->text[state],
1759 &widget->style->base[state]);
1761 gdk_gc_set_clip_region (widget->style->black_gc, NULL);
1762 gdk_region_destroy (clip);
1764 else if (label->select_info && GTK_WIDGET_HAS_FOCUS (widget))
1765 gtk_label_draw_cursor (label, x, y);
1772 gtk_label_set_uline_text_internal (GtkLabel *label,
1775 guint accel_key = GDK_VoidSymbol;
1780 gchar *dest, *pattern_dest;
1781 gboolean underscore;
1783 g_return_if_fail (GTK_IS_LABEL (label));
1784 g_return_if_fail (str != NULL);
1786 /* Convert text to wide characters */
1788 new_str = g_new (gchar, strlen (str) + 1);
1789 pattern = g_new (gchar, g_utf8_strlen (str, -1) + 1);
1798 pattern_dest = pattern;
1805 c = g_utf8_get_char (src);
1806 if (c == (gunichar)-1)
1808 g_warning ("Invalid input string");
1813 next_src = g_utf8_next_char (src);
1818 *pattern_dest++ = ' ';
1821 *pattern_dest++ = '_';
1822 if (accel_key == GDK_VoidSymbol)
1823 accel_key = gdk_keyval_to_lower (c);
1826 while (src < next_src)
1840 while (src < next_src)
1843 *pattern_dest++ = ' ';
1850 gtk_label_set_text_internal (label, new_str);
1851 gtk_label_set_pattern_internal (label, pattern);
1855 label->mnemonic_keyval = accel_key;
1859 gtk_label_parse_uline (GtkLabel *label,
1865 g_return_val_if_fail (GTK_IS_LABEL (label), GDK_VoidSymbol);
1866 g_return_val_if_fail (str != NULL, GDK_VoidSymbol);
1868 orig_keyval = label->mnemonic_keyval;
1870 gtk_label_set_label_internal (label, g_strdup (str ? str : ""));
1871 gtk_label_set_use_markup_internal (label, FALSE);
1872 gtk_label_set_use_underline_internal (label, TRUE);
1874 gtk_label_recalculate (label);
1876 keyval = label->mnemonic_keyval;
1877 label->mnemonic_keyval = GDK_VoidSymbol;
1879 gtk_label_setup_mnemonic (label, orig_keyval);
1885 * gtk_label_set_text_with_mnemonic:
1886 * @label: a #GtkLabel
1889 * Sets the label's text from the string @str.
1890 * If characters in @str are preceded by an underscore, they are underlined
1891 * indicating that they represent a keyboard accelerator called a mnemonic.
1892 * The mnemonic key can be used to activate another widget, chosen automatically,
1893 * or explicitly using gtk_label_set_mnemonic_widget().
1896 gtk_label_set_text_with_mnemonic (GtkLabel *label,
1901 g_return_if_fail (GTK_IS_LABEL (label));
1902 g_return_if_fail (str != NULL);
1904 last_keyval = label->mnemonic_keyval;
1906 gtk_label_set_label_internal (label, g_strdup (str ? str : ""));
1907 gtk_label_set_use_markup_internal (label, FALSE);
1908 gtk_label_set_use_underline_internal (label, TRUE);
1910 gtk_label_recalculate (label);
1912 gtk_label_setup_mnemonic (label, last_keyval);
1916 gtk_label_realize_cursor_gc (GtkLabel *label)
1918 GdkColor *cursor_color;
1919 GdkColor red = {0, 0xffff, 0x0000, 0x0000};
1921 if (label->select_info == NULL)
1924 if (label->select_info->cursor_gc)
1925 gdk_gc_unref (label->select_info->cursor_gc);
1927 gtk_widget_style_get (GTK_WIDGET (label), "cursor_color", &cursor_color, NULL);
1928 label->select_info->cursor_gc = gdk_gc_new (GTK_WIDGET (label)->window);
1930 gdk_gc_set_rgb_fg_color (label->select_info->cursor_gc, cursor_color);
1932 gdk_gc_set_rgb_fg_color (label->select_info->cursor_gc, &red);
1936 gtk_label_realize (GtkWidget *widget)
1940 label = GTK_LABEL (widget);
1942 (* GTK_WIDGET_CLASS (parent_class)->realize) (widget);
1944 if (label->select_info)
1946 gtk_label_create_window (label);
1947 gtk_label_realize_cursor_gc (label);
1952 gtk_label_unrealize_cursor_gc (GtkLabel *label)
1954 if (label->select_info == NULL)
1957 if (label->select_info->cursor_gc)
1959 gdk_gc_unref (label->select_info->cursor_gc);
1960 label->select_info->cursor_gc = NULL;
1965 gtk_label_unrealize (GtkWidget *widget)
1969 label = GTK_LABEL (widget);
1971 if (label->select_info)
1973 gtk_label_unrealize_cursor_gc (label);
1974 gtk_label_destroy_window (label);
1977 (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
1981 gtk_label_map (GtkWidget *widget)
1985 label = GTK_LABEL (widget);
1987 (* GTK_WIDGET_CLASS (parent_class)->map) (widget);
1989 if (label->select_info)
1990 gdk_window_show (label->select_info->window);
1994 gtk_label_unmap (GtkWidget *widget)
1998 label = GTK_LABEL (widget);
2000 if (label->select_info)
2001 gdk_window_hide (label->select_info->window);
2003 (* GTK_WIDGET_CLASS (parent_class)->unmap) (widget);
2007 window_to_layout_coords (GtkLabel *label,
2014 widget = GTK_WIDGET (label);
2016 /* get layout location in widget->window coords */
2017 get_layout_location (label, &lx, &ly);
2021 *x += widget->allocation.x; /* go to widget->window */
2022 *x -= lx; /* go to layout */
2027 *y += widget->allocation.y; /* go to widget->window */
2028 *y -= ly; /* go to layout */
2034 layout_to_window_coords (GtkLabel *label,
2041 widget = GTK_WIDGET (label);
2043 /* get layout location in widget->window coords */
2044 get_layout_location (label, &lx, &ly);
2048 *x += lx; /* go to widget->window */
2049 *x -= widget->allocation.x; /* go to selection window */
2054 *y += ly; /* go to widget->window */
2055 *y -= widget->allocation.y; /* go to selection window */
2061 get_layout_index (GtkLabel *label,
2067 const gchar *cluster;
2068 const gchar *cluster_end;
2072 gtk_label_ensure_layout (label);
2074 window_to_layout_coords (label, &x, &y);
2079 pango_layout_xy_to_index (label->layout,
2084 cluster = label->text + *index;
2085 cluster_end = cluster;
2088 cluster_end = g_utf8_next_char (cluster_end);
2092 *index += (cluster_end - cluster);
2096 gtk_label_select_word (GtkLabel *label)
2100 gint start_index = gtk_label_move_backward_word (label, label->select_info->selection_end);
2101 gint end_index = gtk_label_move_forward_word (label, label->select_info->selection_end);
2103 min = MIN (label->select_info->selection_anchor,
2104 label->select_info->selection_end);
2105 max = MAX (label->select_info->selection_anchor,
2106 label->select_info->selection_end);
2108 min = MIN (min, start_index);
2109 max = MAX (max, end_index);
2111 gtk_label_select_region_index (label, min, max);
2115 gtk_label_button_press (GtkWidget *widget,
2116 GdkEventButton *event)
2121 label = GTK_LABEL (widget);
2123 if (label->select_info == NULL)
2126 if (event->button == 1)
2128 if (!GTK_WIDGET_HAS_FOCUS (widget))
2129 gtk_widget_grab_focus (widget);
2131 if (event->type == GDK_3BUTTON_PRESS)
2133 gtk_label_select_region_index (label, 0, strlen (label->label));
2137 if (event->type == GDK_2BUTTON_PRESS)
2139 gtk_label_select_word (label);
2143 get_layout_index (label, event->x, event->y, &index);
2145 if ((label->select_info->selection_anchor !=
2146 label->select_info->selection_end) &&
2147 (event->state & GDK_SHIFT_MASK))
2151 /* extend (same as motion) */
2152 min = MIN (label->select_info->selection_anchor,
2153 label->select_info->selection_end);
2154 max = MAX (label->select_info->selection_anchor,
2155 label->select_info->selection_end);
2157 min = MIN (min, index);
2158 max = MAX (max, index);
2160 /* ensure the anchor is opposite index */
2168 gtk_label_select_region_index (label, min, max);
2172 if (event->type == GDK_3BUTTON_PRESS)
2173 gtk_label_select_region_index (label, 0, strlen (label->label));
2174 else if (event->type == GDK_2BUTTON_PRESS)
2175 gtk_label_select_word (label);
2177 /* start a replacement */
2178 gtk_label_select_region_index (label, index, index);
2183 else if (event->button == 3 && event->type == GDK_BUTTON_PRESS)
2185 gtk_label_do_popup (label, event);
2194 gtk_label_button_release (GtkWidget *widget,
2195 GdkEventButton *event)
2200 label = GTK_LABEL (widget);
2202 if (label->select_info == NULL)
2205 if (event->button != 1)
2208 /* The goal here is to return TRUE iff we ate the
2209 * button press to start selecting.
2216 gtk_label_motion (GtkWidget *widget,
2217 GdkEventMotion *event)
2223 label = GTK_LABEL (widget);
2225 if (label->select_info == NULL)
2228 if ((event->state & GDK_BUTTON1_MASK) == 0)
2231 gdk_window_get_pointer (label->select_info->window,
2234 get_layout_index (label, x, y, &index);
2236 gtk_label_select_region_index (label,
2237 label->select_info->selection_anchor,
2244 gtk_label_create_window (GtkLabel *label)
2247 GdkWindowAttr attributes;
2248 gint attributes_mask;
2250 g_assert (label->select_info);
2251 g_assert (GTK_WIDGET_REALIZED (label));
2253 if (label->select_info->window)
2256 widget = GTK_WIDGET (label);
2258 attributes.x = widget->allocation.x;
2259 attributes.y = widget->allocation.y;
2260 attributes.width = widget->allocation.width;
2261 attributes.height = widget->allocation.height;
2262 attributes.window_type = GDK_WINDOW_TEMP;
2263 attributes.wclass = GDK_INPUT_ONLY;
2264 attributes.override_redirect = TRUE;
2265 attributes.event_mask = gtk_widget_get_events (widget) |
2266 GDK_BUTTON_PRESS_MASK |
2267 GDK_BUTTON_RELEASE_MASK |
2268 GDK_BUTTON_MOTION_MASK;
2270 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_NOREDIR;
2272 label->select_info->window = gdk_window_new (widget->window,
2273 &attributes, attributes_mask);
2274 gdk_window_set_user_data (label->select_info->window, widget);
2278 gtk_label_destroy_window (GtkLabel *label)
2280 g_assert (label->select_info);
2282 if (label->select_info->window == NULL)
2285 gdk_window_set_user_data (label->select_info->window, NULL);
2286 gdk_window_destroy (label->select_info->window);
2287 label->select_info->window = NULL;
2291 * gtk_label_set_selectable:
2292 * @label: a #GtkLabel
2293 * @setting: %TRUE to allow selecting text in the label
2295 * Selectable labels allow the user to select text from the label, for
2300 gtk_label_set_selectable (GtkLabel *label,
2303 gboolean old_setting;
2305 g_return_if_fail (GTK_IS_LABEL (label));
2307 setting = setting != FALSE;
2308 old_setting = label->select_info != NULL;
2312 if (label->select_info == NULL)
2314 label->select_info = g_new0 (GtkLabelSelectionInfo, 1);
2316 GTK_WIDGET_SET_FLAGS (label, GTK_CAN_FOCUS);
2318 if (GTK_WIDGET_REALIZED (label))
2320 gtk_label_create_window (label);
2321 gtk_label_realize_cursor_gc (label);
2324 if (GTK_WIDGET_MAPPED (label))
2325 gdk_window_show (label->select_info->window);
2330 if (label->select_info)
2332 /* unselect, to give up the selection */
2333 gtk_label_select_region (label, 0, 0);
2335 gtk_label_unrealize_cursor_gc (label);
2337 if (label->select_info->window)
2339 gtk_label_destroy_window (label);
2342 g_free (label->select_info);
2344 label->select_info = NULL;
2346 GTK_WIDGET_UNSET_FLAGS (label, GTK_CAN_FOCUS);
2349 if (setting != old_setting)
2351 g_object_freeze_notify (G_OBJECT (label));
2352 g_object_notify (G_OBJECT (label), "selectable");
2353 g_object_notify (G_OBJECT (label), "cursor_position");
2354 g_object_notify (G_OBJECT (label), "selection_bound");
2355 g_object_thaw_notify (G_OBJECT (label));
2356 gtk_widget_queue_draw (GTK_WIDGET (label));
2361 * gtk_label_get_selectable:
2362 * @label: a #GtkLabel
2364 * Gets the value set by gtk_label_set_selectable().
2366 * Return value: %TRUE if the user can copy text from the label
2369 gtk_label_get_selectable (GtkLabel *label)
2371 g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
2373 return label->select_info != NULL;
2377 get_text_callback (GtkClipboard *clipboard,
2378 GtkSelectionData *selection_data,
2380 gpointer user_data_or_owner)
2384 label = GTK_LABEL (user_data_or_owner);
2386 if ((label->select_info->selection_anchor !=
2387 label->select_info->selection_end) &&
2393 start = MIN (label->select_info->selection_anchor,
2394 label->select_info->selection_end);
2395 end = MAX (label->select_info->selection_anchor,
2396 label->select_info->selection_end);
2398 len = strlen (label->text);
2406 gtk_selection_data_set_text (selection_data,
2407 label->text + start,
2413 clear_text_callback (GtkClipboard *clipboard,
2414 gpointer user_data_or_owner)
2418 label = GTK_LABEL (user_data_or_owner);
2420 if (label->select_info)
2422 label->select_info->selection_anchor = label->select_info->selection_end;
2424 gtk_widget_queue_draw (GTK_WIDGET (label));
2429 gtk_label_select_region_index (GtkLabel *label,
2433 static const GtkTargetEntry targets[] = {
2436 { "COMPOUND_TEXT", 0, 0 },
2437 { "UTF8_STRING", 0, 0 }
2440 g_return_if_fail (GTK_IS_LABEL (label));
2442 if (label->select_info)
2444 GtkClipboard *clipboard;
2446 if (label->select_info->selection_anchor == anchor_index &&
2447 label->select_info->selection_end == end_index)
2450 label->select_info->selection_anchor = anchor_index;
2451 label->select_info->selection_end = end_index;
2453 clipboard = gtk_clipboard_get (GDK_SELECTION_PRIMARY);
2455 if (anchor_index != end_index)
2457 gtk_clipboard_set_with_owner (clipboard,
2459 G_N_ELEMENTS (targets),
2461 clear_text_callback,
2466 if (gtk_clipboard_get_owner (clipboard) == G_OBJECT (label))
2467 gtk_clipboard_clear (clipboard);
2470 gtk_widget_queue_draw (GTK_WIDGET (label));
2472 g_object_freeze_notify (G_OBJECT (label));
2473 g_object_notify (G_OBJECT (label), "cursor_position");
2474 g_object_notify (G_OBJECT (label), "selection_bound");
2475 g_object_thaw_notify (G_OBJECT (label));
2480 * gtk_label_select_region:
2481 * @label: a #GtkLabel
2482 * @start_offset: start offset (in characters not bytes)
2483 * @end_offset: end offset (in characters not bytes)
2485 * Selects a range of characters in the label, if the label is selectable.
2486 * See gtk_label_set_selectable(). If the label is not selectable,
2487 * this function has no effect. If @start_offset or
2488 * @end_offset are -1, then the end of the label will be substituted.
2492 gtk_label_select_region (GtkLabel *label,
2496 g_return_if_fail (GTK_IS_LABEL (label));
2498 if (label->text && label->select_info)
2500 if (start_offset < 0)
2501 start_offset = g_utf8_strlen (label->text, -1);
2504 end_offset = g_utf8_strlen (label->text, -1);
2506 gtk_label_select_region_index (label,
2507 g_utf8_offset_to_pointer (label->text, start_offset) - label->text,
2508 g_utf8_offset_to_pointer (label->text, end_offset) - label->text);
2513 * gtk_label_get_selection_bounds:
2514 * @label: a #GtkLabel
2515 * @start: return location for start of selection, as a character offset
2516 * @end: return location for end of selection, as a character offset
2518 * Gets the selected range of characters in the label, returning %TRUE
2519 * if there's a selection.
2521 * Return value: %TRUE if selection is non-empty
2524 gtk_label_get_selection_bounds (GtkLabel *label,
2528 g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
2530 if (label->select_info == NULL)
2532 /* not a selectable label */
2542 gint start_index, end_index;
2543 gint start_offset, end_offset;
2546 start_index = MIN (label->select_info->selection_anchor,
2547 label->select_info->selection_end);
2548 end_index = MAX (label->select_info->selection_anchor,
2549 label->select_info->selection_end);
2551 len = strlen (label->text);
2553 if (end_index > len)
2556 if (start_index > len)
2559 start_offset = g_utf8_strlen (label->text, start_index);
2560 end_offset = g_utf8_strlen (label->text, end_index);
2562 if (start_offset > end_offset)
2564 gint tmp = start_offset;
2565 start_offset = end_offset;
2570 *start = start_offset;
2575 return start_offset != end_offset;
2581 * gtk_label_get_layout:
2582 * @label: a #GtkLabel
2584 * Gets the #PangoLayout used to display the label.
2585 * The layout is useful to e.g. convert text positions to
2586 * pixel positions, in combination with gtk_label_get_layout_offsets().
2587 * The returned layout is owned by the label so need not be
2588 * freed by the caller.
2590 * Return value: the #PangoLayout for this label
2593 gtk_label_get_layout (GtkLabel *label)
2595 g_return_val_if_fail (GTK_IS_LABEL (label), NULL);
2597 gtk_label_ensure_layout (label);
2599 return label->layout;
2603 * gtk_label_get_layout_offsets:
2604 * @label: a #GtkLabel
2605 * @x: location to store X offset of layout, or %NULL
2606 * @y: location to store Y offset of layout, or %NULL
2608 * Obtains the coordinates where the label will draw the #PangoLayout
2609 * representing the text in the label; useful to convert mouse events
2610 * into coordinates inside the #PangoLayout, e.g. to take some action
2611 * if some part of the label is clicked. Of course you will need to
2612 * create a #GtkEventBox to receive the events, and pack the label
2613 * inside it, since labels are a #GTK_NO_WINDOW widget. Remember
2614 * when using the #PangoLayout functions you need to convert to
2615 * and from pixels using PANGO_PIXELS() or #PANGO_SCALE.
2619 gtk_label_get_layout_offsets (GtkLabel *label,
2623 g_return_if_fail (GTK_IS_LABEL (label));
2625 get_layout_location (label, x, y);
2629 * gtk_label_set_use_markup:
2630 * @label: a #GtkLabel
2631 * @setting: %TRUE if the label's text should be parsed for markup.
2633 * Sets whether the text of the label contains markup in Pango's
2634 * text markup lango. See gtk_label_set_markup().
2637 gtk_label_set_use_markup (GtkLabel *label,
2640 g_return_if_fail (GTK_IS_LABEL (label));
2642 gtk_label_set_use_markup_internal (label, setting);
2643 gtk_label_recalculate (label);
2647 * gtk_label_get_use_markup:
2648 * @label: a #GtkLabel
2650 * Returns whether the label's text is interpreted as marked up with the
2651 * Pango text markup language. See gtk_label_set_use_markup ().
2653 * Return value: %TRUE if the label's text will be parsed for markup.
2656 gtk_label_get_use_markup (GtkLabel *label)
2658 g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
2660 return label->use_markup;
2664 * gtk_label_set_use_underline:
2665 * @label: a #GtkLabel
2666 * @setting: %TRUE if underlines in the text indicate mnemonics
2668 * If true, an underline in the text indicates the next character should be
2669 * used for the mnemonic accelerator key.
2672 gtk_label_set_use_underline (GtkLabel *label,
2675 g_return_if_fail (GTK_IS_LABEL (label));
2677 gtk_label_set_use_underline_internal (label, setting);
2678 gtk_label_recalculate (label);
2679 if (label->use_underline)
2680 gtk_label_setup_mnemonic (label, label->mnemonic_keyval);
2684 * gtk_label_get_use_underline:
2685 * @label: a #GtkLabel
2687 * Returns whether an embedded underline in the label indicates a
2688 * mnemonic. See gtk_label_set_use_underline ().
2690 * Return value: %TRUE whether an embedded underline in the label indicates
2691 * the mnemonic accelerator keys.
2694 gtk_label_get_use_underline (GtkLabel *label)
2696 g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
2698 return label->use_underline;
2702 gtk_label_focus (GtkWidget *widget,
2703 GtkDirectionType direction)
2705 /* We never want to be in the tab chain */
2709 /* Compute the X position for an offset that corresponds to the "more important
2710 * cursor position for that offset. We use this when trying to guess to which
2711 * end of the selection we should go to when the user hits the left or
2715 get_better_cursor (GtkLabel *label,
2720 GtkTextDirection keymap_direction =
2721 (gdk_keymap_get_direction (gdk_keymap_get_default ()) == PANGO_DIRECTION_LTR) ?
2722 GTK_TEXT_DIR_LTR : GTK_TEXT_DIR_RTL;
2723 GtkTextDirection widget_direction = gtk_widget_get_direction (GTK_WIDGET (label));
2724 gboolean split_cursor;
2725 PangoRectangle strong_pos, weak_pos;
2727 g_object_get (gtk_widget_get_settings (GTK_WIDGET (label)),
2728 "gtk-split-cursor", &split_cursor,
2731 gtk_label_ensure_layout (label);
2733 pango_layout_get_cursor_pos (label->layout, index,
2734 &strong_pos, &weak_pos);
2738 *x = strong_pos.x / PANGO_SCALE;
2739 *y = strong_pos.y / PANGO_SCALE;
2743 if (keymap_direction == widget_direction)
2745 *x = strong_pos.x / PANGO_SCALE;
2746 *y = strong_pos.y / PANGO_SCALE;
2750 *x = weak_pos.x / PANGO_SCALE;
2751 *y = weak_pos.y / PANGO_SCALE;
2758 gtk_label_move_logically (GtkLabel *label,
2762 gint offset = g_utf8_pointer_to_offset (label->label,
2763 label->label + start);
2767 PangoLogAttr *log_attrs;
2771 gtk_label_ensure_layout (label);
2773 length = g_utf8_strlen (label->label, -1);
2775 pango_layout_get_log_attrs (label->layout, &log_attrs, &n_attrs);
2777 while (count > 0 && offset < length)
2781 while (offset < length && !log_attrs[offset].is_cursor_position);
2785 while (count < 0 && offset > 0)
2789 while (offset > 0 && !log_attrs[offset].is_cursor_position);
2797 return g_utf8_offset_to_pointer (label->label, offset) - label->label;
2801 gtk_label_move_visually (GtkLabel *label,
2811 int new_index, new_trailing;
2812 gboolean split_cursor;
2815 gtk_label_ensure_layout (label);
2817 g_object_get (gtk_widget_get_settings (GTK_WIDGET (label)),
2818 "gtk-split-cursor", &split_cursor,
2825 GtkTextDirection keymap_direction =
2826 (gdk_keymap_get_direction (gdk_keymap_get_default ()) == PANGO_DIRECTION_LTR) ?
2827 GTK_TEXT_DIR_LTR : GTK_TEXT_DIR_RTL;
2829 strong = keymap_direction == gtk_widget_get_direction (GTK_WIDGET (label));
2834 pango_layout_move_cursor_visually (label->layout, strong, index, 0, 1, &new_index, &new_trailing);
2839 pango_layout_move_cursor_visually (label->layout, strong, index, 0, -1, &new_index, &new_trailing);
2843 if (new_index < 0 || new_index == G_MAXINT)
2848 while (new_trailing--)
2849 index = g_utf8_next_char (label->label + new_index) - label->label;
2856 gtk_label_move_forward_word (GtkLabel *label,
2859 gint new_pos = g_utf8_pointer_to_offset (label->label,
2860 label->label + start);
2863 length = g_utf8_strlen (label->label, -1);
2864 if (new_pos < length)
2866 PangoLogAttr *log_attrs;
2869 gtk_label_ensure_layout (label);
2871 pango_layout_get_log_attrs (label->layout, &log_attrs, &n_attrs);
2873 /* Find the next word end */
2875 while (new_pos < n_attrs && !log_attrs[new_pos].is_word_end)
2881 return g_utf8_offset_to_pointer (label->label, new_pos) - label->label;
2886 gtk_label_move_backward_word (GtkLabel *label,
2889 gint new_pos = g_utf8_pointer_to_offset (label->label,
2890 label->label + start);
2893 length = g_utf8_strlen (label->label, -1);
2897 PangoLogAttr *log_attrs;
2900 gtk_label_ensure_layout (label);
2902 pango_layout_get_log_attrs (label->layout, &log_attrs, &n_attrs);
2906 /* Find the previous word beginning */
2907 while (new_pos > 0 && !log_attrs[new_pos].is_word_start)
2913 return g_utf8_offset_to_pointer (label->label, new_pos) - label->label;
2917 gtk_label_move_cursor (GtkLabel *label,
2918 GtkMovementStep step,
2920 gboolean extend_selection)
2924 if (label->select_info == NULL)
2927 new_pos = label->select_info->selection_end;
2929 if (label->select_info->selection_end != label->select_info->selection_anchor &&
2932 /* If we have a current selection and aren't extending it, move to the
2933 * start/or end of the selection as appropriate
2937 case GTK_MOVEMENT_VISUAL_POSITIONS:
2940 gint anchor_x, anchor_y;
2941 gboolean end_is_left;
2943 get_better_cursor (label, label->select_info->selection_end, &end_x, &end_y);
2944 get_better_cursor (label, label->select_info->selection_anchor, &anchor_x, &anchor_y);
2946 end_is_left = (end_y < anchor_y) || (end_y == anchor_y && end_x < anchor_x);
2949 new_pos = end_is_left ? label->select_info->selection_end : label->select_info->selection_anchor;
2951 new_pos = !end_is_left ? label->select_info->selection_end : label->select_info->selection_anchor;
2955 case GTK_MOVEMENT_LOGICAL_POSITIONS:
2956 case GTK_MOVEMENT_WORDS:
2958 new_pos = MIN (label->select_info->selection_end, label->select_info->selection_anchor);
2960 new_pos = MAX (label->select_info->selection_end, label->select_info->selection_anchor);
2962 case GTK_MOVEMENT_DISPLAY_LINE_ENDS:
2963 case GTK_MOVEMENT_PARAGRAPH_ENDS:
2964 case GTK_MOVEMENT_BUFFER_ENDS:
2965 /* FIXME: Can do better here */
2966 new_pos = count < 0 ? 0 : strlen (label->label);
2968 case GTK_MOVEMENT_DISPLAY_LINES:
2969 case GTK_MOVEMENT_PARAGRAPHS:
2970 case GTK_MOVEMENT_PAGES:
2978 case GTK_MOVEMENT_LOGICAL_POSITIONS:
2979 new_pos = gtk_label_move_logically (label, new_pos, count);
2981 case GTK_MOVEMENT_VISUAL_POSITIONS:
2982 new_pos = gtk_label_move_visually (label, new_pos, count);
2984 case GTK_MOVEMENT_WORDS:
2987 new_pos = gtk_label_move_forward_word (label, new_pos);
2992 new_pos = gtk_label_move_backward_word (label, new_pos);
2996 case GTK_MOVEMENT_DISPLAY_LINE_ENDS:
2997 case GTK_MOVEMENT_PARAGRAPH_ENDS:
2998 case GTK_MOVEMENT_BUFFER_ENDS:
2999 /* FIXME: Can do better here */
3000 new_pos = count < 0 ? 0 : strlen (label->label);
3002 case GTK_MOVEMENT_DISPLAY_LINES:
3003 case GTK_MOVEMENT_PARAGRAPHS:
3004 case GTK_MOVEMENT_PAGES:
3009 if (extend_selection)
3010 gtk_label_select_region_index (label,
3011 label->select_info->selection_anchor,
3014 gtk_label_select_region_index (label, new_pos, new_pos);
3018 gtk_label_copy_clipboard (GtkLabel *label)
3020 if (label->text && label->select_info)
3025 start = MIN (label->select_info->selection_anchor,
3026 label->select_info->selection_end);
3027 end = MAX (label->select_info->selection_anchor,
3028 label->select_info->selection_end);
3030 len = strlen (label->text);
3039 gtk_clipboard_set_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
3040 label->text + start, end - start);
3045 gtk_label_select_all (GtkLabel *label)
3047 gtk_label_select_region_index (label, 0, strlen (label->label));
3050 /* Quick hack of a popup menu
3053 activate_cb (GtkWidget *menuitem,
3056 const gchar *signal = gtk_object_get_data (GTK_OBJECT (menuitem), "gtk-signal");
3057 gtk_signal_emit_by_name (GTK_OBJECT (label), signal);
3061 append_action_signal (GtkLabel *label,
3063 const gchar *stock_id,
3064 const gchar *signal,
3067 GtkWidget *menuitem = gtk_image_menu_item_new_from_stock (stock_id, NULL);
3069 gtk_object_set_data (GTK_OBJECT (menuitem), "gtk-signal", (char *)signal);
3070 gtk_signal_connect (GTK_OBJECT (menuitem), "activate",
3071 GTK_SIGNAL_FUNC (activate_cb), label);
3073 gtk_widget_set_sensitive (menuitem, sensitive);
3075 gtk_widget_show (menuitem);
3076 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
3080 popup_menu_detach (GtkWidget *attach_widget,
3084 label = GTK_LABEL (attach_widget);
3086 if (label->select_info)
3087 label->select_info->popup_menu = NULL;
3091 popup_position_func (GtkMenu *menu,
3101 label = GTK_LABEL (user_data);
3102 widget = GTK_WIDGET (label);
3104 if (label->select_info == NULL)
3107 g_return_if_fail (GTK_WIDGET_REALIZED (label));
3109 gdk_window_get_origin (widget->window, x, y);
3111 gtk_widget_size_request (label->select_info->popup_menu, &req);
3113 *x += widget->allocation.width / 2;
3114 *y += widget->allocation.height;
3116 *x = CLAMP (*x, 0, MAX (0, gdk_screen_width () - req.width));
3117 *y = CLAMP (*y, 0, MAX (0, gdk_screen_height () - req.height));
3122 gtk_label_do_popup (GtkLabel *label,
3123 GdkEventButton *event)
3125 GtkWidget *menuitem;
3126 gboolean have_selection;
3128 if (label->select_info == NULL)
3131 if (label->select_info->popup_menu)
3132 gtk_widget_destroy (label->select_info->popup_menu);
3134 label->select_info->popup_menu = gtk_menu_new ();
3136 gtk_menu_attach_to_widget (GTK_MENU (label->select_info->popup_menu),
3141 label->select_info->selection_anchor != label->select_info->selection_end;
3144 append_action_signal (label, label->select_info->popup_menu, GTK_STOCK_CUT, "cut_clipboard",
3146 append_action_signal (label, label->select_info->popup_menu, GTK_STOCK_COPY, "copy_clipboard",
3148 append_action_signal (label, label->select_info->popup_menu, GTK_STOCK_PASTE, "paste_clipboard",
3151 menuitem = gtk_menu_item_new_with_label (_("Select All"));
3152 gtk_signal_connect_object (GTK_OBJECT (menuitem), "activate",
3153 GTK_SIGNAL_FUNC (gtk_label_select_all), label);
3154 gtk_widget_show (menuitem);
3155 gtk_menu_shell_append (GTK_MENU_SHELL (label->select_info->popup_menu), menuitem);
3157 menuitem = gtk_separator_menu_item_new ();
3158 gtk_widget_show (menuitem);
3159 gtk_menu_shell_append (GTK_MENU_SHELL (label->select_info->popup_menu), menuitem);
3161 menuitem = gtk_menu_item_new_with_label (_("Input Methods"));
3162 gtk_widget_show (menuitem);
3163 gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), gtk_menu_new ());
3164 gtk_widget_set_sensitive (menuitem, FALSE);
3165 gtk_menu_shell_append (GTK_MENU_SHELL (label->select_info->popup_menu), menuitem);
3167 gtk_signal_emit (GTK_OBJECT (label),
3168 signals[POPULATE_POPUP],
3169 label->select_info->popup_menu);
3172 gtk_menu_popup (GTK_MENU (label->select_info->popup_menu), NULL, NULL,
3174 event->button, event->time);
3176 gtk_menu_popup (GTK_MENU (label->select_info->popup_menu), NULL, NULL,
3177 popup_position_func, label,
3178 0, gtk_get_current_event_time ());