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/.
32 #include "gtkmarshalers.h"
33 #include "gtkwindow.h"
34 #include "gdk/gdkkeysyms.h"
35 #include "gtkclipboard.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"
44 #include "gtkprivate.h"
47 #define GTK_LABEL_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_LABEL, GtkLabelPrivate))
53 guint single_line_mode : 1;
54 guint have_transform : 1;
59 struct _GtkLabelSelectionInfo
62 gint selection_anchor;
64 GtkWidget *popup_menu;
95 PROP_SINGLE_LINE_MODE,
100 static guint signals[LAST_SIGNAL] = { 0 };
102 static void gtk_label_class_init (GtkLabelClass *klass);
103 static void gtk_label_init (GtkLabel *label);
104 static void gtk_label_set_property (GObject *object,
108 static void gtk_label_get_property (GObject *object,
112 static void gtk_label_destroy (GtkObject *object);
113 static void gtk_label_finalize (GObject *object);
114 static void gtk_label_size_request (GtkWidget *widget,
115 GtkRequisition *requisition);
116 static void gtk_label_size_allocate (GtkWidget *widget,
117 GtkAllocation *allocation);
118 static void gtk_label_state_changed (GtkWidget *widget,
120 static void gtk_label_style_set (GtkWidget *widget,
121 GtkStyle *previous_style);
122 static void gtk_label_direction_changed (GtkWidget *widget,
123 GtkTextDirection previous_dir);
124 static gint gtk_label_expose (GtkWidget *widget,
125 GdkEventExpose *event);
127 static void gtk_label_realize (GtkWidget *widget);
128 static void gtk_label_unrealize (GtkWidget *widget);
129 static void gtk_label_map (GtkWidget *widget);
130 static void gtk_label_unmap (GtkWidget *widget);
132 static gboolean gtk_label_button_press (GtkWidget *widget,
133 GdkEventButton *event);
134 static gboolean gtk_label_button_release (GtkWidget *widget,
135 GdkEventButton *event);
136 static gboolean gtk_label_motion (GtkWidget *widget,
137 GdkEventMotion *event);
140 static void gtk_label_set_text_internal (GtkLabel *label,
142 static void gtk_label_set_label_internal (GtkLabel *label,
144 static void gtk_label_set_use_markup_internal (GtkLabel *label,
146 static void gtk_label_set_use_underline_internal (GtkLabel *label,
148 static void gtk_label_set_attributes_internal (GtkLabel *label,
149 PangoAttrList *attrs);
150 static void gtk_label_set_uline_text_internal (GtkLabel *label,
152 static void gtk_label_set_pattern_internal (GtkLabel *label,
153 const gchar *pattern);
154 static void set_markup (GtkLabel *label,
156 gboolean with_uline);
157 static void gtk_label_recalculate (GtkLabel *label);
158 static void gtk_label_hierarchy_changed (GtkWidget *widget,
159 GtkWidget *old_toplevel);
160 static void gtk_label_screen_changed (GtkWidget *widget,
161 GdkScreen *old_screen);
163 static void gtk_label_create_window (GtkLabel *label);
164 static void gtk_label_destroy_window (GtkLabel *label);
165 static void gtk_label_clear_layout (GtkLabel *label);
166 static void gtk_label_ensure_layout (GtkLabel *label);
167 static void gtk_label_select_region_index (GtkLabel *label,
171 static gboolean gtk_label_mnemonic_activate (GtkWidget *widget,
172 gboolean group_cycling);
173 static void gtk_label_setup_mnemonic (GtkLabel *label,
175 static void gtk_label_drag_data_get (GtkWidget *widget,
176 GdkDragContext *context,
177 GtkSelectionData *selection_data,
182 /* For selectable lables: */
183 static void gtk_label_move_cursor (GtkLabel *label,
184 GtkMovementStep step,
186 gboolean extend_selection);
187 static void gtk_label_copy_clipboard (GtkLabel *label);
188 static void gtk_label_select_all (GtkLabel *label);
189 static void gtk_label_do_popup (GtkLabel *label,
190 GdkEventButton *event);
192 static gint gtk_label_move_forward_word (GtkLabel *label,
194 static gint gtk_label_move_backward_word (GtkLabel *label,
197 static GtkMiscClass *parent_class = NULL;
201 gtk_label_get_type (void)
203 static GType label_type = 0;
207 static const GTypeInfo label_info =
209 sizeof (GtkLabelClass),
210 NULL, /* base_init */
211 NULL, /* base_finalize */
212 (GClassInitFunc) gtk_label_class_init,
213 NULL, /* class_finalize */
214 NULL, /* class_data */
216 32, /* n_preallocs */
217 (GInstanceInitFunc) gtk_label_init,
220 label_type = g_type_register_static (GTK_TYPE_MISC, "GtkLabel",
228 add_move_binding (GtkBindingSet *binding_set,
231 GtkMovementStep step,
234 g_return_if_fail ((modmask & GDK_SHIFT_MASK) == 0);
236 gtk_binding_entry_add_signal (binding_set, keyval, modmask,
240 G_TYPE_BOOLEAN, FALSE);
242 /* Selection-extending version */
243 gtk_binding_entry_add_signal (binding_set, keyval, modmask | GDK_SHIFT_MASK,
247 G_TYPE_BOOLEAN, TRUE);
251 gtk_label_class_init (GtkLabelClass *class)
253 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
254 GtkObjectClass *object_class = GTK_OBJECT_CLASS (class);
255 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
256 GtkBindingSet *binding_set;
258 parent_class = g_type_class_peek_parent (class);
260 gobject_class->set_property = gtk_label_set_property;
261 gobject_class->get_property = gtk_label_get_property;
262 gobject_class->finalize = gtk_label_finalize;
264 object_class->destroy = gtk_label_destroy;
266 widget_class->size_request = gtk_label_size_request;
267 widget_class->size_allocate = gtk_label_size_allocate;
268 widget_class->state_changed = gtk_label_state_changed;
269 widget_class->style_set = gtk_label_style_set;
270 widget_class->direction_changed = gtk_label_direction_changed;
271 widget_class->expose_event = gtk_label_expose;
272 widget_class->realize = gtk_label_realize;
273 widget_class->unrealize = gtk_label_unrealize;
274 widget_class->map = gtk_label_map;
275 widget_class->unmap = gtk_label_unmap;
276 widget_class->button_press_event = gtk_label_button_press;
277 widget_class->button_release_event = gtk_label_button_release;
278 widget_class->motion_notify_event = gtk_label_motion;
279 widget_class->hierarchy_changed = gtk_label_hierarchy_changed;
280 widget_class->screen_changed = gtk_label_screen_changed;
281 widget_class->mnemonic_activate = gtk_label_mnemonic_activate;
282 widget_class->drag_data_get = gtk_label_drag_data_get;
284 class->move_cursor = gtk_label_move_cursor;
285 class->copy_clipboard = gtk_label_copy_clipboard;
287 signals[MOVE_CURSOR] =
288 g_signal_new ("move_cursor",
289 G_OBJECT_CLASS_TYPE (gobject_class),
290 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
291 G_STRUCT_OFFSET (GtkLabelClass, move_cursor),
293 _gtk_marshal_VOID__ENUM_INT_BOOLEAN,
295 GTK_TYPE_MOVEMENT_STEP,
299 signals[COPY_CLIPBOARD] =
300 g_signal_new ("copy_clipboard",
301 G_OBJECT_CLASS_TYPE (gobject_class),
302 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
303 G_STRUCT_OFFSET (GtkLabelClass, copy_clipboard),
305 _gtk_marshal_VOID__VOID,
308 signals[POPULATE_POPUP] =
309 g_signal_new ("populate_popup",
310 G_OBJECT_CLASS_TYPE (gobject_class),
312 G_STRUCT_OFFSET (GtkLabelClass, populate_popup),
314 _gtk_marshal_VOID__OBJECT,
318 g_object_class_install_property (gobject_class,
320 g_param_spec_string ("label",
322 P_("The text of the label"),
324 GTK_PARAM_READWRITE));
325 g_object_class_install_property (gobject_class,
327 g_param_spec_boxed ("attributes",
329 P_("A list of style attributes to apply to the text of the label"),
330 PANGO_TYPE_ATTR_LIST,
331 GTK_PARAM_READWRITE));
332 g_object_class_install_property (gobject_class,
334 g_param_spec_boolean ("use-markup",
336 P_("The text of the label includes XML markup. See pango_parse_markup()"),
338 GTK_PARAM_READWRITE));
339 g_object_class_install_property (gobject_class,
341 g_param_spec_boolean ("use-underline",
343 P_("If set, an underline in the text indicates the next character should be used for the mnemonic accelerator key"),
345 GTK_PARAM_READWRITE));
347 g_object_class_install_property (gobject_class,
349 g_param_spec_enum ("justify",
351 P_("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"),
352 GTK_TYPE_JUSTIFICATION,
354 GTK_PARAM_READWRITE));
356 g_object_class_install_property (gobject_class,
358 g_param_spec_string ("pattern",
360 P_("A string with _ characters in positions correspond to characters in the text to underline"),
362 GTK_PARAM_WRITABLE));
364 g_object_class_install_property (gobject_class,
366 g_param_spec_boolean ("wrap",
368 P_("If set, wrap lines if the text becomes too wide"),
370 GTK_PARAM_READWRITE));
371 g_object_class_install_property (gobject_class,
373 g_param_spec_boolean ("selectable",
375 P_("Whether the label text can be selected with the mouse"),
377 GTK_PARAM_READWRITE));
378 g_object_class_install_property (gobject_class,
379 PROP_MNEMONIC_KEYVAL,
380 g_param_spec_uint ("mnemonic-keyval",
382 P_("The mnemonic accelerator key for this label"),
386 GTK_PARAM_READABLE));
387 g_object_class_install_property (gobject_class,
388 PROP_MNEMONIC_WIDGET,
389 g_param_spec_object ("mnemonic-widget",
390 P_("Mnemonic widget"),
391 P_("The widget to be activated when the label's mnemonic "
394 GTK_PARAM_READWRITE));
396 g_object_class_install_property (gobject_class,
397 PROP_CURSOR_POSITION,
398 g_param_spec_int ("cursor-position",
399 P_("Cursor Position"),
400 P_("The current position of the insertion cursor in chars"),
404 GTK_PARAM_READABLE));
406 g_object_class_install_property (gobject_class,
407 PROP_SELECTION_BOUND,
408 g_param_spec_int ("selection-bound",
409 P_("Selection Bound"),
410 P_("The position of the opposite end of the selection from the cursor in chars"),
414 GTK_PARAM_READABLE));
417 * GtkLabel:ellipsize:
419 * The preferred place to ellipsize the string, if the label does not have
420 * enough room to display the entire string, specified as a #PangoEllisizeMode.
422 * Note that setting this property to a value other than %PANGO_ELLIPSIZE_NONE
423 * has the side-effect that the label requests only enough space to display the
424 * ellipsis "...". In particular, this means that ellipsizing labels don't
425 * work well in notebook tabs, unless the tab's ::tab-expand property is set
426 * to %TRUE. Other means to set a label's width are
427 * gtk_widget_set_size_request() and gtk_label_set_width_chars().
431 g_object_class_install_property (gobject_class,
433 g_param_spec_enum ("ellipsize",
435 P_("The preferred place to ellipsize the string, if the label does not have enough room to display the entire string, if at all"),
436 PANGO_TYPE_ELLIPSIZE_MODE,
437 PANGO_ELLIPSIZE_NONE,
438 GTK_PARAM_READWRITE));
441 * GtkLabel:width-chars:
443 * The desired width of the label, in characters. If this property is set to
444 * -1, the width will be calculated automatically, otherwise the label will
445 * request either 3 characters or the property value, whichever is greater.
446 * If the width-chars property is set to a positive value, then the
447 * max-width-chars property is ignored.
451 g_object_class_install_property (gobject_class,
453 g_param_spec_int ("width-chars",
454 P_("Width In Characters"),
455 P_("The desired width of the label, in characters"),
459 GTK_PARAM_READWRITE));
462 * GtkLabel:single-line-mode:
464 * Whether the label is in single line mode. In single line mode,
465 * the height of the label does not depend on the actual text, it
466 * is always set to ascent + descent of the font. This can be an
467 * advantage in situations where resizing the label because of text
468 * changes would be distracting, e.g. in a statusbar.
472 g_object_class_install_property (gobject_class,
473 PROP_SINGLE_LINE_MODE,
474 g_param_spec_boolean ("single-line-mode",
475 P_("Single Line Mode"),
476 P_("Whether the label is in single line mode"),
478 GTK_PARAM_READWRITE));
483 * The angle that the baseline of the label makes with the horizontal,
484 * in degrees, measured counterclockwise. An angle of 90 reads from
485 * from bottom to top, an angle of 270, from top to bottom. Ignored
486 * if the label is selectable, wrapped, or ellipsized.
490 g_object_class_install_property (gobject_class,
492 g_param_spec_double ("angle",
494 P_("Angle at which the label is rotated"),
498 GTK_PARAM_READWRITE));
501 * GtkLabel:max-width-chars:
503 * The desired maximum width of the label, in characters. If this property
504 * is set to -1, the width will be calculated automatically, otherwise the
505 * label will request space for no more than the requested number of
506 * characters. If the width-chars property is set to a positive value,
507 * then the max-width-chars property is ignored.
511 g_object_class_install_property (gobject_class,
512 PROP_MAX_WIDTH_CHARS,
513 g_param_spec_int ("max-width-chars",
514 P_("Maximum Width In Characters"),
515 P_("The desired maximum width of the label, in characters"),
519 GTK_PARAM_READWRITE));
524 binding_set = gtk_binding_set_by_class (class);
526 /* Moving the insertion point */
527 add_move_binding (binding_set, GDK_Right, 0,
528 GTK_MOVEMENT_VISUAL_POSITIONS, 1);
530 add_move_binding (binding_set, GDK_Left, 0,
531 GTK_MOVEMENT_VISUAL_POSITIONS, -1);
533 add_move_binding (binding_set, GDK_KP_Right, 0,
534 GTK_MOVEMENT_VISUAL_POSITIONS, 1);
536 add_move_binding (binding_set, GDK_KP_Left, 0,
537 GTK_MOVEMENT_VISUAL_POSITIONS, -1);
539 add_move_binding (binding_set, GDK_f, GDK_CONTROL_MASK,
540 GTK_MOVEMENT_LOGICAL_POSITIONS, 1);
542 add_move_binding (binding_set, GDK_b, GDK_CONTROL_MASK,
543 GTK_MOVEMENT_LOGICAL_POSITIONS, -1);
545 add_move_binding (binding_set, GDK_Right, GDK_CONTROL_MASK,
546 GTK_MOVEMENT_WORDS, 1);
548 add_move_binding (binding_set, GDK_Left, GDK_CONTROL_MASK,
549 GTK_MOVEMENT_WORDS, -1);
551 add_move_binding (binding_set, GDK_KP_Right, GDK_CONTROL_MASK,
552 GTK_MOVEMENT_WORDS, 1);
554 add_move_binding (binding_set, GDK_KP_Left, GDK_CONTROL_MASK,
555 GTK_MOVEMENT_WORDS, -1);
557 add_move_binding (binding_set, GDK_a, GDK_CONTROL_MASK,
558 GTK_MOVEMENT_PARAGRAPH_ENDS, -1);
560 add_move_binding (binding_set, GDK_e, GDK_CONTROL_MASK,
561 GTK_MOVEMENT_PARAGRAPH_ENDS, 1);
563 add_move_binding (binding_set, GDK_f, GDK_MOD1_MASK,
564 GTK_MOVEMENT_WORDS, 1);
566 add_move_binding (binding_set, GDK_b, GDK_MOD1_MASK,
567 GTK_MOVEMENT_WORDS, -1);
569 add_move_binding (binding_set, GDK_Home, 0,
570 GTK_MOVEMENT_DISPLAY_LINE_ENDS, -1);
572 add_move_binding (binding_set, GDK_End, 0,
573 GTK_MOVEMENT_DISPLAY_LINE_ENDS, 1);
575 add_move_binding (binding_set, GDK_KP_Home, 0,
576 GTK_MOVEMENT_DISPLAY_LINE_ENDS, -1);
578 add_move_binding (binding_set, GDK_KP_End, 0,
579 GTK_MOVEMENT_DISPLAY_LINE_ENDS, 1);
581 add_move_binding (binding_set, GDK_Home, GDK_CONTROL_MASK,
582 GTK_MOVEMENT_BUFFER_ENDS, -1);
584 add_move_binding (binding_set, GDK_End, GDK_CONTROL_MASK,
585 GTK_MOVEMENT_BUFFER_ENDS, 1);
587 add_move_binding (binding_set, GDK_KP_Home, GDK_CONTROL_MASK,
588 GTK_MOVEMENT_BUFFER_ENDS, -1);
590 add_move_binding (binding_set, GDK_KP_End, GDK_CONTROL_MASK,
591 GTK_MOVEMENT_BUFFER_ENDS, 1);
594 gtk_binding_entry_add_signal (binding_set, GDK_c, GDK_CONTROL_MASK,
595 "copy_clipboard", 0);
597 g_type_class_add_private (class, sizeof (GtkLabelPrivate));
601 gtk_label_set_property (GObject *object,
608 label = GTK_LABEL (object);
613 gtk_label_set_label (label, g_value_get_string (value));
615 case PROP_ATTRIBUTES:
616 gtk_label_set_attributes (label, g_value_get_boxed (value));
618 case PROP_USE_MARKUP:
619 gtk_label_set_use_markup (label, g_value_get_boolean (value));
621 case PROP_USE_UNDERLINE:
622 gtk_label_set_use_underline (label, g_value_get_boolean (value));
625 gtk_label_set_justify (label, g_value_get_enum (value));
628 gtk_label_set_pattern (label, g_value_get_string (value));
631 gtk_label_set_line_wrap (label, g_value_get_boolean (value));
633 case PROP_SELECTABLE:
634 gtk_label_set_selectable (label, g_value_get_boolean (value));
636 case PROP_MNEMONIC_WIDGET:
637 gtk_label_set_mnemonic_widget (label, (GtkWidget*) g_value_get_object (value));
640 gtk_label_set_ellipsize (label, g_value_get_enum (value));
642 case PROP_WIDTH_CHARS:
643 gtk_label_set_width_chars (label, g_value_get_int (value));
645 case PROP_SINGLE_LINE_MODE:
646 gtk_label_set_single_line_mode (label, g_value_get_boolean (value));
649 gtk_label_set_angle (label, g_value_get_double (value));
651 case PROP_MAX_WIDTH_CHARS:
652 gtk_label_set_max_width_chars (label, g_value_get_int (value));
655 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
661 gtk_label_get_property (GObject *object,
668 label = GTK_LABEL (object);
673 g_value_set_string (value, label->label);
675 case PROP_ATTRIBUTES:
676 g_value_set_boxed (value, label->attrs);
678 case PROP_USE_MARKUP:
679 g_value_set_boolean (value, label->use_markup);
681 case PROP_USE_UNDERLINE:
682 g_value_set_boolean (value, label->use_underline);
685 g_value_set_enum (value, label->jtype);
688 g_value_set_boolean (value, label->wrap);
690 case PROP_SELECTABLE:
691 g_value_set_boolean (value, gtk_label_get_selectable (label));
693 case PROP_MNEMONIC_KEYVAL:
694 g_value_set_uint (value, label->mnemonic_keyval);
696 case PROP_MNEMONIC_WIDGET:
697 g_value_set_object (value, (GObject*) label->mnemonic_widget);
699 case PROP_CURSOR_POSITION:
700 if (label->select_info)
702 gint offset = g_utf8_pointer_to_offset (label->text,
703 label->text + label->select_info->selection_end);
704 g_value_set_int (value, offset);
707 g_value_set_int (value, 0);
709 case PROP_SELECTION_BOUND:
710 if (label->select_info)
712 gint offset = g_utf8_pointer_to_offset (label->text,
713 label->text + label->select_info->selection_anchor);
714 g_value_set_int (value, offset);
717 g_value_set_int (value, 0);
720 g_value_set_enum (value, label->ellipsize);
722 case PROP_WIDTH_CHARS:
723 g_value_set_int (value, gtk_label_get_width_chars (label));
725 case PROP_SINGLE_LINE_MODE:
726 g_value_set_boolean (value, gtk_label_get_single_line_mode (label));
729 g_value_set_double (value, gtk_label_get_angle (label));
731 case PROP_MAX_WIDTH_CHARS:
732 g_value_set_int (value, gtk_label_get_max_width_chars (label));
736 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
742 gtk_label_init (GtkLabel *label)
744 GtkLabelPrivate *priv;
746 GTK_WIDGET_SET_FLAGS (label, GTK_NO_WINDOW);
748 priv = GTK_LABEL_GET_PRIVATE (label);
749 priv->width_chars = -1;
751 priv->max_width_chars = -1;
754 label->jtype = GTK_JUSTIFY_LEFT;
756 label->ellipsize = PANGO_ELLIPSIZE_NONE;
758 label->use_underline = FALSE;
759 label->use_markup = FALSE;
761 label->mnemonic_keyval = GDK_VoidSymbol;
762 label->layout = NULL;
766 label->mnemonic_widget = NULL;
767 label->mnemonic_window = NULL;
769 gtk_label_set_text (label, "");
774 * @str: The text of the label
776 * Creates a new label with the given text inside it. You can
777 * pass %NULL to get an empty label widget.
779 * Return value: the new #GtkLabel
782 gtk_label_new (const gchar *str)
786 label = g_object_new (GTK_TYPE_LABEL, NULL);
789 gtk_label_set_text (label, str);
791 return GTK_WIDGET (label);
795 * gtk_label_new_with_mnemonic:
796 * @str: The text of the label, with an underscore in front of the
799 * Creates a new #GtkLabel, containing the text in @str.
801 * If characters in @str are preceded by an underscore, they are
802 * underlined. If you need a literal underscore character in a label, use
803 * '__' (two underscores). The first underlined character represents a
804 * keyboard accelerator called a mnemonic. The mnemonic key can be used
805 * to activate another widget, chosen automatically, or explicitly using
806 * gtk_label_set_mnemonic_widget().
808 * If gtk_label_set_mnemonic_widget()
809 * is not called, then the first activatable ancestor of the #GtkLabel
810 * will be chosen as the mnemonic widget. For instance, if the
811 * label is inside a button or menu item, the button or menu item will
812 * automatically become the mnemonic widget and be activated by
815 * Return value: the new #GtkLabel
818 gtk_label_new_with_mnemonic (const gchar *str)
822 label = g_object_new (GTK_TYPE_LABEL, NULL);
825 gtk_label_set_text_with_mnemonic (label, str);
827 return GTK_WIDGET (label);
831 gtk_label_mnemonic_activate (GtkWidget *widget,
832 gboolean group_cycling)
836 if (GTK_LABEL (widget)->mnemonic_widget)
837 return gtk_widget_mnemonic_activate (GTK_LABEL (widget)->mnemonic_widget, group_cycling);
839 /* Try to find the widget to activate by traversing the
842 parent = widget->parent;
844 if (parent && GTK_IS_NOTEBOOK (parent))
849 if (GTK_WIDGET_CAN_FOCUS (parent) ||
850 (!group_cycling && GTK_WIDGET_GET_CLASS (parent)->activate_signal) ||
851 (parent->parent && GTK_IS_NOTEBOOK (parent->parent)) ||
852 (GTK_IS_MENU_ITEM (parent)))
853 return gtk_widget_mnemonic_activate (parent, group_cycling);
854 parent = parent->parent;
857 /* barf if there was nothing to activate */
858 g_warning ("Couldn't find a target for a mnemonic activation.");
859 gdk_display_beep (gtk_widget_get_display (widget));
865 gtk_label_setup_mnemonic (GtkLabel *label,
868 GtkWidget *widget = GTK_WIDGET (label);
870 GtkWidget *mnemonic_menu;
872 mnemonic_menu = g_object_get_data (G_OBJECT (label), "gtk-mnemonic-menu");
874 if (last_key != GDK_VoidSymbol)
876 if (label->mnemonic_window)
878 gtk_window_remove_mnemonic (label->mnemonic_window,
881 label->mnemonic_window = NULL;
885 _gtk_menu_shell_remove_mnemonic (GTK_MENU_SHELL (mnemonic_menu),
888 mnemonic_menu = NULL;
892 if (label->mnemonic_keyval == GDK_VoidSymbol)
895 toplevel = gtk_widget_get_toplevel (widget);
896 if (GTK_WIDGET_TOPLEVEL (toplevel))
898 GtkWidget *menu_shell;
900 menu_shell = gtk_widget_get_ancestor (widget,
901 GTK_TYPE_MENU_SHELL);
905 _gtk_menu_shell_add_mnemonic (GTK_MENU_SHELL (menu_shell),
906 label->mnemonic_keyval,
908 mnemonic_menu = menu_shell;
911 if (!(menu_shell && GTK_IS_MENU (menu_shell)))
913 gtk_window_add_mnemonic (GTK_WINDOW (toplevel),
914 label->mnemonic_keyval,
916 label->mnemonic_window = GTK_WINDOW (toplevel);
921 g_object_set_data (G_OBJECT (label), "gtk-mnemonic-menu", mnemonic_menu);
925 gtk_label_hierarchy_changed (GtkWidget *widget,
926 GtkWidget *old_toplevel)
928 GtkLabel *label = GTK_LABEL (widget);
930 gtk_label_setup_mnemonic (label, label->mnemonic_keyval);
934 gtk_label_screen_changed (GtkWidget *widget,
935 GdkScreen *old_screen)
937 gtk_label_clear_layout (GTK_LABEL (widget));
941 label_mnemonic_widget_weak_notify (gpointer data,
942 GObject *where_the_object_was)
944 GtkLabel *label = data;
946 label->mnemonic_widget = NULL;
947 g_object_notify (G_OBJECT (label), "mnemonic_widget");
951 * gtk_label_set_mnemonic_widget:
952 * @label: a #GtkLabel
953 * @widget: the target #GtkWidget
955 * If the label has been set so that it has an mnemonic key (using
956 * i.e. gtk_label_set_markup_with_mnemonic(),
957 * gtk_label_set_text_with_mnemonic(), gtk_label_new_with_mnemonic()
958 * or the "use_underline" property) the label can be associated with a
959 * widget that is the target of the mnemonic. When the label is inside
960 * a widget (like a #GtkButton or a #GtkNotebook tab) it is
961 * automatically associated with the correct widget, but sometimes
962 * (i.e. when the target is a #GtkEntry next to the label) you need to
963 * set it explicitly using this function.
965 * The target widget will be accelerated by emitting "mnemonic_activate" on it.
966 * The default handler for this signal will activate the widget if there are no
967 * mnemonic collisions and toggle focus between the colliding widgets otherwise.
970 gtk_label_set_mnemonic_widget (GtkLabel *label,
973 g_return_if_fail (GTK_IS_LABEL (label));
975 g_return_if_fail (GTK_IS_WIDGET (widget));
977 if (label->mnemonic_widget)
979 gtk_widget_remove_mnemonic_label (label->mnemonic_widget, GTK_WIDGET (label));
980 g_object_weak_unref (G_OBJECT (label->mnemonic_widget),
981 label_mnemonic_widget_weak_notify,
984 label->mnemonic_widget = widget;
985 if (label->mnemonic_widget)
987 g_object_weak_ref (G_OBJECT (label->mnemonic_widget),
988 label_mnemonic_widget_weak_notify,
990 gtk_widget_add_mnemonic_label (label->mnemonic_widget, GTK_WIDGET (label));
993 g_object_notify (G_OBJECT (label), "mnemonic_widget");
997 * gtk_label_get_mnemonic_widget:
998 * @label: a #GtkLabel
1000 * Retrieves the target of the mnemonic (keyboard shortcut) of this
1001 * label. See gtk_label_set_mnemonic_widget ().
1003 * Return value: the target of the label's mnemonic, or %NULL if none
1004 * has been set and the default algorithm will be used.
1007 gtk_label_get_mnemonic_widget (GtkLabel *label)
1009 g_return_val_if_fail (GTK_IS_LABEL (label), NULL);
1011 return label->mnemonic_widget;
1015 * gtk_label_get_mnemonic_keyval:
1016 * @label: a #GtkLabel
1018 * If the label has been set so that it has an mnemonic key this function
1019 * returns the keyval used for the mnemonic accelerator. If there is no
1020 * mnemonic set up it returns #GDK_VoidSymbol.
1022 * Returns: GDK keyval usable for accelerators, or #GDK_VoidSymbol
1025 gtk_label_get_mnemonic_keyval (GtkLabel *label)
1027 g_return_val_if_fail (GTK_IS_LABEL (label), GDK_VoidSymbol);
1029 return label->mnemonic_keyval;
1033 gtk_label_set_text_internal (GtkLabel *label,
1036 g_free (label->text);
1040 gtk_label_select_region_index (label, 0, 0);
1044 gtk_label_set_label_internal (GtkLabel *label,
1047 g_free (label->label);
1051 g_object_notify (G_OBJECT (label), "label");
1055 gtk_label_set_use_markup_internal (GtkLabel *label,
1059 if (label->use_markup != val)
1061 g_object_notify (G_OBJECT (label), "use_markup");
1062 label->use_markup = val;
1067 gtk_label_set_use_underline_internal (GtkLabel *label,
1071 if (label->use_underline != val)
1073 g_object_notify (G_OBJECT (label), "use_underline");
1074 label->use_underline = val;
1079 gtk_label_set_attributes_internal (GtkLabel *label,
1080 PangoAttrList *attrs)
1083 pango_attr_list_ref (attrs);
1086 pango_attr_list_unref (label->attrs);
1088 if (!label->use_markup && !label->use_underline)
1091 pango_attr_list_ref (attrs);
1092 if (label->effective_attrs)
1093 pango_attr_list_unref (label->effective_attrs);
1094 label->effective_attrs = attrs;
1097 label->attrs = attrs;
1098 g_object_notify (G_OBJECT (label), "attributes");
1102 /* Calculates text, attrs and mnemonic_keyval from
1103 * label, use_underline and use_markup
1106 gtk_label_recalculate (GtkLabel *label)
1108 if (label->use_markup)
1109 set_markup (label, label->label, label->use_underline);
1112 if (label->use_underline)
1113 gtk_label_set_uline_text_internal (label, label->label);
1116 gtk_label_set_text_internal (label, g_strdup (label->label));
1118 pango_attr_list_ref (label->attrs);
1119 if (label->effective_attrs)
1120 pango_attr_list_unref (label->effective_attrs);
1121 label->effective_attrs = label->attrs;
1125 if (!label->use_underline)
1127 guint keyval = label->mnemonic_keyval;
1129 label->mnemonic_keyval = GDK_VoidSymbol;
1130 gtk_label_setup_mnemonic (label, keyval);
1133 gtk_label_clear_layout (label);
1134 gtk_widget_queue_resize (GTK_WIDGET (label));
1138 * gtk_label_set_text:
1139 * @label: a #GtkLabel
1140 * @str: The text you want to set.
1142 * Sets the text within the #GtkLabel widget. It overwrites any text that
1145 * This will also clear any previously set mnemonic accelerators.
1148 gtk_label_set_text (GtkLabel *label,
1151 g_return_if_fail (GTK_IS_LABEL (label));
1153 g_object_freeze_notify (G_OBJECT (label));
1155 gtk_label_set_label_internal (label, g_strdup (str ? str : ""));
1156 gtk_label_set_use_markup_internal (label, FALSE);
1157 gtk_label_set_use_underline_internal (label, FALSE);
1159 gtk_label_recalculate (label);
1161 g_object_thaw_notify (G_OBJECT (label));
1165 * gtk_label_set_attributes:
1166 * @label: a #GtkLabel
1167 * @attrs: a #PangoAttrList
1169 * Sets a #PangoAttrList; the attributes in the list are applied to the
1170 * label text. The attributes set with this function will be ignored
1171 * if the "use_underline" property or the "use_markup" property
1175 gtk_label_set_attributes (GtkLabel *label,
1176 PangoAttrList *attrs)
1178 g_return_if_fail (GTK_IS_LABEL (label));
1180 gtk_label_set_attributes_internal (label, attrs);
1182 gtk_label_clear_layout (label);
1183 gtk_widget_queue_resize (GTK_WIDGET (label));
1187 * gtk_label_get_attributes:
1188 * @label: a #GtkLabel
1190 * Gets the attribute list that was set on the label using
1191 * gtk_label_set_attributes(), if any. This function does
1192 * not reflect attributes that come from the labels markup
1193 * (see gtk_label_set_markup()). If you want to get the
1194 * effective attributes for the label, use
1195 * pango_layout_get_attribute (gtk_label_get_layout (label)).
1197 * Return value: the attribute list, or %NULL if none was set.
1200 gtk_label_get_attributes (GtkLabel *label)
1202 g_return_val_if_fail (GTK_IS_LABEL (label), NULL);
1204 return label->attrs;
1208 * gtk_label_set_label:
1209 * @label: a #GtkLabel
1210 * @str: the new text to set for the label
1212 * Sets the text of the label. The label is interpreted as
1213 * including embedded underlines and/or Pango markup depending
1214 * on the values of label->use_underline and label->use_markup.
1217 gtk_label_set_label (GtkLabel *label,
1222 g_return_if_fail (GTK_IS_LABEL (label));
1223 g_return_if_fail (str != NULL);
1225 last_keyval = label->mnemonic_keyval;
1227 gtk_label_set_label_internal (label, g_strdup (str));
1228 gtk_label_recalculate (label);
1229 if (last_keyval != label->mnemonic_keyval)
1230 gtk_label_setup_mnemonic (label, last_keyval);
1234 * gtk_label_get_label:
1235 * @label: a #GtkLabel
1237 * Fetches the text from a label widget including any embedded
1238 * underlines indicating mnemonics and Pango markup. (See
1239 * gtk_label_get_text ()).
1241 * Return value: the text of the label widget. This string is
1242 * owned by the widget and must not be modified or freed.
1244 G_CONST_RETURN gchar *
1245 gtk_label_get_label (GtkLabel *label)
1247 g_return_val_if_fail (GTK_IS_LABEL (label), NULL);
1249 return label->label;
1253 set_markup (GtkLabel *label,
1255 gboolean with_uline)
1258 GError *error = NULL;
1259 PangoAttrList *attrs = NULL;
1260 gunichar accel_char = 0;
1262 if (!pango_parse_markup (str,
1264 with_uline ? '_' : 0,
1267 with_uline ? &accel_char : NULL,
1270 g_warning ("Failed to set label from markup due to error parsing markup: %s",
1272 g_error_free (error);
1277 gtk_label_set_text_internal (label, text);
1281 if (label->effective_attrs)
1282 pango_attr_list_unref (label->effective_attrs);
1283 label->effective_attrs = attrs;
1286 if (accel_char != 0)
1287 label->mnemonic_keyval = gdk_keyval_to_lower (gdk_unicode_to_keyval (accel_char));
1289 label->mnemonic_keyval = GDK_VoidSymbol;
1293 * gtk_label_set_markup:
1294 * @label: a #GtkLabel
1295 * @str: a markup string (see <link linkend="PangoMarkupFormat">Pango markup format</link>)
1297 * Parses @str which is marked up with the <link
1298 * linkend="PangoMarkupFormat">Pango text markup language</link>, setting the
1299 * label's text and attribute list based on the parse results. If the @str is
1300 * external data, you may need to escape it with g_markup_escape_text() or
1301 * g_markup_printf_escaped()<!-- -->:
1302 * <informalexample><programlisting>
1305 * markup = g_markup_printf_escaped ("<span style=\"italic\">%s</span>", str);
1306 * gtk_label_set_markup (GTK_LABEL (label), markup);
1308 * </programlisting></informalexample>
1311 gtk_label_set_markup (GtkLabel *label,
1314 g_return_if_fail (GTK_IS_LABEL (label));
1316 gtk_label_set_label_internal (label, g_strdup (str ? str : ""));
1317 gtk_label_set_use_markup_internal (label, TRUE);
1318 gtk_label_set_use_underline_internal (label, FALSE);
1320 gtk_label_recalculate (label);
1324 * gtk_label_set_markup_with_mnemonic:
1325 * @label: a #GtkLabel
1326 * @str: a markup string (see <link linkend="PangoMarkupFormat">Pango markup format</link>)
1328 * Parses @str which is marked up with the <link linkend="PangoMarkupFormat">Pango text markup language</link>,
1329 * setting the label's text and attribute list based on the parse results.
1330 * If characters in @str are preceded by an underscore, they are underlined
1331 * indicating that they represent a keyboard accelerator called a mnemonic.
1333 * The mnemonic key can be used to activate another widget, chosen automatically,
1334 * or explicitly using gtk_label_set_mnemonic_widget().
1337 gtk_label_set_markup_with_mnemonic (GtkLabel *label,
1341 g_return_if_fail (GTK_IS_LABEL (label));
1343 last_keyval = label->mnemonic_keyval;
1344 gtk_label_set_label_internal (label, g_strdup (str ? str : ""));
1345 gtk_label_set_use_markup_internal (label, TRUE);
1346 gtk_label_set_use_underline_internal (label, TRUE);
1348 gtk_label_recalculate (label);
1349 gtk_label_setup_mnemonic (label, last_keyval);
1353 * gtk_label_get_text:
1354 * @label: a #GtkLabel
1356 * Fetches the text from a label widget, as displayed on the
1357 * screen. This does not include any embedded underlines
1358 * indicating mnemonics or Pango markup. (See gtk_label_get_label())
1360 * Return value: the text in the label widget. This is the internal
1361 * string used by the label, and must not be modified.
1363 G_CONST_RETURN gchar *
1364 gtk_label_get_text (GtkLabel *label)
1366 g_return_val_if_fail (GTK_IS_LABEL (label), NULL);
1371 static PangoAttrList *
1372 gtk_label_pattern_to_attrs (GtkLabel *label,
1373 const gchar *pattern)
1376 const char *p = label->text;
1377 const char *q = pattern;
1378 PangoAttrList *attrs;
1380 attrs = pango_attr_list_new ();
1384 while (*p && *q && *q != '_')
1386 p = g_utf8_next_char (p);
1390 while (*p && *q && *q == '_')
1392 p = g_utf8_next_char (p);
1398 PangoAttribute *attr = pango_attr_underline_new (PANGO_UNDERLINE_LOW);
1399 attr->start_index = start - label->text;
1400 attr->end_index = p - label->text;
1402 pango_attr_list_insert (attrs, attr);
1412 gtk_label_set_pattern_internal (GtkLabel *label,
1413 const gchar *pattern)
1415 PangoAttrList *attrs;
1416 g_return_if_fail (GTK_IS_LABEL (label));
1419 attrs = gtk_label_pattern_to_attrs (label, pattern);
1423 if (label->effective_attrs)
1424 pango_attr_list_unref (label->effective_attrs);
1425 label->effective_attrs = attrs;
1429 gtk_label_set_pattern (GtkLabel *label,
1430 const gchar *pattern)
1432 g_return_if_fail (GTK_IS_LABEL (label));
1434 gtk_label_set_pattern_internal (label, pattern);
1436 gtk_label_clear_layout (label);
1437 gtk_widget_queue_resize (GTK_WIDGET (label));
1442 * gtk_label_set_justify:
1443 * @label: a #GtkLabel
1444 * @jtype: a #GtkJustification
1446 * Sets the alignment of the lines in the text of the label relative to
1447 * each other. %GTK_JUSTIFY_LEFT is the default value when the
1448 * widget is first created with gtk_label_new(). If you instead want
1449 * to set the alignment of the label as a whole, use
1450 * gtk_misc_set_alignment() instead. gtk_label_set_justify() has no
1451 * effect on labels containing only a single line.
1454 gtk_label_set_justify (GtkLabel *label,
1455 GtkJustification jtype)
1457 g_return_if_fail (GTK_IS_LABEL (label));
1458 g_return_if_fail (jtype >= GTK_JUSTIFY_LEFT && jtype <= GTK_JUSTIFY_FILL);
1460 if ((GtkJustification) label->jtype != jtype)
1462 label->jtype = jtype;
1464 /* No real need to be this drastic, but easier than duplicating the code */
1465 gtk_label_clear_layout (label);
1467 g_object_notify (G_OBJECT (label), "justify");
1468 gtk_widget_queue_resize (GTK_WIDGET (label));
1473 * gtk_label_get_justify:
1474 * @label: a #GtkLabel
1476 * Returns the justification of the label. See gtk_label_set_justify ().
1478 * Return value: #GtkJustification
1481 gtk_label_get_justify (GtkLabel *label)
1483 g_return_val_if_fail (GTK_IS_LABEL (label), 0);
1485 return label->jtype;
1489 * gtk_label_set_ellipsize:
1490 * @label: a #GtkLabel
1491 * @mode: a #PangoEllipsizeMode
1493 * Sets the mode used to ellipsize (add an ellipsis: "...") to the text if there
1494 * is not enough space to render the entire string.
1499 gtk_label_set_ellipsize (GtkLabel *label,
1500 PangoEllipsizeMode mode)
1502 g_return_if_fail (GTK_IS_LABEL (label));
1503 g_return_if_fail (mode >= PANGO_ELLIPSIZE_NONE && mode <= PANGO_ELLIPSIZE_END);
1505 if ((PangoEllipsizeMode) label->ellipsize != mode)
1507 label->ellipsize = mode;
1509 /* No real need to be this drastic, but easier than duplicating the code */
1510 gtk_label_clear_layout (label);
1512 g_object_notify (G_OBJECT (label), "ellipsize");
1513 gtk_widget_queue_resize (GTK_WIDGET (label));
1518 * gtk_label_get_ellipsize:
1519 * @label: a #GtkLabel
1521 * Returns the ellipsizing position of the label. See gtk_label_set_ellipsize().
1523 * Return value: #PangoEllipsizeMode
1528 gtk_label_get_ellipsize (GtkLabel *label)
1530 g_return_val_if_fail (GTK_IS_LABEL (label), PANGO_ELLIPSIZE_NONE);
1532 return label->ellipsize;
1536 * gtk_label_set_width_chars:
1537 * @label: a #GtkLabel
1538 * @n_chars: the new desired width, in characters.
1540 * Sets the desired width in characters of @label to @n_chars.
1545 gtk_label_set_width_chars (GtkLabel *label,
1548 GtkLabelPrivate *priv;
1550 g_return_if_fail (GTK_IS_LABEL (label));
1552 priv = GTK_LABEL_GET_PRIVATE (label);
1554 if (priv->width_chars != n_chars)
1556 priv->width_chars = n_chars;
1557 g_object_notify (G_OBJECT (label), "width-chars");
1558 gtk_widget_queue_resize (GTK_WIDGET (label));
1563 * gtk_label_get_width_chars:
1564 * @label: a #GtkLabel
1566 * Retrieves the desired width of @label, in characters. See
1567 * gtk_label_set_width_chars().
1569 * Return value: the width of the label in characters.
1574 gtk_label_get_width_chars (GtkLabel *label)
1576 g_return_val_if_fail (GTK_IS_LABEL (label), -1);
1578 return GTK_LABEL_GET_PRIVATE (label)->width_chars;
1582 * gtk_label_set_max_width_chars:
1583 * @label: a #GtkLabel
1584 * @n_chars: the new desired maximum width, in characters.
1586 * Sets the desired maximum width in characters of @label to @n_chars.
1591 gtk_label_set_max_width_chars (GtkLabel *label,
1594 GtkLabelPrivate *priv;
1596 g_return_if_fail (GTK_IS_LABEL (label));
1598 priv = GTK_LABEL_GET_PRIVATE (label);
1600 if (priv->max_width_chars != n_chars)
1602 priv->max_width_chars = n_chars;
1604 g_object_notify (G_OBJECT (label), "max-width-chars");
1605 gtk_widget_queue_resize (GTK_WIDGET (label));
1610 * gtk_label_get_max_width_chars:
1611 * @label: a #GtkLabel
1613 * Retrieves the desired maximum width of @label, in characters. See
1614 * gtk_label_set_width_chars().
1616 * Return value: the maximum width of the label in characters.
1621 gtk_label_get_max_width_chars (GtkLabel *label)
1623 g_return_val_if_fail (GTK_IS_LABEL (label), -1);
1625 return GTK_LABEL_GET_PRIVATE (label)->max_width_chars;
1629 * gtk_label_set_line_wrap:
1630 * @label: a #GtkLabel
1631 * @wrap: the setting
1633 * Toggles line wrapping within the #GtkLabel widget. %TRUE makes it break
1634 * lines if text exceeds the widget's size. %FALSE lets the text get cut off
1635 * by the edge of the widget if it exceeds the widget size.
1638 gtk_label_set_line_wrap (GtkLabel *label,
1641 g_return_if_fail (GTK_IS_LABEL (label));
1643 wrap = wrap != FALSE;
1645 if (label->wrap != wrap)
1648 g_object_notify (G_OBJECT (label), "wrap");
1650 gtk_widget_queue_resize (GTK_WIDGET (label));
1655 * gtk_label_get_line_wrap:
1656 * @label: a #GtkLabel
1658 * Returns whether lines in the label are automatically wrapped. See gtk_label_set_line_wrap ().
1660 * Return value: %TRUE if the lines of the label are automatically wrapped.
1663 gtk_label_get_line_wrap (GtkLabel *label)
1665 g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
1671 gtk_label_get (GtkLabel *label,
1674 g_return_if_fail (GTK_IS_LABEL (label));
1675 g_return_if_fail (str != NULL);
1681 gtk_label_destroy (GtkObject *object)
1683 GtkLabel *label = GTK_LABEL (object);
1685 gtk_label_set_mnemonic_widget (label, NULL);
1687 GTK_OBJECT_CLASS (parent_class)->destroy (object);
1691 gtk_label_finalize (GObject *object)
1695 g_return_if_fail (GTK_IS_LABEL (object));
1697 label = GTK_LABEL (object);
1699 g_free (label->label);
1700 g_free (label->text);
1703 g_object_unref (label->layout);
1706 pango_attr_list_unref (label->attrs);
1708 if (label->effective_attrs)
1709 pango_attr_list_unref (label->effective_attrs);
1711 g_free (label->select_info);
1713 G_OBJECT_CLASS (parent_class)->finalize (object);
1717 gtk_label_clear_layout (GtkLabel *label)
1721 g_object_unref (label->layout);
1722 label->layout = NULL;
1726 typedef struct _LabelWrapWidth LabelWrapWidth;
1727 struct _LabelWrapWidth
1730 PangoFontDescription *font_desc;
1734 label_wrap_width_free (gpointer data)
1736 LabelWrapWidth *wrap_width = data;
1737 pango_font_description_free (wrap_width->font_desc);
1738 g_free (wrap_width);
1742 get_label_wrap_width (GtkLabel *label)
1744 PangoLayout *layout;
1745 GtkStyle *style = GTK_WIDGET (label)->style;
1747 LabelWrapWidth *wrap_width = g_object_get_data (G_OBJECT (style), "gtk-label-wrap-width");
1750 wrap_width = g_new0 (LabelWrapWidth, 1);
1751 g_object_set_data_full (G_OBJECT (style), "gtk-label-wrap-width",
1752 wrap_width, label_wrap_width_free);
1755 if (wrap_width->font_desc && pango_font_description_equal (wrap_width->font_desc, style->font_desc))
1756 return wrap_width->width;
1758 if (wrap_width->font_desc)
1759 pango_font_description_free (wrap_width->font_desc);
1761 wrap_width->font_desc = pango_font_description_copy (style->font_desc);
1763 layout = gtk_widget_create_pango_layout (GTK_WIDGET (label),
1764 "This long string gives a good enough length for any line to have.");
1765 pango_layout_get_size (layout, &wrap_width->width, NULL);
1766 g_object_unref (layout);
1768 return wrap_width->width;
1772 gtk_label_ensure_layout (GtkLabel *label)
1775 PangoRectangle logical_rect;
1776 gint rwidth, rheight;
1779 widget = GTK_WIDGET (label);
1781 rtl = gtk_widget_get_direction(widget) == GTK_TEXT_DIR_RTL;
1782 rwidth = label->misc.xpad * 2;
1783 rheight = label->misc.ypad * 2;
1787 PangoAlignment align = PANGO_ALIGN_LEFT; /* Quiet gcc */
1788 GtkLabelPrivate *priv = GTK_LABEL_GET_PRIVATE (label);
1790 if (priv->angle != 0.0 && !label->wrap && !label->ellipsize && !label->select_info)
1792 /* We rotate the standard singleton PangoContext for the widget,
1793 * depending on the fact that it's meant pretty much exclusively
1796 PangoMatrix matrix = PANGO_MATRIX_INIT;
1798 pango_matrix_rotate (&matrix, priv->angle);
1800 pango_context_set_matrix (gtk_widget_get_pango_context (widget), &matrix);
1802 priv->have_transform = TRUE;
1806 if (priv->have_transform)
1807 pango_context_set_matrix (gtk_widget_get_pango_context (widget), NULL);
1809 priv->have_transform = FALSE;
1812 label->layout = gtk_widget_create_pango_layout (widget, label->text);
1814 if (label->effective_attrs)
1815 pango_layout_set_attributes (label->layout, label->effective_attrs);
1817 switch (label->jtype)
1819 case GTK_JUSTIFY_LEFT:
1820 align = rtl ? PANGO_ALIGN_RIGHT : PANGO_ALIGN_LEFT;
1822 case GTK_JUSTIFY_RIGHT:
1823 align = rtl ? PANGO_ALIGN_LEFT : PANGO_ALIGN_RIGHT;
1825 case GTK_JUSTIFY_CENTER:
1826 align = PANGO_ALIGN_CENTER;
1828 case GTK_JUSTIFY_FILL:
1829 /* FIXME: This just doesn't work to do this */
1830 align = rtl ? PANGO_ALIGN_RIGHT : PANGO_ALIGN_LEFT;
1831 pango_layout_set_justify (label->layout, TRUE);
1834 g_assert_not_reached();
1837 pango_layout_set_alignment (label->layout, align);
1838 pango_layout_set_ellipsize (label->layout, label->ellipsize);
1839 pango_layout_set_single_paragraph_mode (label->layout, priv->single_line_mode);
1841 if (label->ellipsize)
1842 pango_layout_set_width (label->layout,
1843 widget->allocation.width * PANGO_SCALE);
1844 else if (label->wrap)
1846 GtkWidgetAuxInfo *aux_info;
1847 gint longest_paragraph;
1850 aux_info = _gtk_widget_get_aux_info (widget, FALSE);
1851 if (aux_info && aux_info->width > 0)
1852 pango_layout_set_width (label->layout, aux_info->width * PANGO_SCALE);
1855 GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET (label));
1858 pango_layout_set_width (label->layout, -1);
1859 pango_layout_get_extents (label->layout, NULL, &logical_rect);
1861 width = logical_rect.width;
1863 /* Try to guess a reasonable maximum width */
1864 longest_paragraph = width;
1866 wrap_width = get_label_wrap_width (label);
1867 width = MIN (width, wrap_width);
1869 PANGO_SCALE * (gdk_screen_get_width (screen) + 1) / 2);
1871 pango_layout_set_width (label->layout, width);
1872 pango_layout_get_extents (label->layout, NULL, &logical_rect);
1873 width = logical_rect.width;
1874 height = logical_rect.height;
1876 /* Unfortunately, the above may leave us with a very unbalanced looking paragraph,
1877 * so we try short search for a narrower width that leaves us with the same height
1879 if (longest_paragraph > 0)
1881 gint nlines, perfect_width;
1883 nlines = pango_layout_get_line_count (label->layout);
1884 perfect_width = (longest_paragraph + nlines - 1) / nlines;
1886 if (perfect_width < width)
1888 pango_layout_set_width (label->layout, perfect_width);
1889 pango_layout_get_extents (label->layout, NULL, &logical_rect);
1891 if (logical_rect.height <= height)
1892 width = logical_rect.width;
1895 gint mid_width = (perfect_width + width) / 2;
1897 if (mid_width > perfect_width)
1899 pango_layout_set_width (label->layout, mid_width);
1900 pango_layout_get_extents (label->layout, NULL, &logical_rect);
1902 if (logical_rect.height <= height)
1903 width = logical_rect.width;
1908 pango_layout_set_width (label->layout, width);
1911 else /* !label->wrap */
1912 pango_layout_set_width (label->layout, -1);
1916 /* Gets the bounds of a layout in device coordinates. Note cut-and-paste
1917 * between here and gdkpango.c */
1919 get_rotated_layout_bounds (PangoLayout *layout,
1922 PangoContext *context = pango_layout_get_context (layout);
1923 const PangoMatrix *matrix = pango_context_get_matrix (context);
1924 gdouble x_min = 0, x_max = 0, y_min = 0, y_max = 0; /* quiet gcc */
1925 PangoRectangle logical_rect;
1928 pango_layout_get_extents (layout, NULL, &logical_rect);
1930 for (i = 0; i < 2; i++)
1932 gdouble x = (i == 0) ? logical_rect.x : logical_rect.x + logical_rect.width;
1933 for (j = 0; j < 2; j++)
1935 gdouble y = (j == 0) ? logical_rect.y : logical_rect.y + logical_rect.height;
1937 gdouble xt = (x * matrix->xx + y * matrix->xy) / PANGO_SCALE + matrix->x0;
1938 gdouble yt = (x * matrix->yx + y * matrix->yy) / PANGO_SCALE + matrix->y0;
1940 if (i == 0 && j == 0)
1959 rect->x = floor (x_min);
1960 rect->width = ceil (x_max) - rect->x;
1961 rect->y = floor (y_min);
1962 rect->height = floor (y_max) - rect->y;
1966 gtk_label_size_request (GtkWidget *widget,
1967 GtkRequisition *requisition)
1970 GtkLabelPrivate *priv;
1972 PangoRectangle logical_rect;
1973 GtkWidgetAuxInfo *aux_info;
1975 g_return_if_fail (GTK_IS_LABEL (widget));
1976 g_return_if_fail (requisition != NULL);
1978 label = GTK_LABEL (widget);
1979 priv = GTK_LABEL_GET_PRIVATE (widget);
1982 * If word wrapping is on, then the height requisition can depend
1985 * - Any width set on the widget via gtk_widget_set_usize().
1986 * - The padding of the widget (xpad, set by gtk_misc_set_padding)
1988 * Instead of trying to detect changes to these quantities, if we
1989 * are wrapping, we just rewrap for each size request. Since
1990 * size requisitions are cached by the GTK+ core, this is not
1995 gtk_label_clear_layout (label);
1997 gtk_label_ensure_layout (label);
1999 width = label->misc.xpad * 2;
2000 height = label->misc.ypad * 2;
2002 aux_info = _gtk_widget_get_aux_info (widget, FALSE);
2004 if (priv->have_transform)
2008 get_rotated_layout_bounds (label->layout, &rect);
2010 requisition->width = width + rect.width;
2011 requisition->height = height + rect.height;
2016 pango_layout_get_extents (label->layout, NULL, &logical_rect);
2018 if ((label->wrap || label->ellipsize ||
2019 priv->width_chars > 0 || priv->max_width_chars > 0) &&
2020 aux_info && aux_info->width > 0)
2021 width += aux_info->width;
2022 else if (label->ellipsize || priv->width_chars > 0 || priv->max_width_chars > 0)
2024 PangoContext *context;
2025 PangoFontMetrics *metrics;
2026 gint char_width, digit_width, char_pixels, w;
2028 context = pango_layout_get_context (label->layout);
2029 metrics = pango_context_get_metrics (context, widget->style->font_desc,
2030 pango_context_get_language (context));
2032 char_width = pango_font_metrics_get_approximate_char_width (metrics);
2033 digit_width = pango_font_metrics_get_approximate_digit_width (metrics);
2034 char_pixels = MAX (char_width, digit_width);
2035 pango_font_metrics_unref (metrics);
2037 if (priv->width_chars < 0)
2039 PangoRectangle rect;
2041 pango_layout_set_width (label->layout, -1);
2042 pango_layout_get_extents (label->layout, NULL, &rect);
2044 w = char_pixels * MAX (priv->max_width_chars, 3);
2045 w = MIN (rect.width, w);
2049 /* enforce minimum width for ellipsized labels at ~3 chars */
2050 w = char_pixels * MAX (priv->width_chars, 3);
2053 width += PANGO_PIXELS (w);
2056 width += PANGO_PIXELS (logical_rect.width);
2058 if (priv->single_line_mode)
2060 PangoContext *context;
2061 PangoFontMetrics *metrics;
2062 gint ascent, descent;
2064 context = pango_layout_get_context (label->layout);
2065 metrics = pango_context_get_metrics (context, widget->style->font_desc,
2066 pango_context_get_language (context));
2068 ascent = pango_font_metrics_get_ascent (metrics);
2069 descent = pango_font_metrics_get_descent (metrics);
2070 pango_font_metrics_unref (metrics);
2072 height += PANGO_PIXELS (ascent + descent);
2075 height += PANGO_PIXELS (logical_rect.height);
2077 requisition->width = width;
2078 requisition->height = height;
2082 gtk_label_size_allocate (GtkWidget *widget,
2083 GtkAllocation *allocation)
2086 GtkLabelPrivate *priv;
2088 label = GTK_LABEL (widget);
2089 priv = GTK_LABEL_GET_PRIVATE (widget);
2091 (* GTK_WIDGET_CLASS (parent_class)->size_allocate) (widget, allocation);
2093 if (label->ellipsize)
2096 pango_layout_set_width (label->layout, allocation->width * PANGO_SCALE);
2099 if (label->select_info && label->select_info->window)
2101 gdk_window_move_resize (label->select_info->window,
2105 allocation->height);
2110 gtk_label_state_changed (GtkWidget *widget,
2111 GtkStateType prev_state)
2115 label = GTK_LABEL (widget);
2117 if (label->select_info)
2118 gtk_label_select_region (label, 0, 0);
2120 if (GTK_WIDGET_CLASS (parent_class)->state_changed)
2121 GTK_WIDGET_CLASS (parent_class)->state_changed (widget, prev_state);
2125 gtk_label_style_set (GtkWidget *widget,
2126 GtkStyle *previous_style)
2130 g_return_if_fail (GTK_IS_LABEL (widget));
2132 label = GTK_LABEL (widget);
2134 /* We have to clear the layout, fonts etc. may have changed */
2135 gtk_label_clear_layout (label);
2139 gtk_label_direction_changed (GtkWidget *widget,
2140 GtkTextDirection previous_dir)
2142 GtkLabel *label = GTK_LABEL (widget);
2145 pango_layout_context_changed (label->layout);
2147 GTK_WIDGET_CLASS (parent_class)->direction_changed (widget, previous_dir);
2151 get_layout_location (GtkLabel *label,
2158 gint req_width, x, y;
2160 misc = GTK_MISC (label);
2161 widget = GTK_WIDGET (label);
2163 if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
2164 xalign = misc->xalign;
2166 xalign = 1.0 - misc->xalign;
2168 if (label->ellipsize)
2170 PangoRectangle ink_rect;
2172 pango_layout_get_extents (label->layout, &ink_rect, NULL);
2174 req_width = PANGO_PIXELS (ink_rect.width);
2177 req_width = widget->requisition.width;
2179 x = floor (widget->allocation.x + (gint)misc->xpad +
2180 xalign * (widget->allocation.width - req_width)
2183 if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
2184 x = MAX (x, widget->allocation.x + misc->xpad);
2187 widget->allocation.x + widget->allocation.width -
2188 req_width - misc->xpad);
2190 y = floor (widget->allocation.y + (gint)misc->ypad
2191 + MAX (((widget->allocation.height - widget->requisition.height) * misc->yalign)
2202 draw_insertion_cursor (GtkLabel *label,
2203 GdkRectangle *cursor_location,
2204 gboolean is_primary,
2205 PangoDirection direction,
2206 gboolean draw_arrow)
2208 GtkWidget *widget = GTK_WIDGET (label);
2209 GtkTextDirection text_dir;
2211 if (direction == PANGO_DIRECTION_LTR)
2212 text_dir = GTK_TEXT_DIR_LTR;
2214 text_dir = GTK_TEXT_DIR_RTL;
2216 gtk_draw_insertion_cursor (widget, widget->window, &(widget->allocation),
2218 is_primary, text_dir, draw_arrow);
2221 static PangoDirection
2222 get_cursor_direction (GtkLabel *label)
2226 g_assert (label->select_info);
2228 gtk_label_ensure_layout (label);
2230 for (l = pango_layout_get_lines (label->layout); l; l = l->next)
2232 PangoLayoutLine *line = l->data;
2234 /* If label->select_info->selection_end is at the very end of
2235 * the line, we don't know if the cursor is on this line or
2236 * the next without looking ahead at the next line. (End
2237 * of paragraph is different from line break.) But it's
2238 * definitely in this paragraph, which is good enough
2239 * to figure out the resolved direction.
2241 if (line->start_index + line->length >= label->select_info->selection_end)
2242 return line->resolved_dir;
2245 return PANGO_DIRECTION_LTR;
2249 gtk_label_draw_cursor (GtkLabel *label, gint xoffset, gint yoffset)
2251 if (label->select_info == NULL)
2254 if (GTK_WIDGET_DRAWABLE (label))
2256 GtkWidget *widget = GTK_WIDGET (label);
2258 PangoDirection keymap_direction;
2259 PangoDirection cursor_direction;
2260 PangoRectangle strong_pos, weak_pos;
2261 gboolean split_cursor;
2262 PangoRectangle *cursor1 = NULL;
2263 PangoRectangle *cursor2 = NULL;
2264 GdkRectangle cursor_location;
2265 PangoDirection dir1 = PANGO_DIRECTION_NEUTRAL;
2266 PangoDirection dir2 = PANGO_DIRECTION_NEUTRAL;
2268 keymap_direction = gdk_keymap_get_direction (gdk_keymap_get_for_display (gtk_widget_get_display (widget)));
2269 cursor_direction = get_cursor_direction (label);
2271 gtk_label_ensure_layout (label);
2273 pango_layout_get_cursor_pos (label->layout, label->select_info->selection_end,
2274 &strong_pos, &weak_pos);
2276 g_object_get (gtk_widget_get_settings (widget),
2277 "gtk-split-cursor", &split_cursor,
2280 dir1 = cursor_direction;
2284 cursor1 = &strong_pos;
2286 if (strong_pos.x != weak_pos.x ||
2287 strong_pos.y != weak_pos.y)
2289 dir2 = (cursor_direction == PANGO_DIRECTION_LTR) ? PANGO_DIRECTION_RTL : PANGO_DIRECTION_LTR;
2290 cursor2 = &weak_pos;
2295 if (keymap_direction == cursor_direction)
2296 cursor1 = &strong_pos;
2298 cursor1 = &weak_pos;
2301 cursor_location.x = xoffset + PANGO_PIXELS (cursor1->x);
2302 cursor_location.y = yoffset + PANGO_PIXELS (cursor1->y);
2303 cursor_location.width = 0;
2304 cursor_location.height = PANGO_PIXELS (cursor1->height);
2306 draw_insertion_cursor (label,
2307 &cursor_location, TRUE, dir1,
2308 dir2 != PANGO_DIRECTION_NEUTRAL);
2310 if (dir2 != PANGO_DIRECTION_NEUTRAL)
2312 cursor_location.x = xoffset + PANGO_PIXELS (cursor2->x);
2313 cursor_location.y = yoffset + PANGO_PIXELS (cursor2->y);
2314 cursor_location.width = 0;
2315 cursor_location.height = PANGO_PIXELS (cursor2->height);
2317 draw_insertion_cursor (label,
2318 &cursor_location, FALSE, dir2,
2326 gtk_label_expose (GtkWidget *widget,
2327 GdkEventExpose *event)
2332 g_return_val_if_fail (GTK_IS_LABEL (widget), FALSE);
2333 g_return_val_if_fail (event != NULL, FALSE);
2335 label = GTK_LABEL (widget);
2337 gtk_label_ensure_layout (label);
2339 if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_MAPPED (widget) &&
2340 label->text && (*label->text != '\0'))
2342 get_layout_location (label, &x, &y);
2344 gtk_paint_layout (widget->style,
2346 GTK_WIDGET_STATE (widget),
2354 if (label->select_info &&
2355 (label->select_info->selection_anchor !=
2356 label->select_info->selection_end))
2362 range[0] = label->select_info->selection_anchor;
2363 range[1] = label->select_info->selection_end;
2365 if (range[0] > range[1])
2367 gint tmp = range[0];
2368 range[0] = range[1];
2372 clip = gdk_pango_layout_get_clip_region (label->layout,
2376 gdk_region_intersect (clip, event->region);
2378 /* FIXME should use gtk_paint, but it can't use a clip
2382 gdk_gc_set_clip_region (widget->style->black_gc, clip);
2385 state = GTK_STATE_SELECTED;
2386 if (!GTK_WIDGET_HAS_FOCUS (widget))
2387 state = GTK_STATE_ACTIVE;
2389 gdk_draw_layout_with_colors (widget->window,
2390 widget->style->black_gc,
2393 &widget->style->text[state],
2394 &widget->style->base[state]);
2396 gdk_gc_set_clip_region (widget->style->black_gc, NULL);
2397 gdk_region_destroy (clip);
2399 else if (label->select_info && GTK_WIDGET_HAS_FOCUS (widget))
2400 gtk_label_draw_cursor (label, x, y);
2407 gtk_label_set_uline_text_internal (GtkLabel *label,
2410 guint accel_key = GDK_VoidSymbol;
2415 gchar *dest, *pattern_dest;
2416 gboolean underscore;
2418 g_return_if_fail (GTK_IS_LABEL (label));
2419 g_return_if_fail (str != NULL);
2421 /* Split text into the base text and a separate pattern
2425 new_str = g_new (gchar, strlen (str) + 1);
2426 pattern = g_new (gchar, g_utf8_strlen (str, -1) + 1);
2435 pattern_dest = pattern;
2442 c = g_utf8_get_char (src);
2443 if (c == (gunichar)-1)
2445 g_warning ("Invalid input string");
2450 next_src = g_utf8_next_char (src);
2455 *pattern_dest++ = ' ';
2458 *pattern_dest++ = '_';
2459 if (accel_key == GDK_VoidSymbol)
2460 accel_key = gdk_keyval_to_lower (gdk_unicode_to_keyval (c));
2463 while (src < next_src)
2477 while (src < next_src)
2480 *pattern_dest++ = ' ';
2487 gtk_label_set_text_internal (label, new_str);
2488 gtk_label_set_pattern_internal (label, pattern);
2492 label->mnemonic_keyval = accel_key;
2496 gtk_label_parse_uline (GtkLabel *label,
2502 g_return_val_if_fail (GTK_IS_LABEL (label), GDK_VoidSymbol);
2503 g_return_val_if_fail (str != NULL, GDK_VoidSymbol);
2505 orig_keyval = label->mnemonic_keyval;
2507 g_object_freeze_notify (G_OBJECT (label));
2509 gtk_label_set_label_internal (label, g_strdup (str ? str : ""));
2510 gtk_label_set_use_markup_internal (label, FALSE);
2511 gtk_label_set_use_underline_internal (label, TRUE);
2513 gtk_label_recalculate (label);
2515 keyval = label->mnemonic_keyval;
2516 label->mnemonic_keyval = GDK_VoidSymbol;
2518 gtk_label_setup_mnemonic (label, orig_keyval);
2520 g_object_thaw_notify (G_OBJECT (label));
2526 * gtk_label_set_text_with_mnemonic:
2527 * @label: a #GtkLabel
2530 * Sets the label's text from the string @str.
2531 * If characters in @str are preceded by an underscore, they are underlined
2532 * indicating that they represent a keyboard accelerator called a mnemonic.
2533 * The mnemonic key can be used to activate another widget, chosen automatically,
2534 * or explicitly using gtk_label_set_mnemonic_widget().
2537 gtk_label_set_text_with_mnemonic (GtkLabel *label,
2542 g_return_if_fail (GTK_IS_LABEL (label));
2543 g_return_if_fail (str != NULL);
2545 last_keyval = label->mnemonic_keyval;
2547 g_object_freeze_notify (G_OBJECT (label));
2549 gtk_label_set_label_internal (label, g_strdup (str ? str : ""));
2550 gtk_label_set_use_markup_internal (label, FALSE);
2551 gtk_label_set_use_underline_internal (label, TRUE);
2553 gtk_label_recalculate (label);
2555 gtk_label_setup_mnemonic (label, last_keyval);
2557 g_object_thaw_notify (G_OBJECT (label));
2561 gtk_label_realize (GtkWidget *widget)
2565 label = GTK_LABEL (widget);
2567 (* GTK_WIDGET_CLASS (parent_class)->realize) (widget);
2569 if (label->select_info)
2570 gtk_label_create_window (label);
2574 gtk_label_unrealize (GtkWidget *widget)
2578 label = GTK_LABEL (widget);
2580 if (label->select_info)
2581 gtk_label_destroy_window (label);
2583 (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
2587 gtk_label_map (GtkWidget *widget)
2591 label = GTK_LABEL (widget);
2593 (* GTK_WIDGET_CLASS (parent_class)->map) (widget);
2595 if (label->select_info)
2596 gdk_window_show (label->select_info->window);
2600 gtk_label_unmap (GtkWidget *widget)
2604 label = GTK_LABEL (widget);
2606 if (label->select_info)
2607 gdk_window_hide (label->select_info->window);
2609 (* GTK_WIDGET_CLASS (parent_class)->unmap) (widget);
2613 window_to_layout_coords (GtkLabel *label,
2620 widget = GTK_WIDGET (label);
2622 /* get layout location in widget->window coords */
2623 get_layout_location (label, &lx, &ly);
2627 *x += widget->allocation.x; /* go to widget->window */
2628 *x -= lx; /* go to layout */
2633 *y += widget->allocation.y; /* go to widget->window */
2634 *y -= ly; /* go to layout */
2640 layout_to_window_coords (GtkLabel *label,
2647 widget = GTK_WIDGET (label);
2649 /* get layout location in widget->window coords */
2650 get_layout_location (label, &lx, &ly);
2654 *x += lx; /* go to widget->window */
2655 *x -= widget->allocation.x; /* go to selection window */
2660 *y += ly; /* go to widget->window */
2661 *y -= widget->allocation.y; /* go to selection window */
2667 get_layout_index (GtkLabel *label,
2673 const gchar *cluster;
2674 const gchar *cluster_end;
2678 gtk_label_ensure_layout (label);
2680 window_to_layout_coords (label, &x, &y);
2685 pango_layout_xy_to_index (label->layout,
2690 cluster = label->text + *index;
2691 cluster_end = cluster;
2694 cluster_end = g_utf8_next_char (cluster_end);
2698 *index += (cluster_end - cluster);
2702 gtk_label_select_word (GtkLabel *label)
2706 gint start_index = gtk_label_move_backward_word (label, label->select_info->selection_end);
2707 gint end_index = gtk_label_move_forward_word (label, label->select_info->selection_end);
2709 min = MIN (label->select_info->selection_anchor,
2710 label->select_info->selection_end);
2711 max = MAX (label->select_info->selection_anchor,
2712 label->select_info->selection_end);
2714 min = MIN (min, start_index);
2715 max = MAX (max, end_index);
2717 gtk_label_select_region_index (label, min, max);
2721 gtk_label_button_press (GtkWidget *widget,
2722 GdkEventButton *event)
2728 label = GTK_LABEL (widget);
2730 if (label->select_info == NULL)
2733 label->select_info->in_drag = FALSE;
2734 if (event->button == 1)
2736 if (!GTK_WIDGET_HAS_FOCUS (widget))
2737 gtk_widget_grab_focus (widget);
2739 if (event->type == GDK_3BUTTON_PRESS)
2741 gtk_label_select_region_index (label, 0, strlen (label->text));
2745 if (event->type == GDK_2BUTTON_PRESS)
2747 gtk_label_select_word (label);
2751 get_layout_index (label, event->x, event->y, &index);
2753 min = MIN (label->select_info->selection_anchor,
2754 label->select_info->selection_end);
2755 max = MAX (label->select_info->selection_anchor,
2756 label->select_info->selection_end);
2758 if ((label->select_info->selection_anchor !=
2759 label->select_info->selection_end) &&
2760 (event->state & GDK_SHIFT_MASK))
2762 /* extend (same as motion) */
2763 min = MIN (min, index);
2764 max = MAX (max, index);
2766 /* ensure the anchor is opposite index */
2774 gtk_label_select_region_index (label, min, max);
2778 if (event->type == GDK_3BUTTON_PRESS)
2779 gtk_label_select_region_index (label, 0, strlen (label->text));
2780 else if (event->type == GDK_2BUTTON_PRESS)
2781 gtk_label_select_word (label);
2782 else if (min < max && min <= index && index <= max)
2784 label->select_info->in_drag = TRUE;
2785 label->select_info->drag_start_x = event->x;
2786 label->select_info->drag_start_y = event->y;
2789 /* start a replacement */
2790 gtk_label_select_region_index (label, index, index);
2795 else if (event->button == 3 && event->type == GDK_BUTTON_PRESS)
2797 gtk_label_do_popup (label, event);
2806 gtk_label_button_release (GtkWidget *widget,
2807 GdkEventButton *event)
2810 GtkLabel *label = GTK_LABEL (widget);
2813 if (label->select_info == NULL)
2816 if (label->select_info->in_drag)
2818 label->select_info->in_drag = 0;
2820 get_layout_index (label, event->x, event->y, &index);
2821 gtk_label_select_region_index (label, index, index);
2826 if (event->button != 1)
2829 /* The goal here is to return TRUE iff we ate the
2830 * button press to start selecting.
2837 gtk_label_motion (GtkWidget *widget,
2838 GdkEventMotion *event)
2844 label = GTK_LABEL (widget);
2846 if (label->select_info == NULL)
2850 if ((event->state & GDK_BUTTON1_MASK) == 0)
2853 gdk_window_get_pointer (label->select_info->window,
2856 if (label->select_info->in_drag)
2858 if (gtk_drag_check_threshold (widget,
2859 label->select_info->drag_start_x,
2860 label->select_info->drag_start_y,
2861 event->x, event->y))
2863 GdkDragContext *context;
2864 GtkTargetList *target_list = gtk_target_list_new (NULL, 0);
2866 gtk_target_list_add_text_targets (target_list, 0);
2868 context = gtk_drag_begin (widget, target_list,
2870 1, (GdkEvent *)event);
2873 label->select_info->in_drag = FALSE;
2875 gtk_target_list_unref (target_list);
2876 gtk_drag_set_icon_default (context);
2881 get_layout_index (label, x, y, &index);
2883 gtk_label_select_region_index (label,
2884 label->select_info->selection_anchor,
2892 gtk_label_create_window (GtkLabel *label)
2895 GdkWindowAttr attributes;
2896 gint attributes_mask;
2898 g_assert (label->select_info);
2899 g_assert (GTK_WIDGET_REALIZED (label));
2901 if (label->select_info->window)
2904 widget = GTK_WIDGET (label);
2906 attributes.x = widget->allocation.x;
2907 attributes.y = widget->allocation.y;
2908 attributes.width = widget->allocation.width;
2909 attributes.height = widget->allocation.height;
2910 attributes.window_type = GDK_WINDOW_TEMP;
2911 attributes.wclass = GDK_INPUT_ONLY;
2912 attributes.override_redirect = TRUE;
2913 attributes.cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget),
2915 attributes.event_mask = gtk_widget_get_events (widget) |
2916 GDK_BUTTON_PRESS_MASK |
2917 GDK_BUTTON_RELEASE_MASK |
2918 GDK_BUTTON_MOTION_MASK;
2920 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_NOREDIR | GDK_WA_CURSOR;
2922 label->select_info->window = gdk_window_new (widget->window,
2923 &attributes, attributes_mask);
2924 gdk_window_set_user_data (label->select_info->window, widget);
2926 gdk_cursor_unref (attributes.cursor);
2930 gtk_label_destroy_window (GtkLabel *label)
2932 g_assert (label->select_info);
2934 if (label->select_info->window == NULL)
2937 gdk_window_set_user_data (label->select_info->window, NULL);
2938 gdk_window_destroy (label->select_info->window);
2939 label->select_info->window = NULL;
2943 * gtk_label_set_selectable:
2944 * @label: a #GtkLabel
2945 * @setting: %TRUE to allow selecting text in the label
2947 * Selectable labels allow the user to select text from the label, for
2952 gtk_label_set_selectable (GtkLabel *label,
2955 gboolean old_setting;
2957 g_return_if_fail (GTK_IS_LABEL (label));
2959 setting = setting != FALSE;
2960 old_setting = label->select_info != NULL;
2964 if (label->select_info == NULL)
2966 label->select_info = g_new0 (GtkLabelSelectionInfo, 1);
2968 GTK_WIDGET_SET_FLAGS (label, GTK_CAN_FOCUS);
2970 if (GTK_WIDGET_REALIZED (label))
2971 gtk_label_create_window (label);
2973 if (GTK_WIDGET_MAPPED (label))
2974 gdk_window_show (label->select_info->window);
2979 if (label->select_info)
2981 /* unselect, to give up the selection */
2982 gtk_label_select_region (label, 0, 0);
2984 if (label->select_info->window)
2986 gtk_label_destroy_window (label);
2989 g_free (label->select_info);
2991 label->select_info = NULL;
2993 GTK_WIDGET_UNSET_FLAGS (label, GTK_CAN_FOCUS);
2996 if (setting != old_setting)
2998 g_object_freeze_notify (G_OBJECT (label));
2999 g_object_notify (G_OBJECT (label), "selectable");
3000 g_object_notify (G_OBJECT (label), "cursor_position");
3001 g_object_notify (G_OBJECT (label), "selection_bound");
3002 g_object_thaw_notify (G_OBJECT (label));
3003 gtk_widget_queue_draw (GTK_WIDGET (label));
3008 * gtk_label_get_selectable:
3009 * @label: a #GtkLabel
3011 * Gets the value set by gtk_label_set_selectable().
3013 * Return value: %TRUE if the user can copy text from the label
3016 gtk_label_get_selectable (GtkLabel *label)
3018 g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
3020 return label->select_info != NULL;
3024 * gtk_label_set_angle:
3025 * @label: a #GtkLabel
3026 * @angle: the angle that the baseline of the label makes with
3027 * the horizontal, in degrees, measured counterclockwise
3029 * Sets the angle of rotation for the label. An angle of 90 reads from
3030 * from bottom to top, an angle of 270, from top to bottom. The angle
3031 * setting for the label is ignored if the label is selectable,
3032 * wrapped, or ellipsized.
3037 gtk_label_set_angle (GtkLabel *label,
3040 GtkLabelPrivate *priv;
3042 g_return_if_fail (GTK_IS_LABEL (label));
3044 priv = GTK_LABEL_GET_PRIVATE (label);
3046 /* Canonicalize to [0,360]. We don't canonicalize 360 to 0, because
3047 * double property ranges are inclusive, and changing 360 to 0 would
3048 * make a property editor behave strangely.
3050 if (angle < 0 || angle > 360.0)
3051 angle = angle - 360. * floor (angle / 360.);
3053 if (angle != priv->angle)
3055 priv->angle = angle;
3057 gtk_label_clear_layout (label);
3058 gtk_widget_queue_resize (GTK_WIDGET (label));
3060 g_object_notify (G_OBJECT (label), "angle");
3065 * gtk_label_get_angle:
3066 * @label: a #GtkLabel
3068 * Gets the angle of rotation for the label. See
3069 * gtk_label_set_angle.
3071 * Return value: the angle of rotation for the label
3076 gtk_label_get_angle (GtkLabel *label)
3078 GtkLabelPrivate *priv;
3080 g_return_val_if_fail (GTK_IS_LABEL (label), 0.0);
3082 priv = GTK_LABEL_GET_PRIVATE (label);
3088 gtk_label_set_selection_text (GtkLabel *label,
3089 GtkSelectionData *selection_data)
3091 if ((label->select_info->selection_anchor !=
3092 label->select_info->selection_end) &&
3098 start = MIN (label->select_info->selection_anchor,
3099 label->select_info->selection_end);
3100 end = MAX (label->select_info->selection_anchor,
3101 label->select_info->selection_end);
3103 len = strlen (label->text);
3111 gtk_selection_data_set_text (selection_data,
3112 label->text + start,
3118 gtk_label_drag_data_get (GtkWidget *widget,
3119 GdkDragContext *context,
3120 GtkSelectionData *selection_data,
3124 gtk_label_set_selection_text (GTK_LABEL (widget), selection_data);
3128 get_text_callback (GtkClipboard *clipboard,
3129 GtkSelectionData *selection_data,
3131 gpointer user_data_or_owner)
3133 gtk_label_set_selection_text (GTK_LABEL (user_data_or_owner), selection_data);
3137 clear_text_callback (GtkClipboard *clipboard,
3138 gpointer user_data_or_owner)
3142 label = GTK_LABEL (user_data_or_owner);
3144 if (label->select_info)
3146 label->select_info->selection_anchor = label->select_info->selection_end;
3148 gtk_widget_queue_draw (GTK_WIDGET (label));
3153 gtk_label_select_region_index (GtkLabel *label,
3157 static const GtkTargetEntry targets[] = {
3160 { "COMPOUND_TEXT", 0, 0 },
3161 { "UTF8_STRING", 0, 0 }
3164 g_return_if_fail (GTK_IS_LABEL (label));
3166 if (label->select_info)
3168 GtkClipboard *clipboard;
3170 if (label->select_info->selection_anchor == anchor_index &&
3171 label->select_info->selection_end == end_index)
3174 label->select_info->selection_anchor = anchor_index;
3175 label->select_info->selection_end = end_index;
3177 clipboard = gtk_widget_get_clipboard (GTK_WIDGET (label),
3178 GDK_SELECTION_PRIMARY);
3180 if (anchor_index != end_index)
3182 gtk_clipboard_set_with_owner (clipboard,
3184 G_N_ELEMENTS (targets),
3186 clear_text_callback,
3191 if (gtk_clipboard_get_owner (clipboard) == G_OBJECT (label))
3192 gtk_clipboard_clear (clipboard);
3195 gtk_widget_queue_draw (GTK_WIDGET (label));
3197 g_object_freeze_notify (G_OBJECT (label));
3198 g_object_notify (G_OBJECT (label), "cursor_position");
3199 g_object_notify (G_OBJECT (label), "selection_bound");
3200 g_object_thaw_notify (G_OBJECT (label));
3205 * gtk_label_select_region:
3206 * @label: a #GtkLabel
3207 * @start_offset: start offset (in characters not bytes)
3208 * @end_offset: end offset (in characters not bytes)
3210 * Selects a range of characters in the label, if the label is selectable.
3211 * See gtk_label_set_selectable(). If the label is not selectable,
3212 * this function has no effect. If @start_offset or
3213 * @end_offset are -1, then the end of the label will be substituted.
3217 gtk_label_select_region (GtkLabel *label,
3221 g_return_if_fail (GTK_IS_LABEL (label));
3223 if (label->text && label->select_info)
3225 if (start_offset < 0)
3226 start_offset = g_utf8_strlen (label->text, -1);
3229 end_offset = g_utf8_strlen (label->text, -1);
3231 gtk_label_select_region_index (label,
3232 g_utf8_offset_to_pointer (label->text, start_offset) - label->text,
3233 g_utf8_offset_to_pointer (label->text, end_offset) - label->text);
3238 * gtk_label_get_selection_bounds:
3239 * @label: a #GtkLabel
3240 * @start: return location for start of selection, as a character offset
3241 * @end: return location for end of selection, as a character offset
3243 * Gets the selected range of characters in the label, returning %TRUE
3244 * if there's a selection.
3246 * Return value: %TRUE if selection is non-empty
3249 gtk_label_get_selection_bounds (GtkLabel *label,
3253 g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
3255 if (label->select_info == NULL)
3257 /* not a selectable label */
3267 gint start_index, end_index;
3268 gint start_offset, end_offset;
3271 start_index = MIN (label->select_info->selection_anchor,
3272 label->select_info->selection_end);
3273 end_index = MAX (label->select_info->selection_anchor,
3274 label->select_info->selection_end);
3276 len = strlen (label->text);
3278 if (end_index > len)
3281 if (start_index > len)
3284 start_offset = g_utf8_strlen (label->text, start_index);
3285 end_offset = g_utf8_strlen (label->text, end_index);
3287 if (start_offset > end_offset)
3289 gint tmp = start_offset;
3290 start_offset = end_offset;
3295 *start = start_offset;
3300 return start_offset != end_offset;
3306 * gtk_label_get_layout:
3307 * @label: a #GtkLabel
3309 * Gets the #PangoLayout used to display the label.
3310 * The layout is useful to e.g. convert text positions to
3311 * pixel positions, in combination with gtk_label_get_layout_offsets().
3312 * The returned layout is owned by the label so need not be
3313 * freed by the caller.
3315 * Return value: the #PangoLayout for this label
3318 gtk_label_get_layout (GtkLabel *label)
3320 g_return_val_if_fail (GTK_IS_LABEL (label), NULL);
3322 gtk_label_ensure_layout (label);
3324 return label->layout;
3328 * gtk_label_get_layout_offsets:
3329 * @label: a #GtkLabel
3330 * @x: location to store X offset of layout, or %NULL
3331 * @y: location to store Y offset of layout, or %NULL
3333 * Obtains the coordinates where the label will draw the #PangoLayout
3334 * representing the text in the label; useful to convert mouse events
3335 * into coordinates inside the #PangoLayout, e.g. to take some action
3336 * if some part of the label is clicked. Of course you will need to
3337 * create a #GtkEventBox to receive the events, and pack the label
3338 * inside it, since labels are a #GTK_NO_WINDOW widget. Remember
3339 * when using the #PangoLayout functions you need to convert to
3340 * and from pixels using PANGO_PIXELS() or #PANGO_SCALE.
3344 gtk_label_get_layout_offsets (GtkLabel *label,
3348 g_return_if_fail (GTK_IS_LABEL (label));
3350 get_layout_location (label, x, y);
3354 * gtk_label_set_use_markup:
3355 * @label: a #GtkLabel
3356 * @setting: %TRUE if the label's text should be parsed for markup.
3358 * Sets whether the text of the label contains markup in <link
3359 * linkend="PangoMarkupFormat">Pango's text markup
3360 * language</link>. See gtk_label_set_markup().
3363 gtk_label_set_use_markup (GtkLabel *label,
3366 g_return_if_fail (GTK_IS_LABEL (label));
3368 gtk_label_set_use_markup_internal (label, setting);
3369 gtk_label_recalculate (label);
3373 * gtk_label_get_use_markup:
3374 * @label: a #GtkLabel
3376 * Returns whether the label's text is interpreted as marked up with
3377 * the <link linkend="PangoMarkupFormat">Pango text markup
3378 * language</link>. See gtk_label_set_use_markup ().
3380 * Return value: %TRUE if the label's text will be parsed for markup.
3383 gtk_label_get_use_markup (GtkLabel *label)
3385 g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
3387 return label->use_markup;
3391 * gtk_label_set_use_underline:
3392 * @label: a #GtkLabel
3393 * @setting: %TRUE if underlines in the text indicate mnemonics
3395 * If true, an underline in the text indicates the next character should be
3396 * used for the mnemonic accelerator key.
3399 gtk_label_set_use_underline (GtkLabel *label,
3402 g_return_if_fail (GTK_IS_LABEL (label));
3404 gtk_label_set_use_underline_internal (label, setting);
3405 gtk_label_recalculate (label);
3406 if (label->use_underline)
3407 gtk_label_setup_mnemonic (label, label->mnemonic_keyval);
3411 * gtk_label_get_use_underline:
3412 * @label: a #GtkLabel
3414 * Returns whether an embedded underline in the label indicates a
3415 * mnemonic. See gtk_label_set_use_underline ().
3417 * Return value: %TRUE whether an embedded underline in the label indicates
3418 * the mnemonic accelerator keys.
3421 gtk_label_get_use_underline (GtkLabel *label)
3423 g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
3425 return label->use_underline;
3429 * gtk_label_set_single_line_mode:
3430 * @label: a #GtkLabel
3431 * @single_line_mode: %TRUE if the label should be in single line mode
3433 * Sets whether the label is in single line mode.
3438 gtk_label_set_single_line_mode (GtkLabel *label,
3439 gboolean single_line_mode)
3441 GtkLabelPrivate *priv;
3443 g_return_if_fail (GTK_IS_LABEL (label));
3445 single_line_mode = single_line_mode != FALSE;
3447 priv = GTK_LABEL_GET_PRIVATE (label);
3448 if (priv->single_line_mode != single_line_mode)
3450 priv->single_line_mode = single_line_mode;
3452 gtk_label_clear_layout (label);
3453 gtk_widget_queue_resize (GTK_WIDGET (label));
3455 g_object_notify (G_OBJECT (label), "single-line-mode");
3460 * gtk_label_get_single_line_mode:
3461 * @label: a #GtkLabel
3463 * Returns whether the label is in single line mode.
3465 * Return value: %TRUE when the label is in single line mode.
3470 gtk_label_get_single_line_mode (GtkLabel *label)
3472 GtkLabelPrivate *priv;
3474 g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
3476 priv = GTK_LABEL_GET_PRIVATE (label);
3478 return priv->single_line_mode;
3481 /* Compute the X position for an offset that corresponds to the "more important
3482 * cursor position for that offset. We use this when trying to guess to which
3483 * end of the selection we should go to when the user hits the left or
3487 get_better_cursor (GtkLabel *label,
3492 GdkKeymap *keymap = gdk_keymap_get_for_display (gtk_widget_get_display (GTK_WIDGET (label)));
3493 PangoDirection keymap_direction = gdk_keymap_get_direction (keymap);
3494 PangoDirection cursor_direction = get_cursor_direction (label);
3495 gboolean split_cursor;
3496 PangoRectangle strong_pos, weak_pos;
3498 g_object_get (gtk_widget_get_settings (GTK_WIDGET (label)),
3499 "gtk-split-cursor", &split_cursor,
3502 gtk_label_ensure_layout (label);
3504 pango_layout_get_cursor_pos (label->layout, index,
3505 &strong_pos, &weak_pos);
3509 *x = strong_pos.x / PANGO_SCALE;
3510 *y = strong_pos.y / PANGO_SCALE;
3514 if (keymap_direction == cursor_direction)
3516 *x = strong_pos.x / PANGO_SCALE;
3517 *y = strong_pos.y / PANGO_SCALE;
3521 *x = weak_pos.x / PANGO_SCALE;
3522 *y = weak_pos.y / PANGO_SCALE;
3529 gtk_label_move_logically (GtkLabel *label,
3533 gint offset = g_utf8_pointer_to_offset (label->text,
3534 label->text + start);
3538 PangoLogAttr *log_attrs;
3542 gtk_label_ensure_layout (label);
3544 length = g_utf8_strlen (label->text, -1);
3546 pango_layout_get_log_attrs (label->layout, &log_attrs, &n_attrs);
3548 while (count > 0 && offset < length)
3552 while (offset < length && !log_attrs[offset].is_cursor_position);
3556 while (count < 0 && offset > 0)
3560 while (offset > 0 && !log_attrs[offset].is_cursor_position);
3568 return g_utf8_offset_to_pointer (label->text, offset) - label->text;
3572 gtk_label_move_visually (GtkLabel *label,
3582 int new_index, new_trailing;
3583 gboolean split_cursor;
3586 gtk_label_ensure_layout (label);
3588 g_object_get (gtk_widget_get_settings (GTK_WIDGET (label)),
3589 "gtk-split-cursor", &split_cursor,
3596 GdkKeymap *keymap = gdk_keymap_get_for_display (gtk_widget_get_display (GTK_WIDGET (label)));
3597 PangoDirection keymap_direction = gdk_keymap_get_direction (keymap);
3599 strong = keymap_direction == get_cursor_direction (label);
3604 pango_layout_move_cursor_visually (label->layout, strong, index, 0, 1, &new_index, &new_trailing);
3609 pango_layout_move_cursor_visually (label->layout, strong, index, 0, -1, &new_index, &new_trailing);
3613 if (new_index < 0 || new_index == G_MAXINT)
3618 while (new_trailing--)
3619 index = g_utf8_next_char (label->text + new_index) - label->text;
3626 gtk_label_move_forward_word (GtkLabel *label,
3629 gint new_pos = g_utf8_pointer_to_offset (label->text,
3630 label->text + start);
3633 length = g_utf8_strlen (label->text, -1);
3634 if (new_pos < length)
3636 PangoLogAttr *log_attrs;
3639 gtk_label_ensure_layout (label);
3641 pango_layout_get_log_attrs (label->layout, &log_attrs, &n_attrs);
3643 /* Find the next word end */
3645 while (new_pos < n_attrs && !log_attrs[new_pos].is_word_end)
3651 return g_utf8_offset_to_pointer (label->text, new_pos) - label->text;
3656 gtk_label_move_backward_word (GtkLabel *label,
3659 gint new_pos = g_utf8_pointer_to_offset (label->text,
3660 label->text + start);
3663 length = g_utf8_strlen (label->text, -1);
3667 PangoLogAttr *log_attrs;
3670 gtk_label_ensure_layout (label);
3672 pango_layout_get_log_attrs (label->layout, &log_attrs, &n_attrs);
3676 /* Find the previous word beginning */
3677 while (new_pos > 0 && !log_attrs[new_pos].is_word_start)
3683 return g_utf8_offset_to_pointer (label->text, new_pos) - label->text;
3687 gtk_label_move_cursor (GtkLabel *label,
3688 GtkMovementStep step,
3690 gboolean extend_selection)
3694 if (label->select_info == NULL)
3697 new_pos = label->select_info->selection_end;
3699 if (label->select_info->selection_end != label->select_info->selection_anchor &&
3702 /* If we have a current selection and aren't extending it, move to the
3703 * start/or end of the selection as appropriate
3707 case GTK_MOVEMENT_VISUAL_POSITIONS:
3710 gint anchor_x, anchor_y;
3711 gboolean end_is_left;
3713 get_better_cursor (label, label->select_info->selection_end, &end_x, &end_y);
3714 get_better_cursor (label, label->select_info->selection_anchor, &anchor_x, &anchor_y);
3716 end_is_left = (end_y < anchor_y) || (end_y == anchor_y && end_x < anchor_x);
3719 new_pos = end_is_left ? label->select_info->selection_end : label->select_info->selection_anchor;
3721 new_pos = !end_is_left ? label->select_info->selection_end : label->select_info->selection_anchor;
3725 case GTK_MOVEMENT_LOGICAL_POSITIONS:
3726 case GTK_MOVEMENT_WORDS:
3728 new_pos = MIN (label->select_info->selection_end, label->select_info->selection_anchor);
3730 new_pos = MAX (label->select_info->selection_end, label->select_info->selection_anchor);
3732 case GTK_MOVEMENT_DISPLAY_LINE_ENDS:
3733 case GTK_MOVEMENT_PARAGRAPH_ENDS:
3734 case GTK_MOVEMENT_BUFFER_ENDS:
3735 /* FIXME: Can do better here */
3736 new_pos = count < 0 ? 0 : strlen (label->text);
3738 case GTK_MOVEMENT_DISPLAY_LINES:
3739 case GTK_MOVEMENT_PARAGRAPHS:
3740 case GTK_MOVEMENT_PAGES:
3741 case GTK_MOVEMENT_HORIZONTAL_PAGES:
3749 case GTK_MOVEMENT_LOGICAL_POSITIONS:
3750 new_pos = gtk_label_move_logically (label, new_pos, count);
3752 case GTK_MOVEMENT_VISUAL_POSITIONS:
3753 new_pos = gtk_label_move_visually (label, new_pos, count);
3755 case GTK_MOVEMENT_WORDS:
3758 new_pos = gtk_label_move_forward_word (label, new_pos);
3763 new_pos = gtk_label_move_backward_word (label, new_pos);
3767 case GTK_MOVEMENT_DISPLAY_LINE_ENDS:
3768 case GTK_MOVEMENT_PARAGRAPH_ENDS:
3769 case GTK_MOVEMENT_BUFFER_ENDS:
3770 /* FIXME: Can do better here */
3771 new_pos = count < 0 ? 0 : strlen (label->text);
3773 case GTK_MOVEMENT_DISPLAY_LINES:
3774 case GTK_MOVEMENT_PARAGRAPHS:
3775 case GTK_MOVEMENT_PAGES:
3776 case GTK_MOVEMENT_HORIZONTAL_PAGES:
3781 if (extend_selection)
3782 gtk_label_select_region_index (label,
3783 label->select_info->selection_anchor,
3786 gtk_label_select_region_index (label, new_pos, new_pos);
3790 gtk_label_copy_clipboard (GtkLabel *label)
3792 if (label->text && label->select_info)
3797 start = MIN (label->select_info->selection_anchor,
3798 label->select_info->selection_end);
3799 end = MAX (label->select_info->selection_anchor,
3800 label->select_info->selection_end);
3802 len = strlen (label->text);
3811 gtk_clipboard_set_text (gtk_widget_get_clipboard (GTK_WIDGET (label),
3812 GDK_SELECTION_CLIPBOARD),
3813 label->text + start, end - start);
3818 gtk_label_select_all (GtkLabel *label)
3820 gtk_label_select_region_index (label, 0, strlen (label->text));
3823 /* Quick hack of a popup menu
3826 activate_cb (GtkWidget *menuitem,
3829 const gchar *signal = g_object_get_data (G_OBJECT (menuitem), "gtk-signal");
3830 g_signal_emit_by_name (label, signal);
3834 append_action_signal (GtkLabel *label,
3836 const gchar *stock_id,
3837 const gchar *signal,
3840 GtkWidget *menuitem = gtk_image_menu_item_new_from_stock (stock_id, NULL);
3842 g_object_set_data (G_OBJECT (menuitem), "gtk-signal", (char *)signal);
3843 g_signal_connect (menuitem, "activate",
3844 G_CALLBACK (activate_cb), label);
3846 gtk_widget_set_sensitive (menuitem, sensitive);
3848 gtk_widget_show (menuitem);
3849 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
3853 popup_menu_detach (GtkWidget *attach_widget,
3857 label = GTK_LABEL (attach_widget);
3859 if (label->select_info)
3860 label->select_info->popup_menu = NULL;
3864 popup_position_func (GtkMenu *menu,
3875 label = GTK_LABEL (user_data);
3876 widget = GTK_WIDGET (label);
3878 if (label->select_info == NULL)
3881 g_return_if_fail (GTK_WIDGET_REALIZED (label));
3883 screen = gtk_widget_get_screen (widget);
3884 gdk_window_get_origin (widget->window, x, y);
3886 gtk_widget_size_request (label->select_info->popup_menu, &req);
3888 *x += widget->allocation.width / 2;
3889 *y += widget->allocation.height;
3891 *x = CLAMP (*x, 0, MAX (0, gdk_screen_get_width (screen) - req.width));
3892 *y = CLAMP (*y, 0, MAX (0, gdk_screen_get_height (screen) - req.height));
3897 gtk_label_do_popup (GtkLabel *label,
3898 GdkEventButton *event)
3900 GtkWidget *menuitem;
3901 gboolean have_selection;
3903 if (label->select_info == NULL)
3906 if (label->select_info->popup_menu)
3907 gtk_widget_destroy (label->select_info->popup_menu);
3909 label->select_info->popup_menu = gtk_menu_new ();
3911 gtk_menu_attach_to_widget (GTK_MENU (label->select_info->popup_menu),
3916 label->select_info->selection_anchor != label->select_info->selection_end;
3919 append_action_signal (label, label->select_info->popup_menu, GTK_STOCK_CUT, "cut_clipboard",
3921 append_action_signal (label, label->select_info->popup_menu, GTK_STOCK_COPY, "copy_clipboard",
3923 append_action_signal (label, label->select_info->popup_menu, GTK_STOCK_PASTE, "paste_clipboard",
3926 menuitem = gtk_image_menu_item_new_from_stock (GTK_STOCK_DELETE, NULL);
3927 gtk_widget_set_sensitive (menuitem, FALSE);
3928 gtk_widget_show (menuitem);
3929 gtk_menu_shell_append (GTK_MENU_SHELL (label->select_info->popup_menu), menuitem);
3931 menuitem = gtk_separator_menu_item_new ();
3932 gtk_widget_show (menuitem);
3933 gtk_menu_shell_append (GTK_MENU_SHELL (label->select_info->popup_menu), menuitem);
3935 menuitem = gtk_menu_item_new_with_label (_("Select All"));
3936 g_signal_connect_swapped (menuitem, "activate",
3937 G_CALLBACK (gtk_label_select_all), label);
3938 gtk_widget_show (menuitem);
3939 gtk_menu_shell_append (GTK_MENU_SHELL (label->select_info->popup_menu), menuitem);
3941 g_signal_emit (label,
3942 signals[POPULATE_POPUP],
3944 label->select_info->popup_menu);
3947 gtk_menu_popup (GTK_MENU (label->select_info->popup_menu), NULL, NULL,
3949 event->button, event->time);
3951 gtk_menu_popup (GTK_MENU (label->select_info->popup_menu), NULL, NULL,
3952 popup_position_func, label,
3953 0, gtk_get_current_event_time ());
3956 #define __GTK_LABEL_C__
3957 #include "gtkaliasdef.c"