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 "gtktextutil.h"
41 #include "gtkmenuitem.h"
42 #include "gtknotebook.h"
44 #include "gtkbindings.h"
45 #include "gtkprivate.h"
48 #define GTK_LABEL_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_LABEL, GtkLabelPrivate))
57 struct _GtkLabelSelectionInfo
60 gint selection_anchor;
62 GtkWidget *popup_menu;
93 PROP_SINGLE_LINE_MODE,
98 static guint signals[LAST_SIGNAL] = { 0 };
100 static void gtk_label_set_property (GObject *object,
104 static void gtk_label_get_property (GObject *object,
108 static void gtk_label_destroy (GtkObject *object);
109 static void gtk_label_finalize (GObject *object);
110 static void gtk_label_size_request (GtkWidget *widget,
111 GtkRequisition *requisition);
112 static void gtk_label_size_allocate (GtkWidget *widget,
113 GtkAllocation *allocation);
114 static void gtk_label_state_changed (GtkWidget *widget,
116 static void gtk_label_style_set (GtkWidget *widget,
117 GtkStyle *previous_style);
118 static void gtk_label_direction_changed (GtkWidget *widget,
119 GtkTextDirection previous_dir);
120 static gint gtk_label_expose (GtkWidget *widget,
121 GdkEventExpose *event);
123 static void gtk_label_realize (GtkWidget *widget);
124 static void gtk_label_unrealize (GtkWidget *widget);
125 static void gtk_label_map (GtkWidget *widget);
126 static void gtk_label_unmap (GtkWidget *widget);
128 static gboolean gtk_label_button_press (GtkWidget *widget,
129 GdkEventButton *event);
130 static gboolean gtk_label_button_release (GtkWidget *widget,
131 GdkEventButton *event);
132 static gboolean gtk_label_motion (GtkWidget *widget,
133 GdkEventMotion *event);
134 static void gtk_label_grab_focus (GtkWidget *widget);
137 static void gtk_label_set_text_internal (GtkLabel *label,
139 static void gtk_label_set_label_internal (GtkLabel *label,
141 static void gtk_label_set_use_markup_internal (GtkLabel *label,
143 static void gtk_label_set_use_underline_internal (GtkLabel *label,
145 static void gtk_label_set_attributes_internal (GtkLabel *label,
146 PangoAttrList *attrs);
147 static void gtk_label_set_uline_text_internal (GtkLabel *label,
149 static void gtk_label_set_pattern_internal (GtkLabel *label,
150 const gchar *pattern);
151 static void set_markup (GtkLabel *label,
153 gboolean with_uline);
154 static void gtk_label_recalculate (GtkLabel *label);
155 static void gtk_label_hierarchy_changed (GtkWidget *widget,
156 GtkWidget *old_toplevel);
157 static void gtk_label_screen_changed (GtkWidget *widget,
158 GdkScreen *old_screen);
160 static void gtk_label_create_window (GtkLabel *label);
161 static void gtk_label_destroy_window (GtkLabel *label);
162 static void gtk_label_clear_layout (GtkLabel *label);
163 static void gtk_label_ensure_layout (GtkLabel *label);
164 static void gtk_label_select_region_index (GtkLabel *label,
168 static gboolean gtk_label_mnemonic_activate (GtkWidget *widget,
169 gboolean group_cycling);
170 static void gtk_label_setup_mnemonic (GtkLabel *label,
172 static void gtk_label_drag_data_get (GtkWidget *widget,
173 GdkDragContext *context,
174 GtkSelectionData *selection_data,
179 /* For selectable lables: */
180 static void gtk_label_move_cursor (GtkLabel *label,
181 GtkMovementStep step,
183 gboolean extend_selection);
184 static void gtk_label_copy_clipboard (GtkLabel *label);
185 static void gtk_label_select_all (GtkLabel *label);
186 static void gtk_label_do_popup (GtkLabel *label,
187 GdkEventButton *event);
189 static gint gtk_label_move_forward_word (GtkLabel *label,
191 static gint gtk_label_move_backward_word (GtkLabel *label,
194 static GQuark quark_angle = 0;
196 G_DEFINE_TYPE (GtkLabel, gtk_label, GTK_TYPE_MISC)
199 add_move_binding (GtkBindingSet *binding_set,
202 GtkMovementStep step,
205 g_return_if_fail ((modmask & GDK_SHIFT_MASK) == 0);
207 gtk_binding_entry_add_signal (binding_set, keyval, modmask,
211 G_TYPE_BOOLEAN, FALSE);
213 /* Selection-extending version */
214 gtk_binding_entry_add_signal (binding_set, keyval, modmask | GDK_SHIFT_MASK,
218 G_TYPE_BOOLEAN, TRUE);
222 gtk_label_class_init (GtkLabelClass *class)
224 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
225 GtkObjectClass *object_class = GTK_OBJECT_CLASS (class);
226 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
227 GtkBindingSet *binding_set;
229 quark_angle = g_quark_from_static_string ("angle");
231 gobject_class->set_property = gtk_label_set_property;
232 gobject_class->get_property = gtk_label_get_property;
233 gobject_class->finalize = gtk_label_finalize;
235 object_class->destroy = gtk_label_destroy;
237 widget_class->size_request = gtk_label_size_request;
238 widget_class->size_allocate = gtk_label_size_allocate;
239 widget_class->state_changed = gtk_label_state_changed;
240 widget_class->style_set = gtk_label_style_set;
241 widget_class->direction_changed = gtk_label_direction_changed;
242 widget_class->expose_event = gtk_label_expose;
243 widget_class->realize = gtk_label_realize;
244 widget_class->unrealize = gtk_label_unrealize;
245 widget_class->map = gtk_label_map;
246 widget_class->unmap = gtk_label_unmap;
247 widget_class->button_press_event = gtk_label_button_press;
248 widget_class->button_release_event = gtk_label_button_release;
249 widget_class->motion_notify_event = gtk_label_motion;
250 widget_class->hierarchy_changed = gtk_label_hierarchy_changed;
251 widget_class->screen_changed = gtk_label_screen_changed;
252 widget_class->mnemonic_activate = gtk_label_mnemonic_activate;
253 widget_class->drag_data_get = gtk_label_drag_data_get;
254 widget_class->grab_focus = gtk_label_grab_focus;
256 class->move_cursor = gtk_label_move_cursor;
257 class->copy_clipboard = gtk_label_copy_clipboard;
259 signals[MOVE_CURSOR] =
260 g_signal_new (I_("move_cursor"),
261 G_OBJECT_CLASS_TYPE (gobject_class),
262 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
263 G_STRUCT_OFFSET (GtkLabelClass, move_cursor),
265 _gtk_marshal_VOID__ENUM_INT_BOOLEAN,
267 GTK_TYPE_MOVEMENT_STEP,
271 signals[COPY_CLIPBOARD] =
272 g_signal_new (I_("copy_clipboard"),
273 G_OBJECT_CLASS_TYPE (gobject_class),
274 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
275 G_STRUCT_OFFSET (GtkLabelClass, copy_clipboard),
277 _gtk_marshal_VOID__VOID,
280 signals[POPULATE_POPUP] =
281 g_signal_new (I_("populate_popup"),
282 G_OBJECT_CLASS_TYPE (gobject_class),
284 G_STRUCT_OFFSET (GtkLabelClass, populate_popup),
286 _gtk_marshal_VOID__OBJECT,
290 g_object_class_install_property (gobject_class,
292 g_param_spec_string ("label",
294 P_("The text of the label"),
296 GTK_PARAM_READWRITE));
297 g_object_class_install_property (gobject_class,
299 g_param_spec_boxed ("attributes",
301 P_("A list of style attributes to apply to the text of the label"),
302 PANGO_TYPE_ATTR_LIST,
303 GTK_PARAM_READWRITE));
304 g_object_class_install_property (gobject_class,
306 g_param_spec_boolean ("use-markup",
308 P_("The text of the label includes XML markup. See pango_parse_markup()"),
310 GTK_PARAM_READWRITE));
311 g_object_class_install_property (gobject_class,
313 g_param_spec_boolean ("use-underline",
315 P_("If set, an underline in the text indicates the next character should be used for the mnemonic accelerator key"),
317 GTK_PARAM_READWRITE));
319 g_object_class_install_property (gobject_class,
321 g_param_spec_enum ("justify",
323 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"),
324 GTK_TYPE_JUSTIFICATION,
326 GTK_PARAM_READWRITE));
328 g_object_class_install_property (gobject_class,
330 g_param_spec_string ("pattern",
332 P_("A string with _ characters in positions correspond to characters in the text to underline"),
334 GTK_PARAM_WRITABLE));
336 g_object_class_install_property (gobject_class,
338 g_param_spec_boolean ("wrap",
340 P_("If set, wrap lines if the text becomes too wide"),
342 GTK_PARAM_READWRITE));
343 g_object_class_install_property (gobject_class,
345 g_param_spec_boolean ("selectable",
347 P_("Whether the label text can be selected with the mouse"),
349 GTK_PARAM_READWRITE));
350 g_object_class_install_property (gobject_class,
351 PROP_MNEMONIC_KEYVAL,
352 g_param_spec_uint ("mnemonic-keyval",
354 P_("The mnemonic accelerator key for this label"),
358 GTK_PARAM_READABLE));
359 g_object_class_install_property (gobject_class,
360 PROP_MNEMONIC_WIDGET,
361 g_param_spec_object ("mnemonic-widget",
362 P_("Mnemonic widget"),
363 P_("The widget to be activated when the label's mnemonic "
366 GTK_PARAM_READWRITE));
368 g_object_class_install_property (gobject_class,
369 PROP_CURSOR_POSITION,
370 g_param_spec_int ("cursor-position",
371 P_("Cursor Position"),
372 P_("The current position of the insertion cursor in chars"),
376 GTK_PARAM_READABLE));
378 g_object_class_install_property (gobject_class,
379 PROP_SELECTION_BOUND,
380 g_param_spec_int ("selection-bound",
381 P_("Selection Bound"),
382 P_("The position of the opposite end of the selection from the cursor in chars"),
386 GTK_PARAM_READABLE));
389 * GtkLabel:ellipsize:
391 * The preferred place to ellipsize the string, if the label does not have
392 * enough room to display the entire string, specified as a #PangoEllisizeMode.
394 * Note that setting this property to a value other than %PANGO_ELLIPSIZE_NONE
395 * has the side-effect that the label requests only enough space to display the
396 * ellipsis "...". In particular, this means that ellipsizing labels don't
397 * work well in notebook tabs, unless the tab's ::tab-expand property is set
398 * to %TRUE. Other means to set a label's width are
399 * gtk_widget_set_size_request() and gtk_label_set_width_chars().
403 g_object_class_install_property (gobject_class,
405 g_param_spec_enum ("ellipsize",
407 P_("The preferred place to ellipsize the string, if the label does not have enough room to display the entire string"),
408 PANGO_TYPE_ELLIPSIZE_MODE,
409 PANGO_ELLIPSIZE_NONE,
410 GTK_PARAM_READWRITE));
413 * GtkLabel:width-chars:
415 * The desired width of the label, in characters. If this property is set to
416 * -1, the width will be calculated automatically, otherwise the label will
417 * request either 3 characters or the property value, whichever is greater.
418 * If the width-chars property is set to a positive value, then the
419 * max-width-chars property is ignored.
423 g_object_class_install_property (gobject_class,
425 g_param_spec_int ("width-chars",
426 P_("Width In Characters"),
427 P_("The desired width of the label, in characters"),
431 GTK_PARAM_READWRITE));
434 * GtkLabel:single-line-mode:
436 * Whether the label is in single line mode. In single line mode,
437 * the height of the label does not depend on the actual text, it
438 * is always set to ascent + descent of the font. This can be an
439 * advantage in situations where resizing the label because of text
440 * changes would be distracting, e.g. in a statusbar.
444 g_object_class_install_property (gobject_class,
445 PROP_SINGLE_LINE_MODE,
446 g_param_spec_boolean ("single-line-mode",
447 P_("Single Line Mode"),
448 P_("Whether the label is in single line mode"),
450 GTK_PARAM_READWRITE));
455 * The angle that the baseline of the label makes with the horizontal,
456 * in degrees, measured counterclockwise. An angle of 90 reads from
457 * from bottom to top, an angle of 270, from top to bottom. Ignored
458 * if the label is selectable, wrapped, or ellipsized.
462 g_object_class_install_property (gobject_class,
464 g_param_spec_double ("angle",
466 P_("Angle at which the label is rotated"),
470 GTK_PARAM_READWRITE));
473 * GtkLabel:max-width-chars:
475 * The desired maximum width of the label, in characters. If this property
476 * is set to -1, the width will be calculated automatically, otherwise the
477 * label will request space for no more than the requested number of
478 * characters. If the width-chars property is set to a positive value,
479 * then the max-width-chars property is ignored.
483 g_object_class_install_property (gobject_class,
484 PROP_MAX_WIDTH_CHARS,
485 g_param_spec_int ("max-width-chars",
486 P_("Maximum Width In Characters"),
487 P_("The desired maximum width of the label, in characters"),
491 GTK_PARAM_READWRITE));
496 binding_set = gtk_binding_set_by_class (class);
498 /* Moving the insertion point */
499 add_move_binding (binding_set, GDK_Right, 0,
500 GTK_MOVEMENT_VISUAL_POSITIONS, 1);
502 add_move_binding (binding_set, GDK_Left, 0,
503 GTK_MOVEMENT_VISUAL_POSITIONS, -1);
505 add_move_binding (binding_set, GDK_KP_Right, 0,
506 GTK_MOVEMENT_VISUAL_POSITIONS, 1);
508 add_move_binding (binding_set, GDK_KP_Left, 0,
509 GTK_MOVEMENT_VISUAL_POSITIONS, -1);
511 add_move_binding (binding_set, GDK_f, GDK_CONTROL_MASK,
512 GTK_MOVEMENT_LOGICAL_POSITIONS, 1);
514 add_move_binding (binding_set, GDK_b, GDK_CONTROL_MASK,
515 GTK_MOVEMENT_LOGICAL_POSITIONS, -1);
517 add_move_binding (binding_set, GDK_Right, GDK_CONTROL_MASK,
518 GTK_MOVEMENT_WORDS, 1);
520 add_move_binding (binding_set, GDK_Left, GDK_CONTROL_MASK,
521 GTK_MOVEMENT_WORDS, -1);
523 add_move_binding (binding_set, GDK_KP_Right, GDK_CONTROL_MASK,
524 GTK_MOVEMENT_WORDS, 1);
526 add_move_binding (binding_set, GDK_KP_Left, GDK_CONTROL_MASK,
527 GTK_MOVEMENT_WORDS, -1);
530 gtk_binding_entry_add_signal (binding_set, GDK_a, GDK_CONTROL_MASK,
532 G_TYPE_ENUM, GTK_MOVEMENT_PARAGRAPH_ENDS,
534 G_TYPE_BOOLEAN, FALSE);
536 gtk_binding_entry_add_signal (binding_set, GDK_a, GDK_CONTROL_MASK,
538 G_TYPE_ENUM, GTK_MOVEMENT_PARAGRAPH_ENDS,
540 G_TYPE_BOOLEAN, TRUE);
542 gtk_binding_entry_add_signal (binding_set, GDK_slash, GDK_CONTROL_MASK,
544 G_TYPE_ENUM, GTK_MOVEMENT_PARAGRAPH_ENDS,
546 G_TYPE_BOOLEAN, FALSE);
548 gtk_binding_entry_add_signal (binding_set, GDK_slash, GDK_CONTROL_MASK,
550 G_TYPE_ENUM, GTK_MOVEMENT_PARAGRAPH_ENDS,
552 G_TYPE_BOOLEAN, TRUE);
555 gtk_binding_entry_add_signal (binding_set, GDK_a, GDK_SHIFT_MASK | GDK_CONTROL_MASK,
557 G_TYPE_ENUM, GTK_MOVEMENT_PARAGRAPH_ENDS,
559 G_TYPE_BOOLEAN, FALSE);
561 gtk_binding_entry_add_signal (binding_set, GDK_backslash, GDK_CONTROL_MASK,
563 G_TYPE_ENUM, GTK_MOVEMENT_PARAGRAPH_ENDS,
565 G_TYPE_BOOLEAN, FALSE);
567 add_move_binding (binding_set, GDK_f, GDK_MOD1_MASK,
568 GTK_MOVEMENT_WORDS, 1);
570 add_move_binding (binding_set, GDK_b, GDK_MOD1_MASK,
571 GTK_MOVEMENT_WORDS, -1);
573 add_move_binding (binding_set, GDK_Home, 0,
574 GTK_MOVEMENT_DISPLAY_LINE_ENDS, -1);
576 add_move_binding (binding_set, GDK_End, 0,
577 GTK_MOVEMENT_DISPLAY_LINE_ENDS, 1);
579 add_move_binding (binding_set, GDK_KP_Home, 0,
580 GTK_MOVEMENT_DISPLAY_LINE_ENDS, -1);
582 add_move_binding (binding_set, GDK_KP_End, 0,
583 GTK_MOVEMENT_DISPLAY_LINE_ENDS, 1);
585 add_move_binding (binding_set, GDK_Home, GDK_CONTROL_MASK,
586 GTK_MOVEMENT_BUFFER_ENDS, -1);
588 add_move_binding (binding_set, GDK_End, GDK_CONTROL_MASK,
589 GTK_MOVEMENT_BUFFER_ENDS, 1);
591 add_move_binding (binding_set, GDK_KP_Home, GDK_CONTROL_MASK,
592 GTK_MOVEMENT_BUFFER_ENDS, -1);
594 add_move_binding (binding_set, GDK_KP_End, GDK_CONTROL_MASK,
595 GTK_MOVEMENT_BUFFER_ENDS, 1);
598 gtk_binding_entry_add_signal (binding_set, GDK_c, GDK_CONTROL_MASK,
599 "copy_clipboard", 0);
601 gtk_settings_install_property (g_param_spec_boolean ("gtk-label-select-on-focus",
602 P_("Select on focus"),
603 P_("Whether to select the contents of a selectable label when it is focused"),
605 GTK_PARAM_READWRITE));
608 g_type_class_add_private (class, sizeof (GtkLabelPrivate));
612 gtk_label_set_property (GObject *object,
619 label = GTK_LABEL (object);
624 gtk_label_set_label (label, g_value_get_string (value));
626 case PROP_ATTRIBUTES:
627 gtk_label_set_attributes (label, g_value_get_boxed (value));
629 case PROP_USE_MARKUP:
630 gtk_label_set_use_markup (label, g_value_get_boolean (value));
632 case PROP_USE_UNDERLINE:
633 gtk_label_set_use_underline (label, g_value_get_boolean (value));
636 gtk_label_set_justify (label, g_value_get_enum (value));
639 gtk_label_set_pattern (label, g_value_get_string (value));
642 gtk_label_set_line_wrap (label, g_value_get_boolean (value));
644 case PROP_SELECTABLE:
645 gtk_label_set_selectable (label, g_value_get_boolean (value));
647 case PROP_MNEMONIC_WIDGET:
648 gtk_label_set_mnemonic_widget (label, (GtkWidget*) g_value_get_object (value));
651 gtk_label_set_ellipsize (label, g_value_get_enum (value));
653 case PROP_WIDTH_CHARS:
654 gtk_label_set_width_chars (label, g_value_get_int (value));
656 case PROP_SINGLE_LINE_MODE:
657 gtk_label_set_single_line_mode (label, g_value_get_boolean (value));
660 gtk_label_set_angle (label, g_value_get_double (value));
662 case PROP_MAX_WIDTH_CHARS:
663 gtk_label_set_max_width_chars (label, g_value_get_int (value));
666 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
672 gtk_label_get_property (GObject *object,
679 label = GTK_LABEL (object);
684 g_value_set_string (value, label->label);
686 case PROP_ATTRIBUTES:
687 g_value_set_boxed (value, label->attrs);
689 case PROP_USE_MARKUP:
690 g_value_set_boolean (value, label->use_markup);
692 case PROP_USE_UNDERLINE:
693 g_value_set_boolean (value, label->use_underline);
696 g_value_set_enum (value, label->jtype);
699 g_value_set_boolean (value, label->wrap);
701 case PROP_SELECTABLE:
702 g_value_set_boolean (value, gtk_label_get_selectable (label));
704 case PROP_MNEMONIC_KEYVAL:
705 g_value_set_uint (value, label->mnemonic_keyval);
707 case PROP_MNEMONIC_WIDGET:
708 g_value_set_object (value, (GObject*) label->mnemonic_widget);
710 case PROP_CURSOR_POSITION:
711 if (label->select_info)
713 gint offset = g_utf8_pointer_to_offset (label->text,
714 label->text + label->select_info->selection_end);
715 g_value_set_int (value, offset);
718 g_value_set_int (value, 0);
720 case PROP_SELECTION_BOUND:
721 if (label->select_info)
723 gint offset = g_utf8_pointer_to_offset (label->text,
724 label->text + label->select_info->selection_anchor);
725 g_value_set_int (value, offset);
728 g_value_set_int (value, 0);
731 g_value_set_enum (value, label->ellipsize);
733 case PROP_WIDTH_CHARS:
734 g_value_set_int (value, gtk_label_get_width_chars (label));
736 case PROP_SINGLE_LINE_MODE:
737 g_value_set_boolean (value, gtk_label_get_single_line_mode (label));
740 g_value_set_double (value, gtk_label_get_angle (label));
742 case PROP_MAX_WIDTH_CHARS:
743 g_value_set_int (value, gtk_label_get_max_width_chars (label));
747 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
753 gtk_label_init (GtkLabel *label)
755 GtkLabelPrivate *priv;
757 GTK_WIDGET_SET_FLAGS (label, GTK_NO_WINDOW);
759 priv = GTK_LABEL_GET_PRIVATE (label);
760 priv->width_chars = -1;
761 priv->max_width_chars = -1;
764 label->jtype = GTK_JUSTIFY_LEFT;
766 label->ellipsize = PANGO_ELLIPSIZE_NONE;
768 label->use_underline = FALSE;
769 label->use_markup = FALSE;
771 label->mnemonic_keyval = GDK_VoidSymbol;
772 label->layout = NULL;
776 label->mnemonic_widget = NULL;
777 label->mnemonic_window = NULL;
779 gtk_label_set_text (label, "");
784 * @str: The text of the label
786 * Creates a new label with the given text inside it. You can
787 * pass %NULL to get an empty label widget.
789 * Return value: the new #GtkLabel
792 gtk_label_new (const gchar *str)
796 label = g_object_new (GTK_TYPE_LABEL, NULL);
799 gtk_label_set_text (label, str);
801 return GTK_WIDGET (label);
805 * gtk_label_new_with_mnemonic:
806 * @str: The text of the label, with an underscore in front of the
809 * Creates a new #GtkLabel, containing the text in @str.
811 * If characters in @str are preceded by an underscore, they are
812 * underlined. If you need a literal underscore character in a label, use
813 * '__' (two underscores). The first underlined character represents a
814 * keyboard accelerator called a mnemonic. The mnemonic key can be used
815 * to activate another widget, chosen automatically, or explicitly using
816 * gtk_label_set_mnemonic_widget().
818 * If gtk_label_set_mnemonic_widget()
819 * is not called, then the first activatable ancestor of the #GtkLabel
820 * will be chosen as the mnemonic widget. For instance, if the
821 * label is inside a button or menu item, the button or menu item will
822 * automatically become the mnemonic widget and be activated by
825 * Return value: the new #GtkLabel
828 gtk_label_new_with_mnemonic (const gchar *str)
832 label = g_object_new (GTK_TYPE_LABEL, NULL);
835 gtk_label_set_text_with_mnemonic (label, str);
837 return GTK_WIDGET (label);
841 gtk_label_mnemonic_activate (GtkWidget *widget,
842 gboolean group_cycling)
846 if (GTK_LABEL (widget)->mnemonic_widget)
847 return gtk_widget_mnemonic_activate (GTK_LABEL (widget)->mnemonic_widget, group_cycling);
849 /* Try to find the widget to activate by traversing the
852 parent = widget->parent;
854 if (parent && GTK_IS_NOTEBOOK (parent))
859 if (GTK_WIDGET_CAN_FOCUS (parent) ||
860 (!group_cycling && GTK_WIDGET_GET_CLASS (parent)->activate_signal) ||
861 (parent->parent && GTK_IS_NOTEBOOK (parent->parent)) ||
862 (GTK_IS_MENU_ITEM (parent)))
863 return gtk_widget_mnemonic_activate (parent, group_cycling);
864 parent = parent->parent;
867 /* barf if there was nothing to activate */
868 g_warning ("Couldn't find a target for a mnemonic activation.");
869 gdk_display_beep (gtk_widget_get_display (widget));
875 gtk_label_setup_mnemonic (GtkLabel *label,
878 GtkWidget *widget = GTK_WIDGET (label);
880 GtkWidget *mnemonic_menu;
882 mnemonic_menu = g_object_get_data (G_OBJECT (label), "gtk-mnemonic-menu");
884 if (last_key != GDK_VoidSymbol)
886 if (label->mnemonic_window)
888 gtk_window_remove_mnemonic (label->mnemonic_window,
891 label->mnemonic_window = NULL;
895 _gtk_menu_shell_remove_mnemonic (GTK_MENU_SHELL (mnemonic_menu),
898 mnemonic_menu = NULL;
902 if (label->mnemonic_keyval == GDK_VoidSymbol)
905 toplevel = gtk_widget_get_toplevel (widget);
906 if (GTK_WIDGET_TOPLEVEL (toplevel))
908 GtkWidget *menu_shell;
910 menu_shell = gtk_widget_get_ancestor (widget,
911 GTK_TYPE_MENU_SHELL);
915 _gtk_menu_shell_add_mnemonic (GTK_MENU_SHELL (menu_shell),
916 label->mnemonic_keyval,
918 mnemonic_menu = menu_shell;
921 if (!(menu_shell && GTK_IS_MENU (menu_shell)))
923 gtk_window_add_mnemonic (GTK_WINDOW (toplevel),
924 label->mnemonic_keyval,
926 label->mnemonic_window = GTK_WINDOW (toplevel);
931 g_object_set_data (G_OBJECT (label), I_("gtk-mnemonic-menu"), mnemonic_menu);
935 gtk_label_hierarchy_changed (GtkWidget *widget,
936 GtkWidget *old_toplevel)
938 GtkLabel *label = GTK_LABEL (widget);
940 gtk_label_setup_mnemonic (label, label->mnemonic_keyval);
944 gtk_label_screen_changed (GtkWidget *widget,
945 GdkScreen *old_screen)
947 gtk_label_clear_layout (GTK_LABEL (widget));
951 label_mnemonic_widget_weak_notify (gpointer data,
952 GObject *where_the_object_was)
954 GtkLabel *label = data;
956 label->mnemonic_widget = NULL;
957 g_object_notify (G_OBJECT (label), "mnemonic-widget");
961 * gtk_label_set_mnemonic_widget:
962 * @label: a #GtkLabel
963 * @widget: the target #GtkWidget
965 * If the label has been set so that it has an mnemonic key (using
966 * i.e. gtk_label_set_markup_with_mnemonic(),
967 * gtk_label_set_text_with_mnemonic(), gtk_label_new_with_mnemonic()
968 * or the "use_underline" property) the label can be associated with a
969 * widget that is the target of the mnemonic. When the label is inside
970 * a widget (like a #GtkButton or a #GtkNotebook tab) it is
971 * automatically associated with the correct widget, but sometimes
972 * (i.e. when the target is a #GtkEntry next to the label) you need to
973 * set it explicitly using this function.
975 * The target widget will be accelerated by emitting "mnemonic_activate" on it.
976 * The default handler for this signal will activate the widget if there are no
977 * mnemonic collisions and toggle focus between the colliding widgets otherwise.
980 gtk_label_set_mnemonic_widget (GtkLabel *label,
983 g_return_if_fail (GTK_IS_LABEL (label));
985 g_return_if_fail (GTK_IS_WIDGET (widget));
987 if (label->mnemonic_widget)
989 gtk_widget_remove_mnemonic_label (label->mnemonic_widget, GTK_WIDGET (label));
990 g_object_weak_unref (G_OBJECT (label->mnemonic_widget),
991 label_mnemonic_widget_weak_notify,
994 label->mnemonic_widget = widget;
995 if (label->mnemonic_widget)
997 g_object_weak_ref (G_OBJECT (label->mnemonic_widget),
998 label_mnemonic_widget_weak_notify,
1000 gtk_widget_add_mnemonic_label (label->mnemonic_widget, GTK_WIDGET (label));
1003 g_object_notify (G_OBJECT (label), "mnemonic-widget");
1007 * gtk_label_get_mnemonic_widget:
1008 * @label: a #GtkLabel
1010 * Retrieves the target of the mnemonic (keyboard shortcut) of this
1011 * label. See gtk_label_set_mnemonic_widget ().
1013 * Return value: the target of the label's mnemonic, or %NULL if none
1014 * has been set and the default algorithm will be used.
1017 gtk_label_get_mnemonic_widget (GtkLabel *label)
1019 g_return_val_if_fail (GTK_IS_LABEL (label), NULL);
1021 return label->mnemonic_widget;
1025 * gtk_label_get_mnemonic_keyval:
1026 * @label: a #GtkLabel
1028 * If the label has been set so that it has an mnemonic key this function
1029 * returns the keyval used for the mnemonic accelerator. If there is no
1030 * mnemonic set up it returns #GDK_VoidSymbol.
1032 * Returns: GDK keyval usable for accelerators, or #GDK_VoidSymbol
1035 gtk_label_get_mnemonic_keyval (GtkLabel *label)
1037 g_return_val_if_fail (GTK_IS_LABEL (label), GDK_VoidSymbol);
1039 return label->mnemonic_keyval;
1043 gtk_label_set_text_internal (GtkLabel *label,
1046 g_free (label->text);
1050 gtk_label_select_region_index (label, 0, 0);
1054 gtk_label_set_label_internal (GtkLabel *label,
1057 g_free (label->label);
1061 g_object_notify (G_OBJECT (label), "label");
1065 gtk_label_set_use_markup_internal (GtkLabel *label,
1069 if (label->use_markup != val)
1071 label->use_markup = val;
1073 g_object_notify (G_OBJECT (label), "use-markup");
1078 gtk_label_set_use_underline_internal (GtkLabel *label,
1082 if (label->use_underline != val)
1084 label->use_underline = val;
1086 g_object_notify (G_OBJECT (label), "use-underline");
1091 gtk_label_set_attributes_internal (GtkLabel *label,
1092 PangoAttrList *attrs)
1095 pango_attr_list_ref (attrs);
1098 pango_attr_list_unref (label->attrs);
1100 if (!label->use_markup && !label->use_underline)
1103 pango_attr_list_ref (attrs);
1104 if (label->effective_attrs)
1105 pango_attr_list_unref (label->effective_attrs);
1106 label->effective_attrs = attrs;
1109 label->attrs = attrs;
1110 g_object_notify (G_OBJECT (label), "attributes");
1114 /* Calculates text, attrs and mnemonic_keyval from
1115 * label, use_underline and use_markup
1118 gtk_label_recalculate (GtkLabel *label)
1120 if (label->use_markup)
1121 set_markup (label, label->label, label->use_underline);
1124 if (label->use_underline)
1125 gtk_label_set_uline_text_internal (label, label->label);
1128 gtk_label_set_text_internal (label, g_strdup (label->label));
1130 pango_attr_list_ref (label->attrs);
1131 if (label->effective_attrs)
1132 pango_attr_list_unref (label->effective_attrs);
1133 label->effective_attrs = label->attrs;
1137 if (!label->use_underline)
1139 guint keyval = label->mnemonic_keyval;
1141 label->mnemonic_keyval = GDK_VoidSymbol;
1142 gtk_label_setup_mnemonic (label, keyval);
1145 gtk_label_clear_layout (label);
1146 gtk_widget_queue_resize (GTK_WIDGET (label));
1150 * gtk_label_set_text:
1151 * @label: a #GtkLabel
1152 * @str: The text you want to set.
1154 * Sets the text within the #GtkLabel widget. It overwrites any text that
1157 * This will also clear any previously set mnemonic accelerators.
1160 gtk_label_set_text (GtkLabel *label,
1163 g_return_if_fail (GTK_IS_LABEL (label));
1165 g_object_freeze_notify (G_OBJECT (label));
1167 gtk_label_set_label_internal (label, g_strdup (str ? str : ""));
1168 gtk_label_set_use_markup_internal (label, FALSE);
1169 gtk_label_set_use_underline_internal (label, FALSE);
1171 gtk_label_recalculate (label);
1173 g_object_thaw_notify (G_OBJECT (label));
1177 * gtk_label_set_attributes:
1178 * @label: a #GtkLabel
1179 * @attrs: a #PangoAttrList
1181 * Sets a #PangoAttrList; the attributes in the list are applied to the
1182 * label text. The attributes set with this function will be ignored
1183 * if the "use_underline" property or the "use_markup" property
1187 gtk_label_set_attributes (GtkLabel *label,
1188 PangoAttrList *attrs)
1190 g_return_if_fail (GTK_IS_LABEL (label));
1192 gtk_label_set_attributes_internal (label, attrs);
1194 gtk_label_clear_layout (label);
1195 gtk_widget_queue_resize (GTK_WIDGET (label));
1199 * gtk_label_get_attributes:
1200 * @label: a #GtkLabel
1202 * Gets the attribute list that was set on the label using
1203 * gtk_label_set_attributes(), if any. This function does
1204 * not reflect attributes that come from the labels markup
1205 * (see gtk_label_set_markup()). If you want to get the
1206 * effective attributes for the label, use
1207 * pango_layout_get_attribute (gtk_label_get_layout (label)).
1209 * Return value: the attribute list, or %NULL if none was set.
1212 gtk_label_get_attributes (GtkLabel *label)
1214 g_return_val_if_fail (GTK_IS_LABEL (label), NULL);
1216 return label->attrs;
1220 * gtk_label_set_label:
1221 * @label: a #GtkLabel
1222 * @str: the new text to set for the label
1224 * Sets the text of the label. The label is interpreted as
1225 * including embedded underlines and/or Pango markup depending
1226 * on the values of label->use_underline and label->use_markup.
1229 gtk_label_set_label (GtkLabel *label,
1234 g_return_if_fail (GTK_IS_LABEL (label));
1235 g_return_if_fail (str != NULL);
1237 last_keyval = label->mnemonic_keyval;
1239 gtk_label_set_label_internal (label, g_strdup (str));
1240 gtk_label_recalculate (label);
1241 if (last_keyval != label->mnemonic_keyval)
1242 gtk_label_setup_mnemonic (label, last_keyval);
1246 * gtk_label_get_label:
1247 * @label: a #GtkLabel
1249 * Fetches the text from a label widget including any embedded
1250 * underlines indicating mnemonics and Pango markup. (See
1251 * gtk_label_get_text ()).
1253 * Return value: the text of the label widget. This string is
1254 * owned by the widget and must not be modified or freed.
1256 G_CONST_RETURN gchar *
1257 gtk_label_get_label (GtkLabel *label)
1259 g_return_val_if_fail (GTK_IS_LABEL (label), NULL);
1261 return label->label;
1265 set_markup (GtkLabel *label,
1267 gboolean with_uline)
1270 GError *error = NULL;
1271 PangoAttrList *attrs = NULL;
1272 gunichar accel_char = 0;
1274 if (!pango_parse_markup (str,
1276 with_uline ? '_' : 0,
1279 with_uline ? &accel_char : NULL,
1282 g_warning ("Failed to set label from markup due to error parsing markup: %s",
1284 g_error_free (error);
1289 gtk_label_set_text_internal (label, text);
1293 if (label->effective_attrs)
1294 pango_attr_list_unref (label->effective_attrs);
1295 label->effective_attrs = attrs;
1298 if (accel_char != 0)
1299 label->mnemonic_keyval = gdk_keyval_to_lower (gdk_unicode_to_keyval (accel_char));
1301 label->mnemonic_keyval = GDK_VoidSymbol;
1305 * gtk_label_set_markup:
1306 * @label: a #GtkLabel
1307 * @str: a markup string (see <link linkend="PangoMarkupFormat">Pango markup format</link>)
1309 * Parses @str which is marked up with the <link
1310 * linkend="PangoMarkupFormat">Pango text markup language</link>, setting the
1311 * label's text and attribute list based on the parse results. If the @str is
1312 * external data, you may need to escape it with g_markup_escape_text() or
1313 * g_markup_printf_escaped()<!-- -->:
1314 * <informalexample><programlisting>
1317 * markup = g_markup_printf_escaped ("<span style=\"italic\">%s</span>", str);
1318 * gtk_label_set_markup (GTK_LABEL (label), markup);
1320 * </programlisting></informalexample>
1323 gtk_label_set_markup (GtkLabel *label,
1326 g_return_if_fail (GTK_IS_LABEL (label));
1328 g_object_freeze_notify (G_OBJECT (label));
1330 gtk_label_set_label_internal (label, g_strdup (str ? str : ""));
1331 gtk_label_set_use_markup_internal (label, TRUE);
1332 gtk_label_set_use_underline_internal (label, FALSE);
1334 gtk_label_recalculate (label);
1336 g_object_thaw_notify (G_OBJECT (label));
1340 * gtk_label_set_markup_with_mnemonic:
1341 * @label: a #GtkLabel
1342 * @str: a markup string (see <link linkend="PangoMarkupFormat">Pango markup format</link>)
1344 * Parses @str which is marked up with the <link linkend="PangoMarkupFormat">Pango text markup language</link>,
1345 * setting the label's text and attribute list based on the parse results.
1346 * If characters in @str are preceded by an underscore, they are underlined
1347 * indicating that they represent a keyboard accelerator called a mnemonic.
1349 * The mnemonic key can be used to activate another widget, chosen automatically,
1350 * or explicitly using gtk_label_set_mnemonic_widget().
1353 gtk_label_set_markup_with_mnemonic (GtkLabel *label,
1357 g_return_if_fail (GTK_IS_LABEL (label));
1359 g_object_freeze_notify (G_OBJECT (label));
1361 last_keyval = label->mnemonic_keyval;
1362 gtk_label_set_label_internal (label, g_strdup (str ? str : ""));
1363 gtk_label_set_use_markup_internal (label, TRUE);
1364 gtk_label_set_use_underline_internal (label, TRUE);
1366 gtk_label_recalculate (label);
1367 gtk_label_setup_mnemonic (label, last_keyval);
1369 g_object_thaw_notify (G_OBJECT (label));
1373 * gtk_label_get_text:
1374 * @label: a #GtkLabel
1376 * Fetches the text from a label widget, as displayed on the
1377 * screen. This does not include any embedded underlines
1378 * indicating mnemonics or Pango markup. (See gtk_label_get_label())
1380 * Return value: the text in the label widget. This is the internal
1381 * string used by the label, and must not be modified.
1383 G_CONST_RETURN gchar *
1384 gtk_label_get_text (GtkLabel *label)
1386 g_return_val_if_fail (GTK_IS_LABEL (label), NULL);
1391 static PangoAttrList *
1392 gtk_label_pattern_to_attrs (GtkLabel *label,
1393 const gchar *pattern)
1396 const char *p = label->text;
1397 const char *q = pattern;
1398 PangoAttrList *attrs;
1400 attrs = pango_attr_list_new ();
1404 while (*p && *q && *q != '_')
1406 p = g_utf8_next_char (p);
1410 while (*p && *q && *q == '_')
1412 p = g_utf8_next_char (p);
1418 PangoAttribute *attr = pango_attr_underline_new (PANGO_UNDERLINE_LOW);
1419 attr->start_index = start - label->text;
1420 attr->end_index = p - label->text;
1422 pango_attr_list_insert (attrs, attr);
1432 gtk_label_set_pattern_internal (GtkLabel *label,
1433 const gchar *pattern)
1435 PangoAttrList *attrs;
1436 g_return_if_fail (GTK_IS_LABEL (label));
1439 attrs = gtk_label_pattern_to_attrs (label, pattern);
1443 if (label->effective_attrs)
1444 pango_attr_list_unref (label->effective_attrs);
1445 label->effective_attrs = attrs;
1449 gtk_label_set_pattern (GtkLabel *label,
1450 const gchar *pattern)
1452 g_return_if_fail (GTK_IS_LABEL (label));
1454 gtk_label_set_pattern_internal (label, pattern);
1456 gtk_label_clear_layout (label);
1457 gtk_widget_queue_resize (GTK_WIDGET (label));
1462 * gtk_label_set_justify:
1463 * @label: a #GtkLabel
1464 * @jtype: a #GtkJustification
1466 * Sets the alignment of the lines in the text of the label relative to
1467 * each other. %GTK_JUSTIFY_LEFT is the default value when the
1468 * widget is first created with gtk_label_new(). If you instead want
1469 * to set the alignment of the label as a whole, use
1470 * gtk_misc_set_alignment() instead. gtk_label_set_justify() has no
1471 * effect on labels containing only a single line.
1474 gtk_label_set_justify (GtkLabel *label,
1475 GtkJustification jtype)
1477 g_return_if_fail (GTK_IS_LABEL (label));
1478 g_return_if_fail (jtype >= GTK_JUSTIFY_LEFT && jtype <= GTK_JUSTIFY_FILL);
1480 if ((GtkJustification) label->jtype != jtype)
1482 label->jtype = jtype;
1484 /* No real need to be this drastic, but easier than duplicating the code */
1485 gtk_label_clear_layout (label);
1487 g_object_notify (G_OBJECT (label), "justify");
1488 gtk_widget_queue_resize (GTK_WIDGET (label));
1493 * gtk_label_get_justify:
1494 * @label: a #GtkLabel
1496 * Returns the justification of the label. See gtk_label_set_justify ().
1498 * Return value: #GtkJustification
1501 gtk_label_get_justify (GtkLabel *label)
1503 g_return_val_if_fail (GTK_IS_LABEL (label), 0);
1505 return label->jtype;
1509 * gtk_label_set_ellipsize:
1510 * @label: a #GtkLabel
1511 * @mode: a #PangoEllipsizeMode
1513 * Sets the mode used to ellipsize (add an ellipsis: "...") to the text if there
1514 * is not enough space to render the entire string.
1519 gtk_label_set_ellipsize (GtkLabel *label,
1520 PangoEllipsizeMode mode)
1522 g_return_if_fail (GTK_IS_LABEL (label));
1523 g_return_if_fail (mode >= PANGO_ELLIPSIZE_NONE && mode <= PANGO_ELLIPSIZE_END);
1525 if ((PangoEllipsizeMode) label->ellipsize != mode)
1527 label->ellipsize = mode;
1529 /* No real need to be this drastic, but easier than duplicating the code */
1530 gtk_label_clear_layout (label);
1532 g_object_notify (G_OBJECT (label), "ellipsize");
1533 gtk_widget_queue_resize (GTK_WIDGET (label));
1538 * gtk_label_get_ellipsize:
1539 * @label: a #GtkLabel
1541 * Returns the ellipsizing position of the label. See gtk_label_set_ellipsize().
1543 * Return value: #PangoEllipsizeMode
1548 gtk_label_get_ellipsize (GtkLabel *label)
1550 g_return_val_if_fail (GTK_IS_LABEL (label), PANGO_ELLIPSIZE_NONE);
1552 return label->ellipsize;
1556 * gtk_label_set_width_chars:
1557 * @label: a #GtkLabel
1558 * @n_chars: the new desired width, in characters.
1560 * Sets the desired width in characters of @label to @n_chars.
1565 gtk_label_set_width_chars (GtkLabel *label,
1568 GtkLabelPrivate *priv;
1570 g_return_if_fail (GTK_IS_LABEL (label));
1572 priv = GTK_LABEL_GET_PRIVATE (label);
1574 if (priv->width_chars != n_chars)
1576 priv->width_chars = n_chars;
1577 g_object_notify (G_OBJECT (label), "width-chars");
1578 gtk_widget_queue_resize (GTK_WIDGET (label));
1583 * gtk_label_get_width_chars:
1584 * @label: a #GtkLabel
1586 * Retrieves the desired width of @label, in characters. See
1587 * gtk_label_set_width_chars().
1589 * Return value: the width of the label in characters.
1594 gtk_label_get_width_chars (GtkLabel *label)
1596 g_return_val_if_fail (GTK_IS_LABEL (label), -1);
1598 return GTK_LABEL_GET_PRIVATE (label)->width_chars;
1602 * gtk_label_set_max_width_chars:
1603 * @label: a #GtkLabel
1604 * @n_chars: the new desired maximum width, in characters.
1606 * Sets the desired maximum width in characters of @label to @n_chars.
1611 gtk_label_set_max_width_chars (GtkLabel *label,
1614 GtkLabelPrivate *priv;
1616 g_return_if_fail (GTK_IS_LABEL (label));
1618 priv = GTK_LABEL_GET_PRIVATE (label);
1620 if (priv->max_width_chars != n_chars)
1622 priv->max_width_chars = n_chars;
1624 g_object_notify (G_OBJECT (label), "max-width-chars");
1625 gtk_widget_queue_resize (GTK_WIDGET (label));
1630 * gtk_label_get_max_width_chars:
1631 * @label: a #GtkLabel
1633 * Retrieves the desired maximum width of @label, in characters. See
1634 * gtk_label_set_width_chars().
1636 * Return value: the maximum width of the label in characters.
1641 gtk_label_get_max_width_chars (GtkLabel *label)
1643 g_return_val_if_fail (GTK_IS_LABEL (label), -1);
1645 return GTK_LABEL_GET_PRIVATE (label)->max_width_chars;
1649 * gtk_label_set_line_wrap:
1650 * @label: a #GtkLabel
1651 * @wrap: the setting
1653 * Toggles line wrapping within the #GtkLabel widget. %TRUE makes it break
1654 * lines if text exceeds the widget's size. %FALSE lets the text get cut off
1655 * by the edge of the widget if it exceeds the widget size.
1657 * Note that setting line wrapping to %TRUE does not make the label
1658 * wrap at its parent container's width, because GTK+ widgets
1659 * conceptually can't make their requisition depend on the parent
1660 * container's size. For a label that wraps at a specific position,
1661 * set the label's width using gtk_widget_set_size_request().
1664 gtk_label_set_line_wrap (GtkLabel *label,
1667 g_return_if_fail (GTK_IS_LABEL (label));
1669 wrap = wrap != FALSE;
1671 if (label->wrap != wrap)
1674 g_object_notify (G_OBJECT (label), "wrap");
1676 gtk_widget_queue_resize (GTK_WIDGET (label));
1681 * gtk_label_get_line_wrap:
1682 * @label: a #GtkLabel
1684 * Returns whether lines in the label are automatically wrapped. See gtk_label_set_line_wrap ().
1686 * Return value: %TRUE if the lines of the label are automatically wrapped.
1689 gtk_label_get_line_wrap (GtkLabel *label)
1691 g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
1697 gtk_label_get (GtkLabel *label,
1700 g_return_if_fail (GTK_IS_LABEL (label));
1701 g_return_if_fail (str != NULL);
1707 gtk_label_destroy (GtkObject *object)
1709 GtkLabel *label = GTK_LABEL (object);
1711 gtk_label_set_mnemonic_widget (label, NULL);
1713 GTK_OBJECT_CLASS (gtk_label_parent_class)->destroy (object);
1717 gtk_label_finalize (GObject *object)
1721 g_return_if_fail (GTK_IS_LABEL (object));
1723 label = GTK_LABEL (object);
1725 g_free (label->label);
1726 g_free (label->text);
1729 g_object_unref (label->layout);
1732 pango_attr_list_unref (label->attrs);
1734 if (label->effective_attrs)
1735 pango_attr_list_unref (label->effective_attrs);
1737 g_free (label->select_info);
1739 G_OBJECT_CLASS (gtk_label_parent_class)->finalize (object);
1743 gtk_label_clear_layout (GtkLabel *label)
1747 g_object_unref (label->layout);
1748 label->layout = NULL;
1752 typedef struct _LabelWrapWidth LabelWrapWidth;
1753 struct _LabelWrapWidth
1756 PangoFontDescription *font_desc;
1760 label_wrap_width_free (gpointer data)
1762 LabelWrapWidth *wrap_width = data;
1763 pango_font_description_free (wrap_width->font_desc);
1764 g_slice_free (LabelWrapWidth, wrap_width);
1768 get_label_wrap_width (GtkLabel *label)
1770 PangoLayout *layout;
1771 GtkStyle *style = GTK_WIDGET (label)->style;
1772 static GQuark quark_label_wrap_width = 0;
1773 LabelWrapWidth *wrap_width;
1775 if (quark_label_wrap_width == 0)
1776 quark_label_wrap_width = g_quark_from_static_string ("gtk-label-wrap-width");
1778 wrap_width = g_object_get_qdata (G_OBJECT (style), quark_label_wrap_width);
1781 wrap_width = g_slice_new0 (LabelWrapWidth);
1782 g_object_set_qdata_full (G_OBJECT (style), quark_label_wrap_width,
1783 wrap_width, label_wrap_width_free);
1786 if (wrap_width->font_desc &&
1787 pango_font_description_equal (wrap_width->font_desc, style->font_desc))
1788 return wrap_width->width;
1790 if (wrap_width->font_desc)
1791 pango_font_description_free (wrap_width->font_desc);
1793 wrap_width->font_desc = pango_font_description_copy (style->font_desc);
1795 layout = gtk_widget_create_pango_layout (GTK_WIDGET (label),
1796 "This long string gives a good enough length for any line to have.");
1797 pango_layout_get_size (layout, &wrap_width->width, NULL);
1798 g_object_unref (layout);
1800 return wrap_width->width;
1804 gtk_label_ensure_layout (GtkLabel *label)
1807 PangoRectangle logical_rect;
1810 widget = GTK_WIDGET (label);
1812 rtl = gtk_widget_get_direction(widget) == GTK_TEXT_DIR_RTL;
1816 PangoAlignment align = PANGO_ALIGN_LEFT; /* Quiet gcc */
1817 gdouble angle = gtk_label_get_angle (label);
1819 if (angle != 0.0 && !label->wrap && !label->ellipsize && !label->select_info)
1821 /* We rotate the standard singleton PangoContext for the widget,
1822 * depending on the fact that it's meant pretty much exclusively
1825 PangoMatrix matrix = PANGO_MATRIX_INIT;
1827 pango_matrix_rotate (&matrix, angle);
1829 pango_context_set_matrix (gtk_widget_get_pango_context (widget), &matrix);
1831 label->have_transform = TRUE;
1835 if (label->have_transform)
1836 pango_context_set_matrix (gtk_widget_get_pango_context (widget), NULL);
1838 label->have_transform = FALSE;
1841 label->layout = gtk_widget_create_pango_layout (widget, label->text);
1843 if (label->effective_attrs)
1844 pango_layout_set_attributes (label->layout, label->effective_attrs);
1846 switch (label->jtype)
1848 case GTK_JUSTIFY_LEFT:
1849 align = rtl ? PANGO_ALIGN_RIGHT : PANGO_ALIGN_LEFT;
1851 case GTK_JUSTIFY_RIGHT:
1852 align = rtl ? PANGO_ALIGN_LEFT : PANGO_ALIGN_RIGHT;
1854 case GTK_JUSTIFY_CENTER:
1855 align = PANGO_ALIGN_CENTER;
1857 case GTK_JUSTIFY_FILL:
1858 /* FIXME: This just doesn't work to do this */
1859 align = rtl ? PANGO_ALIGN_RIGHT : PANGO_ALIGN_LEFT;
1860 pango_layout_set_justify (label->layout, TRUE);
1863 g_assert_not_reached();
1866 pango_layout_set_alignment (label->layout, align);
1867 pango_layout_set_ellipsize (label->layout, label->ellipsize);
1868 pango_layout_set_single_paragraph_mode (label->layout, label->single_line_mode);
1870 if (label->ellipsize)
1871 pango_layout_set_width (label->layout,
1872 widget->allocation.width * PANGO_SCALE);
1873 else if (label->wrap)
1875 GtkWidgetAuxInfo *aux_info;
1876 gint longest_paragraph;
1879 aux_info = _gtk_widget_get_aux_info (widget, FALSE);
1880 if (aux_info && aux_info->width > 0)
1881 pango_layout_set_width (label->layout, aux_info->width * PANGO_SCALE);
1884 GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET (label));
1887 pango_layout_set_width (label->layout, -1);
1888 pango_layout_get_extents (label->layout, NULL, &logical_rect);
1890 width = logical_rect.width;
1892 /* Try to guess a reasonable maximum width */
1893 longest_paragraph = width;
1895 wrap_width = get_label_wrap_width (label);
1896 width = MIN (width, wrap_width);
1898 PANGO_SCALE * (gdk_screen_get_width (screen) + 1) / 2);
1900 pango_layout_set_width (label->layout, width);
1901 pango_layout_get_extents (label->layout, NULL, &logical_rect);
1902 width = logical_rect.width;
1903 height = logical_rect.height;
1905 /* Unfortunately, the above may leave us with a very unbalanced looking paragraph,
1906 * so we try short search for a narrower width that leaves us with the same height
1908 if (longest_paragraph > 0)
1910 gint nlines, perfect_width;
1912 nlines = pango_layout_get_line_count (label->layout);
1913 perfect_width = (longest_paragraph + nlines - 1) / nlines;
1915 if (perfect_width < width)
1917 pango_layout_set_width (label->layout, perfect_width);
1918 pango_layout_get_extents (label->layout, NULL, &logical_rect);
1920 if (logical_rect.height <= height)
1921 width = logical_rect.width;
1924 gint mid_width = (perfect_width + width) / 2;
1926 if (mid_width > perfect_width)
1928 pango_layout_set_width (label->layout, mid_width);
1929 pango_layout_get_extents (label->layout, NULL, &logical_rect);
1931 if (logical_rect.height <= height)
1932 width = logical_rect.width;
1937 pango_layout_set_width (label->layout, width);
1940 else /* !label->wrap */
1941 pango_layout_set_width (label->layout, -1);
1945 /* Gets the bounds of a layout in device coordinates. Note cut-and-paste
1946 * between here and gdkpango.c */
1948 get_rotated_layout_bounds (PangoLayout *layout,
1951 PangoContext *context = pango_layout_get_context (layout);
1952 const PangoMatrix *matrix = pango_context_get_matrix (context);
1953 gdouble x_min = 0, x_max = 0, y_min = 0, y_max = 0; /* quiet gcc */
1954 PangoRectangle logical_rect;
1957 pango_layout_get_extents (layout, NULL, &logical_rect);
1959 for (i = 0; i < 2; i++)
1961 gdouble x = (i == 0) ? logical_rect.x : logical_rect.x + logical_rect.width;
1962 for (j = 0; j < 2; j++)
1964 gdouble y = (j == 0) ? logical_rect.y : logical_rect.y + logical_rect.height;
1966 gdouble xt = (x * matrix->xx + y * matrix->xy) / PANGO_SCALE + matrix->x0;
1967 gdouble yt = (x * matrix->yx + y * matrix->yy) / PANGO_SCALE + matrix->y0;
1969 if (i == 0 && j == 0)
1988 rect->x = floor (x_min);
1989 rect->width = ceil (x_max) - rect->x;
1990 rect->y = floor (y_min);
1991 rect->height = floor (y_max) - rect->y;
1995 gtk_label_size_request (GtkWidget *widget,
1996 GtkRequisition *requisition)
1999 GtkLabelPrivate *priv;
2001 PangoRectangle logical_rect;
2002 GtkWidgetAuxInfo *aux_info;
2004 g_return_if_fail (GTK_IS_LABEL (widget));
2005 g_return_if_fail (requisition != NULL);
2007 label = GTK_LABEL (widget);
2008 priv = GTK_LABEL_GET_PRIVATE (widget);
2011 * If word wrapping is on, then the height requisition can depend
2014 * - Any width set on the widget via gtk_widget_set_usize().
2015 * - The padding of the widget (xpad, set by gtk_misc_set_padding)
2017 * Instead of trying to detect changes to these quantities, if we
2018 * are wrapping, we just rewrap for each size request. Since
2019 * size requisitions are cached by the GTK+ core, this is not
2024 gtk_label_clear_layout (label);
2026 gtk_label_ensure_layout (label);
2028 width = label->misc.xpad * 2;
2029 height = label->misc.ypad * 2;
2031 aux_info = _gtk_widget_get_aux_info (widget, FALSE);
2033 if (label->have_transform)
2037 get_rotated_layout_bounds (label->layout, &rect);
2039 requisition->width = width + rect.width;
2040 requisition->height = height + rect.height;
2045 pango_layout_get_extents (label->layout, NULL, &logical_rect);
2047 if ((label->wrap || label->ellipsize ||
2048 priv->width_chars > 0 || priv->max_width_chars > 0) &&
2049 aux_info && aux_info->width > 0)
2050 width += aux_info->width;
2051 else if (label->ellipsize || priv->width_chars > 0 || priv->max_width_chars > 0)
2053 PangoContext *context;
2054 PangoFontMetrics *metrics;
2055 gint char_width, digit_width, char_pixels, w;
2057 context = pango_layout_get_context (label->layout);
2058 metrics = pango_context_get_metrics (context, widget->style->font_desc,
2059 pango_context_get_language (context));
2061 char_width = pango_font_metrics_get_approximate_char_width (metrics);
2062 digit_width = pango_font_metrics_get_approximate_digit_width (metrics);
2063 char_pixels = MAX (char_width, digit_width);
2064 pango_font_metrics_unref (metrics);
2066 if (priv->width_chars < 0)
2068 PangoRectangle rect;
2070 pango_layout_set_width (label->layout, -1);
2071 pango_layout_get_extents (label->layout, NULL, &rect);
2073 w = char_pixels * MAX (priv->max_width_chars, 3);
2074 w = MIN (rect.width, w);
2078 /* enforce minimum width for ellipsized labels at ~3 chars */
2079 w = char_pixels * MAX (priv->width_chars, 3);
2082 width += PANGO_PIXELS (w);
2085 width += PANGO_PIXELS (logical_rect.width);
2087 if (label->single_line_mode)
2089 PangoContext *context;
2090 PangoFontMetrics *metrics;
2091 gint ascent, descent;
2093 context = pango_layout_get_context (label->layout);
2094 metrics = pango_context_get_metrics (context, widget->style->font_desc,
2095 pango_context_get_language (context));
2097 ascent = pango_font_metrics_get_ascent (metrics);
2098 descent = pango_font_metrics_get_descent (metrics);
2099 pango_font_metrics_unref (metrics);
2101 height += PANGO_PIXELS (ascent + descent);
2104 height += PANGO_PIXELS (logical_rect.height);
2106 requisition->width = width;
2107 requisition->height = height;
2111 gtk_label_size_allocate (GtkWidget *widget,
2112 GtkAllocation *allocation)
2116 label = GTK_LABEL (widget);
2118 (* GTK_WIDGET_CLASS (gtk_label_parent_class)->size_allocate) (widget, allocation);
2120 if (label->ellipsize)
2123 pango_layout_set_width (label->layout, allocation->width * PANGO_SCALE);
2126 if (label->select_info && label->select_info->window)
2128 gdk_window_move_resize (label->select_info->window,
2132 allocation->height);
2137 gtk_label_state_changed (GtkWidget *widget,
2138 GtkStateType prev_state)
2142 label = GTK_LABEL (widget);
2144 if (label->select_info)
2145 gtk_label_select_region (label, 0, 0);
2147 if (GTK_WIDGET_CLASS (gtk_label_parent_class)->state_changed)
2148 GTK_WIDGET_CLASS (gtk_label_parent_class)->state_changed (widget, prev_state);
2152 gtk_label_style_set (GtkWidget *widget,
2153 GtkStyle *previous_style)
2157 g_return_if_fail (GTK_IS_LABEL (widget));
2159 label = GTK_LABEL (widget);
2161 /* We have to clear the layout, fonts etc. may have changed */
2162 gtk_label_clear_layout (label);
2166 gtk_label_direction_changed (GtkWidget *widget,
2167 GtkTextDirection previous_dir)
2169 GtkLabel *label = GTK_LABEL (widget);
2172 pango_layout_context_changed (label->layout);
2174 GTK_WIDGET_CLASS (gtk_label_parent_class)->direction_changed (widget, previous_dir);
2178 get_layout_location (GtkLabel *label,
2184 GtkLabelPrivate *priv;
2186 gint req_width, x, y;
2188 misc = GTK_MISC (label);
2189 widget = GTK_WIDGET (label);
2190 priv = GTK_LABEL_GET_PRIVATE (label);
2192 if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
2193 xalign = misc->xalign;
2195 xalign = 1.0 - misc->xalign;
2197 if (label->ellipsize || priv->width_chars > 0)
2201 width = pango_layout_get_width (label->layout);
2203 pango_layout_get_pixel_size (label->layout, &req_width, NULL);
2205 req_width = PANGO_PIXELS (width);
2208 req_width = widget->requisition.width;
2210 x = floor (widget->allocation.x + (gint)misc->xpad +
2211 xalign * (widget->allocation.width - req_width));
2213 if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
2214 x = MAX (x, widget->allocation.x + misc->xpad);
2216 x = MIN (x, widget->allocation.x + widget->allocation.width - misc->xpad);
2218 y = floor (widget->allocation.y + (gint)misc->ypad
2219 + MAX (((widget->allocation.height - widget->requisition.height) * misc->yalign),
2230 draw_insertion_cursor (GtkLabel *label,
2231 GdkRectangle *cursor_location,
2232 gboolean is_primary,
2233 PangoDirection direction,
2234 gboolean draw_arrow)
2236 GtkWidget *widget = GTK_WIDGET (label);
2237 GtkTextDirection text_dir;
2239 if (direction == PANGO_DIRECTION_LTR)
2240 text_dir = GTK_TEXT_DIR_LTR;
2242 text_dir = GTK_TEXT_DIR_RTL;
2244 gtk_draw_insertion_cursor (widget, widget->window, &(widget->allocation),
2246 is_primary, text_dir, draw_arrow);
2249 static PangoDirection
2250 get_cursor_direction (GtkLabel *label)
2254 g_assert (label->select_info);
2256 gtk_label_ensure_layout (label);
2258 for (l = pango_layout_get_lines (label->layout); l; l = l->next)
2260 PangoLayoutLine *line = l->data;
2262 /* If label->select_info->selection_end is at the very end of
2263 * the line, we don't know if the cursor is on this line or
2264 * the next without looking ahead at the next line. (End
2265 * of paragraph is different from line break.) But it's
2266 * definitely in this paragraph, which is good enough
2267 * to figure out the resolved direction.
2269 if (line->start_index + line->length >= label->select_info->selection_end)
2270 return line->resolved_dir;
2273 return PANGO_DIRECTION_LTR;
2277 gtk_label_draw_cursor (GtkLabel *label, gint xoffset, gint yoffset)
2279 if (label->select_info == NULL)
2282 if (GTK_WIDGET_DRAWABLE (label))
2284 GtkWidget *widget = GTK_WIDGET (label);
2286 PangoDirection keymap_direction;
2287 PangoDirection cursor_direction;
2288 PangoRectangle strong_pos, weak_pos;
2289 gboolean split_cursor;
2290 PangoRectangle *cursor1 = NULL;
2291 PangoRectangle *cursor2 = NULL;
2292 GdkRectangle cursor_location;
2293 PangoDirection dir1 = PANGO_DIRECTION_NEUTRAL;
2294 PangoDirection dir2 = PANGO_DIRECTION_NEUTRAL;
2296 keymap_direction = gdk_keymap_get_direction (gdk_keymap_get_for_display (gtk_widget_get_display (widget)));
2297 cursor_direction = get_cursor_direction (label);
2299 gtk_label_ensure_layout (label);
2301 pango_layout_get_cursor_pos (label->layout, label->select_info->selection_end,
2302 &strong_pos, &weak_pos);
2304 g_object_get (gtk_widget_get_settings (widget),
2305 "gtk-split-cursor", &split_cursor,
2308 dir1 = cursor_direction;
2312 cursor1 = &strong_pos;
2314 if (strong_pos.x != weak_pos.x ||
2315 strong_pos.y != weak_pos.y)
2317 dir2 = (cursor_direction == PANGO_DIRECTION_LTR) ? PANGO_DIRECTION_RTL : PANGO_DIRECTION_LTR;
2318 cursor2 = &weak_pos;
2323 if (keymap_direction == cursor_direction)
2324 cursor1 = &strong_pos;
2326 cursor1 = &weak_pos;
2329 cursor_location.x = xoffset + PANGO_PIXELS (cursor1->x);
2330 cursor_location.y = yoffset + PANGO_PIXELS (cursor1->y);
2331 cursor_location.width = 0;
2332 cursor_location.height = PANGO_PIXELS (cursor1->height);
2334 draw_insertion_cursor (label,
2335 &cursor_location, TRUE, dir1,
2336 dir2 != PANGO_DIRECTION_NEUTRAL);
2338 if (dir2 != PANGO_DIRECTION_NEUTRAL)
2340 cursor_location.x = xoffset + PANGO_PIXELS (cursor2->x);
2341 cursor_location.y = yoffset + PANGO_PIXELS (cursor2->y);
2342 cursor_location.width = 0;
2343 cursor_location.height = PANGO_PIXELS (cursor2->height);
2345 draw_insertion_cursor (label,
2346 &cursor_location, FALSE, dir2,
2354 gtk_label_expose (GtkWidget *widget,
2355 GdkEventExpose *event)
2360 g_return_val_if_fail (GTK_IS_LABEL (widget), FALSE);
2361 g_return_val_if_fail (event != NULL, FALSE);
2363 label = GTK_LABEL (widget);
2365 gtk_label_ensure_layout (label);
2367 if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_MAPPED (widget) &&
2368 label->text && (*label->text != '\0'))
2370 get_layout_location (label, &x, &y);
2372 gtk_paint_layout (widget->style,
2374 GTK_WIDGET_STATE (widget),
2382 if (label->select_info &&
2383 (label->select_info->selection_anchor !=
2384 label->select_info->selection_end))
2390 range[0] = label->select_info->selection_anchor;
2391 range[1] = label->select_info->selection_end;
2393 if (range[0] > range[1])
2395 gint tmp = range[0];
2396 range[0] = range[1];
2400 clip = gdk_pango_layout_get_clip_region (label->layout,
2404 gdk_region_intersect (clip, event->region);
2406 /* FIXME should use gtk_paint, but it can't use a clip
2410 gdk_gc_set_clip_region (widget->style->black_gc, clip);
2413 state = GTK_STATE_SELECTED;
2414 if (!GTK_WIDGET_HAS_FOCUS (widget))
2415 state = GTK_STATE_ACTIVE;
2417 gdk_draw_layout_with_colors (widget->window,
2418 widget->style->black_gc,
2421 &widget->style->text[state],
2422 &widget->style->base[state]);
2424 gdk_gc_set_clip_region (widget->style->black_gc, NULL);
2425 gdk_region_destroy (clip);
2427 else if (label->select_info && GTK_WIDGET_HAS_FOCUS (widget))
2428 gtk_label_draw_cursor (label, x, y);
2435 gtk_label_set_uline_text_internal (GtkLabel *label,
2438 guint accel_key = GDK_VoidSymbol;
2443 gchar *dest, *pattern_dest;
2444 gboolean underscore;
2446 g_return_if_fail (GTK_IS_LABEL (label));
2447 g_return_if_fail (str != NULL);
2449 /* Split text into the base text and a separate pattern
2453 new_str = g_new (gchar, strlen (str) + 1);
2454 pattern = g_new (gchar, g_utf8_strlen (str, -1) + 1);
2463 pattern_dest = pattern;
2470 c = g_utf8_get_char (src);
2471 if (c == (gunichar)-1)
2473 g_warning ("Invalid input string");
2478 next_src = g_utf8_next_char (src);
2483 *pattern_dest++ = ' ';
2486 *pattern_dest++ = '_';
2487 if (accel_key == GDK_VoidSymbol)
2488 accel_key = gdk_keyval_to_lower (gdk_unicode_to_keyval (c));
2491 while (src < next_src)
2505 while (src < next_src)
2508 *pattern_dest++ = ' ';
2515 gtk_label_set_text_internal (label, new_str);
2516 gtk_label_set_pattern_internal (label, pattern);
2520 label->mnemonic_keyval = accel_key;
2524 gtk_label_parse_uline (GtkLabel *label,
2530 g_return_val_if_fail (GTK_IS_LABEL (label), GDK_VoidSymbol);
2531 g_return_val_if_fail (str != NULL, GDK_VoidSymbol);
2533 orig_keyval = label->mnemonic_keyval;
2535 g_object_freeze_notify (G_OBJECT (label));
2537 gtk_label_set_label_internal (label, g_strdup (str ? str : ""));
2538 gtk_label_set_use_markup_internal (label, FALSE);
2539 gtk_label_set_use_underline_internal (label, TRUE);
2541 gtk_label_recalculate (label);
2543 keyval = label->mnemonic_keyval;
2544 label->mnemonic_keyval = GDK_VoidSymbol;
2546 gtk_label_setup_mnemonic (label, orig_keyval);
2548 g_object_thaw_notify (G_OBJECT (label));
2554 * gtk_label_set_text_with_mnemonic:
2555 * @label: a #GtkLabel
2558 * Sets the label's text from the string @str.
2559 * If characters in @str are preceded by an underscore, they are underlined
2560 * indicating that they represent a keyboard accelerator called a mnemonic.
2561 * The mnemonic key can be used to activate another widget, chosen automatically,
2562 * or explicitly using gtk_label_set_mnemonic_widget().
2565 gtk_label_set_text_with_mnemonic (GtkLabel *label,
2570 g_return_if_fail (GTK_IS_LABEL (label));
2571 g_return_if_fail (str != NULL);
2573 last_keyval = label->mnemonic_keyval;
2575 g_object_freeze_notify (G_OBJECT (label));
2577 gtk_label_set_label_internal (label, g_strdup (str ? str : ""));
2578 gtk_label_set_use_markup_internal (label, FALSE);
2579 gtk_label_set_use_underline_internal (label, TRUE);
2581 gtk_label_recalculate (label);
2583 gtk_label_setup_mnemonic (label, last_keyval);
2585 g_object_thaw_notify (G_OBJECT (label));
2589 gtk_label_realize (GtkWidget *widget)
2593 label = GTK_LABEL (widget);
2595 (* GTK_WIDGET_CLASS (gtk_label_parent_class)->realize) (widget);
2597 if (label->select_info)
2598 gtk_label_create_window (label);
2602 gtk_label_unrealize (GtkWidget *widget)
2606 label = GTK_LABEL (widget);
2608 if (label->select_info)
2609 gtk_label_destroy_window (label);
2611 (* GTK_WIDGET_CLASS (gtk_label_parent_class)->unrealize) (widget);
2615 gtk_label_map (GtkWidget *widget)
2619 label = GTK_LABEL (widget);
2621 (* GTK_WIDGET_CLASS (gtk_label_parent_class)->map) (widget);
2623 if (label->select_info)
2624 gdk_window_show (label->select_info->window);
2628 gtk_label_unmap (GtkWidget *widget)
2632 label = GTK_LABEL (widget);
2634 if (label->select_info)
2635 gdk_window_hide (label->select_info->window);
2637 (* GTK_WIDGET_CLASS (gtk_label_parent_class)->unmap) (widget);
2641 window_to_layout_coords (GtkLabel *label,
2648 widget = GTK_WIDGET (label);
2650 /* get layout location in widget->window coords */
2651 get_layout_location (label, &lx, &ly);
2655 *x += widget->allocation.x; /* go to widget->window */
2656 *x -= lx; /* go to layout */
2661 *y += widget->allocation.y; /* go to widget->window */
2662 *y -= ly; /* go to layout */
2668 layout_to_window_coords (GtkLabel *label,
2675 widget = GTK_WIDGET (label);
2677 /* get layout location in widget->window coords */
2678 get_layout_location (label, &lx, &ly);
2682 *x += lx; /* go to widget->window */
2683 *x -= widget->allocation.x; /* go to selection window */
2688 *y += ly; /* go to widget->window */
2689 *y -= widget->allocation.y; /* go to selection window */
2695 get_layout_index (GtkLabel *label,
2701 const gchar *cluster;
2702 const gchar *cluster_end;
2706 gtk_label_ensure_layout (label);
2708 window_to_layout_coords (label, &x, &y);
2713 pango_layout_xy_to_index (label->layout,
2718 cluster = label->text + *index;
2719 cluster_end = cluster;
2722 cluster_end = g_utf8_next_char (cluster_end);
2726 *index += (cluster_end - cluster);
2730 gtk_label_select_word (GtkLabel *label)
2734 gint start_index = gtk_label_move_backward_word (label, label->select_info->selection_end);
2735 gint end_index = gtk_label_move_forward_word (label, label->select_info->selection_end);
2737 min = MIN (label->select_info->selection_anchor,
2738 label->select_info->selection_end);
2739 max = MAX (label->select_info->selection_anchor,
2740 label->select_info->selection_end);
2742 min = MIN (min, start_index);
2743 max = MAX (max, end_index);
2745 gtk_label_select_region_index (label, min, max);
2749 gtk_label_grab_focus (GtkWidget *widget)
2752 gboolean select_on_focus;
2754 label = GTK_LABEL (widget);
2756 if (label->select_info == NULL)
2759 GTK_WIDGET_CLASS (gtk_label_parent_class)->grab_focus (widget);
2761 g_object_get (gtk_widget_get_settings (widget),
2762 "gtk-label-select-on-focus",
2766 if (select_on_focus && !label->in_click)
2767 gtk_label_select_region (label, 0, -1);
2771 gtk_label_button_press (GtkWidget *widget,
2772 GdkEventButton *event)
2778 label = GTK_LABEL (widget);
2780 if (label->select_info == NULL)
2783 label->select_info->in_drag = FALSE;
2784 if (event->button == 1)
2786 if (!GTK_WIDGET_HAS_FOCUS (widget))
2788 label->in_click = TRUE;
2789 gtk_widget_grab_focus (widget);
2790 label->in_click = FALSE;
2793 if (event->type == GDK_3BUTTON_PRESS)
2795 gtk_label_select_region_index (label, 0, strlen (label->text));
2799 if (event->type == GDK_2BUTTON_PRESS)
2801 gtk_label_select_word (label);
2805 get_layout_index (label, event->x, event->y, &index);
2807 min = MIN (label->select_info->selection_anchor,
2808 label->select_info->selection_end);
2809 max = MAX (label->select_info->selection_anchor,
2810 label->select_info->selection_end);
2812 if ((label->select_info->selection_anchor !=
2813 label->select_info->selection_end) &&
2814 (event->state & GDK_SHIFT_MASK))
2816 /* extend (same as motion) */
2817 min = MIN (min, index);
2818 max = MAX (max, index);
2820 /* ensure the anchor is opposite index */
2828 gtk_label_select_region_index (label, min, max);
2832 if (event->type == GDK_3BUTTON_PRESS)
2833 gtk_label_select_region_index (label, 0, strlen (label->text));
2834 else if (event->type == GDK_2BUTTON_PRESS)
2835 gtk_label_select_word (label);
2836 else if (min < max && min <= index && index <= max)
2838 label->select_info->in_drag = TRUE;
2839 label->select_info->drag_start_x = event->x;
2840 label->select_info->drag_start_y = event->y;
2843 /* start a replacement */
2844 gtk_label_select_region_index (label, index, index);
2849 else if (event->button == 3 && event->type == GDK_BUTTON_PRESS)
2851 gtk_label_do_popup (label, event);
2860 gtk_label_button_release (GtkWidget *widget,
2861 GdkEventButton *event)
2864 GtkLabel *label = GTK_LABEL (widget);
2867 if (label->select_info == NULL)
2870 if (label->select_info->in_drag)
2872 label->select_info->in_drag = 0;
2874 get_layout_index (label, event->x, event->y, &index);
2875 gtk_label_select_region_index (label, index, index);
2880 if (event->button != 1)
2883 /* The goal here is to return TRUE iff we ate the
2884 * button press to start selecting.
2891 drag_begin_cb (GtkWidget *widget,
2892 GdkDragContext *context,
2896 GdkPixmap *pixmap = NULL;
2898 g_signal_handlers_disconnect_by_func (widget, drag_begin_cb, NULL);
2900 label = GTK_LABEL (widget);
2902 if ((label->select_info->selection_anchor !=
2903 label->select_info->selection_end) &&
2909 start = MIN (label->select_info->selection_anchor,
2910 label->select_info->selection_end);
2911 end = MAX (label->select_info->selection_anchor,
2912 label->select_info->selection_end);
2914 len = strlen (label->text);
2922 pixmap = _gtk_text_util_create_drag_icon (widget,
2923 label->text + start,
2928 gtk_drag_set_icon_pixmap (context,
2929 gdk_drawable_get_colormap (pixmap),
2934 gtk_drag_set_icon_default (context);
2937 g_object_unref (pixmap);
2941 gtk_label_motion (GtkWidget *widget,
2942 GdkEventMotion *event)
2948 label = GTK_LABEL (widget);
2950 if (label->select_info == NULL)
2954 if ((event->state & GDK_BUTTON1_MASK) == 0)
2957 gdk_window_get_pointer (label->select_info->window,
2960 if (label->select_info->in_drag)
2962 if (gtk_drag_check_threshold (widget,
2963 label->select_info->drag_start_x,
2964 label->select_info->drag_start_y,
2965 event->x, event->y))
2967 GtkTargetList *target_list = gtk_target_list_new (NULL, 0);
2969 gtk_target_list_add_text_targets (target_list, 0);
2971 g_signal_connect (widget, "drag-begin",
2972 G_CALLBACK (drag_begin_cb), NULL);
2973 gtk_drag_begin (widget, target_list,
2975 1, (GdkEvent *)event);
2977 label->select_info->in_drag = FALSE;
2979 gtk_target_list_unref (target_list);
2984 get_layout_index (label, x, y, &index);
2986 gtk_label_select_region_index (label,
2987 label->select_info->selection_anchor,
2995 gtk_label_create_window (GtkLabel *label)
2998 GdkWindowAttr attributes;
2999 gint attributes_mask;
3001 g_assert (label->select_info);
3002 g_assert (GTK_WIDGET_REALIZED (label));
3004 if (label->select_info->window)
3007 widget = GTK_WIDGET (label);
3009 attributes.x = widget->allocation.x;
3010 attributes.y = widget->allocation.y;
3011 attributes.width = widget->allocation.width;
3012 attributes.height = widget->allocation.height;
3013 attributes.window_type = GDK_WINDOW_CHILD;
3014 attributes.wclass = GDK_INPUT_ONLY;
3015 attributes.override_redirect = TRUE;
3016 attributes.cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget),
3018 attributes.event_mask = gtk_widget_get_events (widget) |
3019 GDK_BUTTON_PRESS_MASK |
3020 GDK_BUTTON_RELEASE_MASK |
3021 GDK_BUTTON_MOTION_MASK;
3023 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_NOREDIR | GDK_WA_CURSOR;
3025 label->select_info->window = gdk_window_new (widget->window,
3026 &attributes, attributes_mask);
3027 gdk_window_set_user_data (label->select_info->window, widget);
3029 gdk_cursor_unref (attributes.cursor);
3033 gtk_label_destroy_window (GtkLabel *label)
3035 g_assert (label->select_info);
3037 if (label->select_info->window == NULL)
3040 gdk_window_set_user_data (label->select_info->window, NULL);
3041 gdk_window_destroy (label->select_info->window);
3042 label->select_info->window = NULL;
3046 * gtk_label_set_selectable:
3047 * @label: a #GtkLabel
3048 * @setting: %TRUE to allow selecting text in the label
3050 * Selectable labels allow the user to select text from the label, for
3055 gtk_label_set_selectable (GtkLabel *label,
3058 gboolean old_setting;
3060 g_return_if_fail (GTK_IS_LABEL (label));
3062 setting = setting != FALSE;
3063 old_setting = label->select_info != NULL;
3067 if (label->select_info == NULL)
3069 label->select_info = g_new0 (GtkLabelSelectionInfo, 1);
3071 GTK_WIDGET_SET_FLAGS (label, GTK_CAN_FOCUS);
3073 if (GTK_WIDGET_REALIZED (label))
3074 gtk_label_create_window (label);
3076 if (GTK_WIDGET_MAPPED (label))
3077 gdk_window_show (label->select_info->window);
3082 if (label->select_info)
3084 /* unselect, to give up the selection */
3085 gtk_label_select_region (label, 0, 0);
3087 if (label->select_info->window)
3089 gtk_label_destroy_window (label);
3092 g_free (label->select_info);
3094 label->select_info = NULL;
3096 GTK_WIDGET_UNSET_FLAGS (label, GTK_CAN_FOCUS);
3099 if (setting != old_setting)
3101 g_object_freeze_notify (G_OBJECT (label));
3102 g_object_notify (G_OBJECT (label), "selectable");
3103 g_object_notify (G_OBJECT (label), "cursor-position");
3104 g_object_notify (G_OBJECT (label), "selection-bound");
3105 g_object_thaw_notify (G_OBJECT (label));
3106 gtk_widget_queue_draw (GTK_WIDGET (label));
3111 * gtk_label_get_selectable:
3112 * @label: a #GtkLabel
3114 * Gets the value set by gtk_label_set_selectable().
3116 * Return value: %TRUE if the user can copy text from the label
3119 gtk_label_get_selectable (GtkLabel *label)
3121 g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
3123 return label->select_info != NULL;
3127 free_angle (gpointer angle)
3129 g_slice_free (gdouble, angle);
3133 * gtk_label_set_angle:
3134 * @label: a #GtkLabel
3135 * @angle: the angle that the baseline of the label makes with
3136 * the horizontal, in degrees, measured counterclockwise
3138 * Sets the angle of rotation for the label. An angle of 90 reads from
3139 * from bottom to top, an angle of 270, from top to bottom. The angle
3140 * setting for the label is ignored if the label is selectable,
3141 * wrapped, or ellipsized.
3146 gtk_label_set_angle (GtkLabel *label,
3149 gdouble *label_angle;
3151 g_return_if_fail (GTK_IS_LABEL (label));
3153 label_angle = (gdouble *)g_object_get_qdata (G_OBJECT (label), quark_angle);
3157 label_angle = g_slice_new (gdouble);
3159 g_object_set_qdata_full (G_OBJECT (label), quark_angle,
3160 label_angle, free_angle);
3163 /* Canonicalize to [0,360]. We don't canonicalize 360 to 0, because
3164 * double property ranges are inclusive, and changing 360 to 0 would
3165 * make a property editor behave strangely.
3167 if (angle < 0 || angle > 360.0)
3168 angle = angle - 360. * floor (angle / 360.);
3170 if (*label_angle != angle)
3172 *label_angle = angle;
3174 gtk_label_clear_layout (label);
3175 gtk_widget_queue_resize (GTK_WIDGET (label));
3177 g_object_notify (G_OBJECT (label), "angle");
3182 * gtk_label_get_angle:
3183 * @label: a #GtkLabel
3185 * Gets the angle of rotation for the label. See
3186 * gtk_label_set_angle.
3188 * Return value: the angle of rotation for the label
3193 gtk_label_get_angle (GtkLabel *label)
3197 g_return_val_if_fail (GTK_IS_LABEL (label), 0.0);
3199 angle = (gdouble *)g_object_get_qdata (G_OBJECT (label), quark_angle);
3208 gtk_label_set_selection_text (GtkLabel *label,
3209 GtkSelectionData *selection_data)
3211 if ((label->select_info->selection_anchor !=
3212 label->select_info->selection_end) &&
3218 start = MIN (label->select_info->selection_anchor,
3219 label->select_info->selection_end);
3220 end = MAX (label->select_info->selection_anchor,
3221 label->select_info->selection_end);
3223 len = strlen (label->text);
3231 gtk_selection_data_set_text (selection_data,
3232 label->text + start,
3238 gtk_label_drag_data_get (GtkWidget *widget,
3239 GdkDragContext *context,
3240 GtkSelectionData *selection_data,
3244 gtk_label_set_selection_text (GTK_LABEL (widget), selection_data);
3248 get_text_callback (GtkClipboard *clipboard,
3249 GtkSelectionData *selection_data,
3251 gpointer user_data_or_owner)
3253 gtk_label_set_selection_text (GTK_LABEL (user_data_or_owner), selection_data);
3257 clear_text_callback (GtkClipboard *clipboard,
3258 gpointer user_data_or_owner)
3262 label = GTK_LABEL (user_data_or_owner);
3264 if (label->select_info)
3266 label->select_info->selection_anchor = label->select_info->selection_end;
3268 gtk_widget_queue_draw (GTK_WIDGET (label));
3273 gtk_label_select_region_index (GtkLabel *label,
3277 static const GtkTargetEntry targets[] = {
3280 { "COMPOUND_TEXT", 0, 0 },
3281 { "UTF8_STRING", 0, 0 }
3284 g_return_if_fail (GTK_IS_LABEL (label));
3286 if (label->select_info)
3288 GtkClipboard *clipboard;
3290 if (label->select_info->selection_anchor == anchor_index &&
3291 label->select_info->selection_end == end_index)
3294 label->select_info->selection_anchor = anchor_index;
3295 label->select_info->selection_end = end_index;
3297 clipboard = gtk_widget_get_clipboard (GTK_WIDGET (label),
3298 GDK_SELECTION_PRIMARY);
3300 if (anchor_index != end_index)
3302 gtk_clipboard_set_with_owner (clipboard,
3304 G_N_ELEMENTS (targets),
3306 clear_text_callback,
3311 if (gtk_clipboard_get_owner (clipboard) == G_OBJECT (label))
3312 gtk_clipboard_clear (clipboard);
3315 gtk_widget_queue_draw (GTK_WIDGET (label));
3317 g_object_freeze_notify (G_OBJECT (label));
3318 g_object_notify (G_OBJECT (label), "cursor-position");
3319 g_object_notify (G_OBJECT (label), "selection-bound");
3320 g_object_thaw_notify (G_OBJECT (label));
3325 * gtk_label_select_region:
3326 * @label: a #GtkLabel
3327 * @start_offset: start offset (in characters not bytes)
3328 * @end_offset: end offset (in characters not bytes)
3330 * Selects a range of characters in the label, if the label is selectable.
3331 * See gtk_label_set_selectable(). If the label is not selectable,
3332 * this function has no effect. If @start_offset or
3333 * @end_offset are -1, then the end of the label will be substituted.
3337 gtk_label_select_region (GtkLabel *label,
3341 g_return_if_fail (GTK_IS_LABEL (label));
3343 if (label->text && label->select_info)
3345 if (start_offset < 0)
3346 start_offset = g_utf8_strlen (label->text, -1);
3349 end_offset = g_utf8_strlen (label->text, -1);
3351 gtk_label_select_region_index (label,
3352 g_utf8_offset_to_pointer (label->text, start_offset) - label->text,
3353 g_utf8_offset_to_pointer (label->text, end_offset) - label->text);
3358 * gtk_label_get_selection_bounds:
3359 * @label: a #GtkLabel
3360 * @start: return location for start of selection, as a character offset
3361 * @end: return location for end of selection, as a character offset
3363 * Gets the selected range of characters in the label, returning %TRUE
3364 * if there's a selection.
3366 * Return value: %TRUE if selection is non-empty
3369 gtk_label_get_selection_bounds (GtkLabel *label,
3373 g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
3375 if (label->select_info == NULL)
3377 /* not a selectable label */
3387 gint start_index, end_index;
3388 gint start_offset, end_offset;
3391 start_index = MIN (label->select_info->selection_anchor,
3392 label->select_info->selection_end);
3393 end_index = MAX (label->select_info->selection_anchor,
3394 label->select_info->selection_end);
3396 len = strlen (label->text);
3398 if (end_index > len)
3401 if (start_index > len)
3404 start_offset = g_utf8_strlen (label->text, start_index);
3405 end_offset = g_utf8_strlen (label->text, end_index);
3407 if (start_offset > end_offset)
3409 gint tmp = start_offset;
3410 start_offset = end_offset;
3415 *start = start_offset;
3420 return start_offset != end_offset;
3426 * gtk_label_get_layout:
3427 * @label: a #GtkLabel
3429 * Gets the #PangoLayout used to display the label.
3430 * The layout is useful to e.g. convert text positions to
3431 * pixel positions, in combination with gtk_label_get_layout_offsets().
3432 * The returned layout is owned by the label so need not be
3433 * freed by the caller.
3435 * Return value: the #PangoLayout for this label
3438 gtk_label_get_layout (GtkLabel *label)
3440 g_return_val_if_fail (GTK_IS_LABEL (label), NULL);
3442 gtk_label_ensure_layout (label);
3444 return label->layout;
3448 * gtk_label_get_layout_offsets:
3449 * @label: a #GtkLabel
3450 * @x: location to store X offset of layout, or %NULL
3451 * @y: location to store Y offset of layout, or %NULL
3453 * Obtains the coordinates where the label will draw the #PangoLayout
3454 * representing the text in the label; useful to convert mouse events
3455 * into coordinates inside the #PangoLayout, e.g. to take some action
3456 * if some part of the label is clicked. Of course you will need to
3457 * create a #GtkEventBox to receive the events, and pack the label
3458 * inside it, since labels are a #GTK_NO_WINDOW widget. Remember
3459 * when using the #PangoLayout functions you need to convert to
3460 * and from pixels using PANGO_PIXELS() or #PANGO_SCALE.
3464 gtk_label_get_layout_offsets (GtkLabel *label,
3468 g_return_if_fail (GTK_IS_LABEL (label));
3470 get_layout_location (label, x, y);
3474 * gtk_label_set_use_markup:
3475 * @label: a #GtkLabel
3476 * @setting: %TRUE if the label's text should be parsed for markup.
3478 * Sets whether the text of the label contains markup in <link
3479 * linkend="PangoMarkupFormat">Pango's text markup
3480 * language</link>. See gtk_label_set_markup().
3483 gtk_label_set_use_markup (GtkLabel *label,
3486 g_return_if_fail (GTK_IS_LABEL (label));
3488 gtk_label_set_use_markup_internal (label, setting);
3489 gtk_label_recalculate (label);
3493 * gtk_label_get_use_markup:
3494 * @label: a #GtkLabel
3496 * Returns whether the label's text is interpreted as marked up with
3497 * the <link linkend="PangoMarkupFormat">Pango text markup
3498 * language</link>. See gtk_label_set_use_markup ().
3500 * Return value: %TRUE if the label's text will be parsed for markup.
3503 gtk_label_get_use_markup (GtkLabel *label)
3505 g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
3507 return label->use_markup;
3511 * gtk_label_set_use_underline:
3512 * @label: a #GtkLabel
3513 * @setting: %TRUE if underlines in the text indicate mnemonics
3515 * If true, an underline in the text indicates the next character should be
3516 * used for the mnemonic accelerator key.
3519 gtk_label_set_use_underline (GtkLabel *label,
3522 g_return_if_fail (GTK_IS_LABEL (label));
3524 gtk_label_set_use_underline_internal (label, setting);
3525 gtk_label_recalculate (label);
3526 if (label->use_underline)
3527 gtk_label_setup_mnemonic (label, label->mnemonic_keyval);
3531 * gtk_label_get_use_underline:
3532 * @label: a #GtkLabel
3534 * Returns whether an embedded underline in the label indicates a
3535 * mnemonic. See gtk_label_set_use_underline ().
3537 * Return value: %TRUE whether an embedded underline in the label indicates
3538 * the mnemonic accelerator keys.
3541 gtk_label_get_use_underline (GtkLabel *label)
3543 g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
3545 return label->use_underline;
3549 * gtk_label_set_single_line_mode:
3550 * @label: a #GtkLabel
3551 * @single_line_mode: %TRUE if the label should be in single line mode
3553 * Sets whether the label is in single line mode.
3558 gtk_label_set_single_line_mode (GtkLabel *label,
3559 gboolean single_line_mode)
3561 g_return_if_fail (GTK_IS_LABEL (label));
3563 single_line_mode = single_line_mode != FALSE;
3565 if (label->single_line_mode != single_line_mode)
3567 label->single_line_mode = single_line_mode;
3569 gtk_label_clear_layout (label);
3570 gtk_widget_queue_resize (GTK_WIDGET (label));
3572 g_object_notify (G_OBJECT (label), "single-line-mode");
3577 * gtk_label_get_single_line_mode:
3578 * @label: a #GtkLabel
3580 * Returns whether the label is in single line mode.
3582 * Return value: %TRUE when the label is in single line mode.
3587 gtk_label_get_single_line_mode (GtkLabel *label)
3589 g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
3591 return label->single_line_mode;
3594 /* Compute the X position for an offset that corresponds to the "more important
3595 * cursor position for that offset. We use this when trying to guess to which
3596 * end of the selection we should go to when the user hits the left or
3600 get_better_cursor (GtkLabel *label,
3605 GdkKeymap *keymap = gdk_keymap_get_for_display (gtk_widget_get_display (GTK_WIDGET (label)));
3606 PangoDirection keymap_direction = gdk_keymap_get_direction (keymap);
3607 PangoDirection cursor_direction = get_cursor_direction (label);
3608 gboolean split_cursor;
3609 PangoRectangle strong_pos, weak_pos;
3611 g_object_get (gtk_widget_get_settings (GTK_WIDGET (label)),
3612 "gtk-split-cursor", &split_cursor,
3615 gtk_label_ensure_layout (label);
3617 pango_layout_get_cursor_pos (label->layout, index,
3618 &strong_pos, &weak_pos);
3622 *x = strong_pos.x / PANGO_SCALE;
3623 *y = strong_pos.y / PANGO_SCALE;
3627 if (keymap_direction == cursor_direction)
3629 *x = strong_pos.x / PANGO_SCALE;
3630 *y = strong_pos.y / PANGO_SCALE;
3634 *x = weak_pos.x / PANGO_SCALE;
3635 *y = weak_pos.y / PANGO_SCALE;
3642 gtk_label_move_logically (GtkLabel *label,
3646 gint offset = g_utf8_pointer_to_offset (label->text,
3647 label->text + start);
3651 PangoLogAttr *log_attrs;
3655 gtk_label_ensure_layout (label);
3657 length = g_utf8_strlen (label->text, -1);
3659 pango_layout_get_log_attrs (label->layout, &log_attrs, &n_attrs);
3661 while (count > 0 && offset < length)
3665 while (offset < length && !log_attrs[offset].is_cursor_position);
3669 while (count < 0 && offset > 0)
3673 while (offset > 0 && !log_attrs[offset].is_cursor_position);
3681 return g_utf8_offset_to_pointer (label->text, offset) - label->text;
3685 gtk_label_move_visually (GtkLabel *label,
3695 int new_index, new_trailing;
3696 gboolean split_cursor;
3699 gtk_label_ensure_layout (label);
3701 g_object_get (gtk_widget_get_settings (GTK_WIDGET (label)),
3702 "gtk-split-cursor", &split_cursor,
3709 GdkKeymap *keymap = gdk_keymap_get_for_display (gtk_widget_get_display (GTK_WIDGET (label)));
3710 PangoDirection keymap_direction = gdk_keymap_get_direction (keymap);
3712 strong = keymap_direction == get_cursor_direction (label);
3717 pango_layout_move_cursor_visually (label->layout, strong, index, 0, 1, &new_index, &new_trailing);
3722 pango_layout_move_cursor_visually (label->layout, strong, index, 0, -1, &new_index, &new_trailing);
3726 if (new_index < 0 || new_index == G_MAXINT)
3731 while (new_trailing--)
3732 index = g_utf8_next_char (label->text + new_index) - label->text;
3739 gtk_label_move_forward_word (GtkLabel *label,
3742 gint new_pos = g_utf8_pointer_to_offset (label->text,
3743 label->text + start);
3746 length = g_utf8_strlen (label->text, -1);
3747 if (new_pos < length)
3749 PangoLogAttr *log_attrs;
3752 gtk_label_ensure_layout (label);
3754 pango_layout_get_log_attrs (label->layout, &log_attrs, &n_attrs);
3756 /* Find the next word end */
3758 while (new_pos < n_attrs && !log_attrs[new_pos].is_word_end)
3764 return g_utf8_offset_to_pointer (label->text, new_pos) - label->text;
3769 gtk_label_move_backward_word (GtkLabel *label,
3772 gint new_pos = g_utf8_pointer_to_offset (label->text,
3773 label->text + start);
3777 PangoLogAttr *log_attrs;
3780 gtk_label_ensure_layout (label);
3782 pango_layout_get_log_attrs (label->layout, &log_attrs, &n_attrs);
3786 /* Find the previous word beginning */
3787 while (new_pos > 0 && !log_attrs[new_pos].is_word_start)
3793 return g_utf8_offset_to_pointer (label->text, new_pos) - label->text;
3797 gtk_label_move_cursor (GtkLabel *label,
3798 GtkMovementStep step,
3800 gboolean extend_selection)
3804 if (label->select_info == NULL)
3807 new_pos = label->select_info->selection_end;
3809 if (label->select_info->selection_end != label->select_info->selection_anchor &&
3812 /* If we have a current selection and aren't extending it, move to the
3813 * start/or end of the selection as appropriate
3817 case GTK_MOVEMENT_VISUAL_POSITIONS:
3820 gint anchor_x, anchor_y;
3821 gboolean end_is_left;
3823 get_better_cursor (label, label->select_info->selection_end, &end_x, &end_y);
3824 get_better_cursor (label, label->select_info->selection_anchor, &anchor_x, &anchor_y);
3826 end_is_left = (end_y < anchor_y) || (end_y == anchor_y && end_x < anchor_x);
3829 new_pos = end_is_left ? label->select_info->selection_end : label->select_info->selection_anchor;
3831 new_pos = !end_is_left ? label->select_info->selection_end : label->select_info->selection_anchor;
3835 case GTK_MOVEMENT_LOGICAL_POSITIONS:
3836 case GTK_MOVEMENT_WORDS:
3838 new_pos = MIN (label->select_info->selection_end, label->select_info->selection_anchor);
3840 new_pos = MAX (label->select_info->selection_end, label->select_info->selection_anchor);
3842 case GTK_MOVEMENT_DISPLAY_LINE_ENDS:
3843 case GTK_MOVEMENT_PARAGRAPH_ENDS:
3844 case GTK_MOVEMENT_BUFFER_ENDS:
3845 /* FIXME: Can do better here */
3846 new_pos = count < 0 ? 0 : strlen (label->text);
3848 case GTK_MOVEMENT_DISPLAY_LINES:
3849 case GTK_MOVEMENT_PARAGRAPHS:
3850 case GTK_MOVEMENT_PAGES:
3851 case GTK_MOVEMENT_HORIZONTAL_PAGES:
3859 case GTK_MOVEMENT_LOGICAL_POSITIONS:
3860 new_pos = gtk_label_move_logically (label, new_pos, count);
3862 case GTK_MOVEMENT_VISUAL_POSITIONS:
3863 new_pos = gtk_label_move_visually (label, new_pos, count);
3865 case GTK_MOVEMENT_WORDS:
3868 new_pos = gtk_label_move_forward_word (label, new_pos);
3873 new_pos = gtk_label_move_backward_word (label, new_pos);
3877 case GTK_MOVEMENT_DISPLAY_LINE_ENDS:
3878 case GTK_MOVEMENT_PARAGRAPH_ENDS:
3879 case GTK_MOVEMENT_BUFFER_ENDS:
3880 /* FIXME: Can do better here */
3881 new_pos = count < 0 ? 0 : strlen (label->text);
3883 case GTK_MOVEMENT_DISPLAY_LINES:
3884 case GTK_MOVEMENT_PARAGRAPHS:
3885 case GTK_MOVEMENT_PAGES:
3886 case GTK_MOVEMENT_HORIZONTAL_PAGES:
3891 if (extend_selection)
3892 gtk_label_select_region_index (label,
3893 label->select_info->selection_anchor,
3896 gtk_label_select_region_index (label, new_pos, new_pos);
3900 gtk_label_copy_clipboard (GtkLabel *label)
3902 if (label->text && label->select_info)
3907 start = MIN (label->select_info->selection_anchor,
3908 label->select_info->selection_end);
3909 end = MAX (label->select_info->selection_anchor,
3910 label->select_info->selection_end);
3912 len = strlen (label->text);
3921 gtk_clipboard_set_text (gtk_widget_get_clipboard (GTK_WIDGET (label),
3922 GDK_SELECTION_CLIPBOARD),
3923 label->text + start, end - start);
3928 gtk_label_select_all (GtkLabel *label)
3930 gtk_label_select_region_index (label, 0, strlen (label->text));
3933 /* Quick hack of a popup menu
3936 activate_cb (GtkWidget *menuitem,
3939 const gchar *signal = g_object_get_data (G_OBJECT (menuitem), "gtk-signal");
3940 g_signal_emit_by_name (label, signal);
3944 append_action_signal (GtkLabel *label,
3946 const gchar *stock_id,
3947 const gchar *signal,
3950 GtkWidget *menuitem = gtk_image_menu_item_new_from_stock (stock_id, NULL);
3952 g_object_set_data (G_OBJECT (menuitem), I_("gtk-signal"), (char *)signal);
3953 g_signal_connect (menuitem, "activate",
3954 G_CALLBACK (activate_cb), label);
3956 gtk_widget_set_sensitive (menuitem, sensitive);
3958 gtk_widget_show (menuitem);
3959 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
3963 popup_menu_detach (GtkWidget *attach_widget,
3967 label = GTK_LABEL (attach_widget);
3969 if (label->select_info)
3970 label->select_info->popup_menu = NULL;
3974 popup_position_func (GtkMenu *menu,
3985 label = GTK_LABEL (user_data);
3986 widget = GTK_WIDGET (label);
3988 if (label->select_info == NULL)
3991 g_return_if_fail (GTK_WIDGET_REALIZED (label));
3993 screen = gtk_widget_get_screen (widget);
3994 gdk_window_get_origin (widget->window, x, y);
3996 gtk_widget_size_request (label->select_info->popup_menu, &req);
3998 *x += widget->allocation.width / 2;
3999 *y += widget->allocation.height;
4001 *x = CLAMP (*x, 0, MAX (0, gdk_screen_get_width (screen) - req.width));
4002 *y = CLAMP (*y, 0, MAX (0, gdk_screen_get_height (screen) - req.height));
4007 gtk_label_do_popup (GtkLabel *label,
4008 GdkEventButton *event)
4010 GtkWidget *menuitem;
4011 gboolean have_selection;
4013 if (label->select_info == NULL)
4016 if (label->select_info->popup_menu)
4017 gtk_widget_destroy (label->select_info->popup_menu);
4019 label->select_info->popup_menu = gtk_menu_new ();
4021 gtk_menu_attach_to_widget (GTK_MENU (label->select_info->popup_menu),
4026 label->select_info->selection_anchor != label->select_info->selection_end;
4029 append_action_signal (label, label->select_info->popup_menu, GTK_STOCK_CUT, "cut_clipboard",
4031 append_action_signal (label, label->select_info->popup_menu, GTK_STOCK_COPY, "copy_clipboard",
4033 append_action_signal (label, label->select_info->popup_menu, GTK_STOCK_PASTE, "paste_clipboard",
4036 menuitem = gtk_image_menu_item_new_from_stock (GTK_STOCK_DELETE, NULL);
4037 gtk_widget_set_sensitive (menuitem, FALSE);
4038 gtk_widget_show (menuitem);
4039 gtk_menu_shell_append (GTK_MENU_SHELL (label->select_info->popup_menu), menuitem);
4041 menuitem = gtk_separator_menu_item_new ();
4042 gtk_widget_show (menuitem);
4043 gtk_menu_shell_append (GTK_MENU_SHELL (label->select_info->popup_menu), menuitem);
4045 menuitem = gtk_menu_item_new_with_label (_("Select All"));
4046 g_signal_connect_swapped (menuitem, "activate",
4047 G_CALLBACK (gtk_label_select_all), label);
4048 gtk_widget_show (menuitem);
4049 gtk_menu_shell_append (GTK_MENU_SHELL (label->select_info->popup_menu), menuitem);
4051 g_signal_emit (label,
4052 signals[POPULATE_POPUP],
4054 label->select_info->popup_menu);
4057 gtk_menu_popup (GTK_MENU (label->select_info->popup_menu), NULL, NULL,
4059 event->button, event->time);
4061 gtk_menu_popup (GTK_MENU (label->select_info->popup_menu), NULL, NULL,
4062 popup_position_func, label,
4063 0, gtk_get_current_event_time ());
4066 #define __GTK_LABEL_C__
4067 #include "gtkaliasdef.c"