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))
54 guint single_line_mode : 1;
55 guint have_transform : 1;
60 struct _GtkLabelSelectionInfo
63 gint selection_anchor;
65 GtkWidget *popup_menu;
96 PROP_SINGLE_LINE_MODE,
101 static guint signals[LAST_SIGNAL] = { 0 };
103 static void gtk_label_class_init (GtkLabelClass *klass);
104 static void gtk_label_init (GtkLabel *label);
105 static void gtk_label_set_property (GObject *object,
109 static void gtk_label_get_property (GObject *object,
113 static void gtk_label_destroy (GtkObject *object);
114 static void gtk_label_finalize (GObject *object);
115 static void gtk_label_size_request (GtkWidget *widget,
116 GtkRequisition *requisition);
117 static void gtk_label_size_allocate (GtkWidget *widget,
118 GtkAllocation *allocation);
119 static void gtk_label_state_changed (GtkWidget *widget,
121 static void gtk_label_style_set (GtkWidget *widget,
122 GtkStyle *previous_style);
123 static void gtk_label_direction_changed (GtkWidget *widget,
124 GtkTextDirection previous_dir);
125 static gint gtk_label_expose (GtkWidget *widget,
126 GdkEventExpose *event);
128 static void gtk_label_realize (GtkWidget *widget);
129 static void gtk_label_unrealize (GtkWidget *widget);
130 static void gtk_label_map (GtkWidget *widget);
131 static void gtk_label_unmap (GtkWidget *widget);
133 static gboolean gtk_label_button_press (GtkWidget *widget,
134 GdkEventButton *event);
135 static gboolean gtk_label_button_release (GtkWidget *widget,
136 GdkEventButton *event);
137 static gboolean gtk_label_motion (GtkWidget *widget,
138 GdkEventMotion *event);
141 static void gtk_label_set_text_internal (GtkLabel *label,
143 static void gtk_label_set_label_internal (GtkLabel *label,
145 static void gtk_label_set_use_markup_internal (GtkLabel *label,
147 static void gtk_label_set_use_underline_internal (GtkLabel *label,
149 static void gtk_label_set_attributes_internal (GtkLabel *label,
150 PangoAttrList *attrs);
151 static void gtk_label_set_uline_text_internal (GtkLabel *label,
153 static void gtk_label_set_pattern_internal (GtkLabel *label,
154 const gchar *pattern);
155 static void set_markup (GtkLabel *label,
157 gboolean with_uline);
158 static void gtk_label_recalculate (GtkLabel *label);
159 static void gtk_label_hierarchy_changed (GtkWidget *widget,
160 GtkWidget *old_toplevel);
161 static void gtk_label_screen_changed (GtkWidget *widget,
162 GdkScreen *old_screen);
164 static void gtk_label_create_window (GtkLabel *label);
165 static void gtk_label_destroy_window (GtkLabel *label);
166 static void gtk_label_clear_layout (GtkLabel *label);
167 static void gtk_label_ensure_layout (GtkLabel *label);
168 static void gtk_label_select_region_index (GtkLabel *label,
172 static gboolean gtk_label_mnemonic_activate (GtkWidget *widget,
173 gboolean group_cycling);
174 static void gtk_label_setup_mnemonic (GtkLabel *label,
176 static void gtk_label_drag_data_get (GtkWidget *widget,
177 GdkDragContext *context,
178 GtkSelectionData *selection_data,
183 /* For selectable lables: */
184 static void gtk_label_move_cursor (GtkLabel *label,
185 GtkMovementStep step,
187 gboolean extend_selection);
188 static void gtk_label_copy_clipboard (GtkLabel *label);
189 static void gtk_label_select_all (GtkLabel *label);
190 static void gtk_label_do_popup (GtkLabel *label,
191 GdkEventButton *event);
193 static gint gtk_label_move_forward_word (GtkLabel *label,
195 static gint gtk_label_move_backward_word (GtkLabel *label,
198 static GtkMiscClass *parent_class = NULL;
202 gtk_label_get_type (void)
204 static GType label_type = 0;
208 static const GTypeInfo label_info =
210 sizeof (GtkLabelClass),
211 NULL, /* base_init */
212 NULL, /* base_finalize */
213 (GClassInitFunc) gtk_label_class_init,
214 NULL, /* class_finalize */
215 NULL, /* class_data */
217 32, /* n_preallocs */
218 (GInstanceInitFunc) gtk_label_init,
221 label_type = g_type_register_static (GTK_TYPE_MISC, I_("GtkLabel"),
229 add_move_binding (GtkBindingSet *binding_set,
232 GtkMovementStep step,
235 g_return_if_fail ((modmask & GDK_SHIFT_MASK) == 0);
237 gtk_binding_entry_add_signal (binding_set, keyval, modmask,
241 G_TYPE_BOOLEAN, FALSE);
243 /* Selection-extending version */
244 gtk_binding_entry_add_signal (binding_set, keyval, modmask | GDK_SHIFT_MASK,
248 G_TYPE_BOOLEAN, TRUE);
252 gtk_label_class_init (GtkLabelClass *class)
254 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
255 GtkObjectClass *object_class = GTK_OBJECT_CLASS (class);
256 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
257 GtkBindingSet *binding_set;
259 parent_class = g_type_class_peek_parent (class);
261 gobject_class->set_property = gtk_label_set_property;
262 gobject_class->get_property = gtk_label_get_property;
263 gobject_class->finalize = gtk_label_finalize;
265 object_class->destroy = gtk_label_destroy;
267 widget_class->size_request = gtk_label_size_request;
268 widget_class->size_allocate = gtk_label_size_allocate;
269 widget_class->state_changed = gtk_label_state_changed;
270 widget_class->style_set = gtk_label_style_set;
271 widget_class->direction_changed = gtk_label_direction_changed;
272 widget_class->expose_event = gtk_label_expose;
273 widget_class->realize = gtk_label_realize;
274 widget_class->unrealize = gtk_label_unrealize;
275 widget_class->map = gtk_label_map;
276 widget_class->unmap = gtk_label_unmap;
277 widget_class->button_press_event = gtk_label_button_press;
278 widget_class->button_release_event = gtk_label_button_release;
279 widget_class->motion_notify_event = gtk_label_motion;
280 widget_class->hierarchy_changed = gtk_label_hierarchy_changed;
281 widget_class->screen_changed = gtk_label_screen_changed;
282 widget_class->mnemonic_activate = gtk_label_mnemonic_activate;
283 widget_class->drag_data_get = gtk_label_drag_data_get;
285 class->move_cursor = gtk_label_move_cursor;
286 class->copy_clipboard = gtk_label_copy_clipboard;
288 signals[MOVE_CURSOR] =
289 g_signal_new (I_("move_cursor"),
290 G_OBJECT_CLASS_TYPE (gobject_class),
291 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
292 G_STRUCT_OFFSET (GtkLabelClass, move_cursor),
294 _gtk_marshal_VOID__ENUM_INT_BOOLEAN,
296 GTK_TYPE_MOVEMENT_STEP,
300 signals[COPY_CLIPBOARD] =
301 g_signal_new (I_("copy_clipboard"),
302 G_OBJECT_CLASS_TYPE (gobject_class),
303 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
304 G_STRUCT_OFFSET (GtkLabelClass, copy_clipboard),
306 _gtk_marshal_VOID__VOID,
309 signals[POPULATE_POPUP] =
310 g_signal_new (I_("populate_popup"),
311 G_OBJECT_CLASS_TYPE (gobject_class),
313 G_STRUCT_OFFSET (GtkLabelClass, populate_popup),
315 _gtk_marshal_VOID__OBJECT,
319 g_object_class_install_property (gobject_class,
321 g_param_spec_string ("label",
323 P_("The text of the label"),
325 GTK_PARAM_READWRITE));
326 g_object_class_install_property (gobject_class,
328 g_param_spec_boxed ("attributes",
330 P_("A list of style attributes to apply to the text of the label"),
331 PANGO_TYPE_ATTR_LIST,
332 GTK_PARAM_READWRITE));
333 g_object_class_install_property (gobject_class,
335 g_param_spec_boolean ("use-markup",
337 P_("The text of the label includes XML markup. See pango_parse_markup()"),
339 GTK_PARAM_READWRITE));
340 g_object_class_install_property (gobject_class,
342 g_param_spec_boolean ("use-underline",
344 P_("If set, an underline in the text indicates the next character should be used for the mnemonic accelerator key"),
346 GTK_PARAM_READWRITE));
348 g_object_class_install_property (gobject_class,
350 g_param_spec_enum ("justify",
352 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"),
353 GTK_TYPE_JUSTIFICATION,
355 GTK_PARAM_READWRITE));
357 g_object_class_install_property (gobject_class,
359 g_param_spec_string ("pattern",
361 P_("A string with _ characters in positions correspond to characters in the text to underline"),
363 GTK_PARAM_WRITABLE));
365 g_object_class_install_property (gobject_class,
367 g_param_spec_boolean ("wrap",
369 P_("If set, wrap lines if the text becomes too wide"),
371 GTK_PARAM_READWRITE));
372 g_object_class_install_property (gobject_class,
374 g_param_spec_boolean ("selectable",
376 P_("Whether the label text can be selected with the mouse"),
378 GTK_PARAM_READWRITE));
379 g_object_class_install_property (gobject_class,
380 PROP_MNEMONIC_KEYVAL,
381 g_param_spec_uint ("mnemonic-keyval",
383 P_("The mnemonic accelerator key for this label"),
387 GTK_PARAM_READABLE));
388 g_object_class_install_property (gobject_class,
389 PROP_MNEMONIC_WIDGET,
390 g_param_spec_object ("mnemonic-widget",
391 P_("Mnemonic widget"),
392 P_("The widget to be activated when the label's mnemonic "
395 GTK_PARAM_READWRITE));
397 g_object_class_install_property (gobject_class,
398 PROP_CURSOR_POSITION,
399 g_param_spec_int ("cursor-position",
400 P_("Cursor Position"),
401 P_("The current position of the insertion cursor in chars"),
405 GTK_PARAM_READABLE));
407 g_object_class_install_property (gobject_class,
408 PROP_SELECTION_BOUND,
409 g_param_spec_int ("selection-bound",
410 P_("Selection Bound"),
411 P_("The position of the opposite end of the selection from the cursor in chars"),
415 GTK_PARAM_READABLE));
418 * GtkLabel:ellipsize:
420 * The preferred place to ellipsize the string, if the label does not have
421 * enough room to display the entire string, specified as a #PangoEllisizeMode.
423 * Note that setting this property to a value other than %PANGO_ELLIPSIZE_NONE
424 * has the side-effect that the label requests only enough space to display the
425 * ellipsis "...". In particular, this means that ellipsizing labels don't
426 * work well in notebook tabs, unless the tab's ::tab-expand property is set
427 * to %TRUE. Other means to set a label's width are
428 * gtk_widget_set_size_request() and gtk_label_set_width_chars().
432 g_object_class_install_property (gobject_class,
434 g_param_spec_enum ("ellipsize",
436 P_("The preferred place to ellipsize the string, if the label does not have enough room to display the entire string, if at all"),
437 PANGO_TYPE_ELLIPSIZE_MODE,
438 PANGO_ELLIPSIZE_NONE,
439 GTK_PARAM_READWRITE));
442 * GtkLabel:width-chars:
444 * The desired width of the label, in characters. If this property is set to
445 * -1, the width will be calculated automatically, otherwise the label will
446 * request either 3 characters or the property value, whichever is greater.
447 * If the width-chars property is set to a positive value, then the
448 * max-width-chars property is ignored.
452 g_object_class_install_property (gobject_class,
454 g_param_spec_int ("width-chars",
455 P_("Width In Characters"),
456 P_("The desired width of the label, in characters"),
460 GTK_PARAM_READWRITE));
463 * GtkLabel:single-line-mode:
465 * Whether the label is in single line mode. In single line mode,
466 * the height of the label does not depend on the actual text, it
467 * is always set to ascent + descent of the font. This can be an
468 * advantage in situations where resizing the label because of text
469 * changes would be distracting, e.g. in a statusbar.
473 g_object_class_install_property (gobject_class,
474 PROP_SINGLE_LINE_MODE,
475 g_param_spec_boolean ("single-line-mode",
476 P_("Single Line Mode"),
477 P_("Whether the label is in single line mode"),
479 GTK_PARAM_READWRITE));
484 * The angle that the baseline of the label makes with the horizontal,
485 * in degrees, measured counterclockwise. An angle of 90 reads from
486 * from bottom to top, an angle of 270, from top to bottom. Ignored
487 * if the label is selectable, wrapped, or ellipsized.
491 g_object_class_install_property (gobject_class,
493 g_param_spec_double ("angle",
495 P_("Angle at which the label is rotated"),
499 GTK_PARAM_READWRITE));
502 * GtkLabel:max-width-chars:
504 * The desired maximum width of the label, in characters. If this property
505 * is set to -1, the width will be calculated automatically, otherwise the
506 * label will request space for no more than the requested number of
507 * characters. If the width-chars property is set to a positive value,
508 * then the max-width-chars property is ignored.
512 g_object_class_install_property (gobject_class,
513 PROP_MAX_WIDTH_CHARS,
514 g_param_spec_int ("max-width-chars",
515 P_("Maximum Width In Characters"),
516 P_("The desired maximum width of the label, in characters"),
520 GTK_PARAM_READWRITE));
525 binding_set = gtk_binding_set_by_class (class);
527 /* Moving the insertion point */
528 add_move_binding (binding_set, GDK_Right, 0,
529 GTK_MOVEMENT_VISUAL_POSITIONS, 1);
531 add_move_binding (binding_set, GDK_Left, 0,
532 GTK_MOVEMENT_VISUAL_POSITIONS, -1);
534 add_move_binding (binding_set, GDK_KP_Right, 0,
535 GTK_MOVEMENT_VISUAL_POSITIONS, 1);
537 add_move_binding (binding_set, GDK_KP_Left, 0,
538 GTK_MOVEMENT_VISUAL_POSITIONS, -1);
540 add_move_binding (binding_set, GDK_f, GDK_CONTROL_MASK,
541 GTK_MOVEMENT_LOGICAL_POSITIONS, 1);
543 add_move_binding (binding_set, GDK_b, GDK_CONTROL_MASK,
544 GTK_MOVEMENT_LOGICAL_POSITIONS, -1);
546 add_move_binding (binding_set, GDK_Right, GDK_CONTROL_MASK,
547 GTK_MOVEMENT_WORDS, 1);
549 add_move_binding (binding_set, GDK_Left, GDK_CONTROL_MASK,
550 GTK_MOVEMENT_WORDS, -1);
552 add_move_binding (binding_set, GDK_KP_Right, GDK_CONTROL_MASK,
553 GTK_MOVEMENT_WORDS, 1);
555 add_move_binding (binding_set, GDK_KP_Left, GDK_CONTROL_MASK,
556 GTK_MOVEMENT_WORDS, -1);
558 add_move_binding (binding_set, GDK_a, GDK_CONTROL_MASK,
559 GTK_MOVEMENT_PARAGRAPH_ENDS, -1);
561 add_move_binding (binding_set, GDK_e, GDK_CONTROL_MASK,
562 GTK_MOVEMENT_PARAGRAPH_ENDS, 1);
564 add_move_binding (binding_set, GDK_f, GDK_MOD1_MASK,
565 GTK_MOVEMENT_WORDS, 1);
567 add_move_binding (binding_set, GDK_b, GDK_MOD1_MASK,
568 GTK_MOVEMENT_WORDS, -1);
570 add_move_binding (binding_set, GDK_Home, 0,
571 GTK_MOVEMENT_DISPLAY_LINE_ENDS, -1);
573 add_move_binding (binding_set, GDK_End, 0,
574 GTK_MOVEMENT_DISPLAY_LINE_ENDS, 1);
576 add_move_binding (binding_set, GDK_KP_Home, 0,
577 GTK_MOVEMENT_DISPLAY_LINE_ENDS, -1);
579 add_move_binding (binding_set, GDK_KP_End, 0,
580 GTK_MOVEMENT_DISPLAY_LINE_ENDS, 1);
582 add_move_binding (binding_set, GDK_Home, GDK_CONTROL_MASK,
583 GTK_MOVEMENT_BUFFER_ENDS, -1);
585 add_move_binding (binding_set, GDK_End, GDK_CONTROL_MASK,
586 GTK_MOVEMENT_BUFFER_ENDS, 1);
588 add_move_binding (binding_set, GDK_KP_Home, GDK_CONTROL_MASK,
589 GTK_MOVEMENT_BUFFER_ENDS, -1);
591 add_move_binding (binding_set, GDK_KP_End, GDK_CONTROL_MASK,
592 GTK_MOVEMENT_BUFFER_ENDS, 1);
595 gtk_binding_entry_add_signal (binding_set, GDK_c, GDK_CONTROL_MASK,
596 "copy_clipboard", 0);
598 g_type_class_add_private (class, sizeof (GtkLabelPrivate));
602 gtk_label_set_property (GObject *object,
609 label = GTK_LABEL (object);
614 gtk_label_set_label (label, g_value_get_string (value));
616 case PROP_ATTRIBUTES:
617 gtk_label_set_attributes (label, g_value_get_boxed (value));
619 case PROP_USE_MARKUP:
620 gtk_label_set_use_markup (label, g_value_get_boolean (value));
622 case PROP_USE_UNDERLINE:
623 gtk_label_set_use_underline (label, g_value_get_boolean (value));
626 gtk_label_set_justify (label, g_value_get_enum (value));
629 gtk_label_set_pattern (label, g_value_get_string (value));
632 gtk_label_set_line_wrap (label, g_value_get_boolean (value));
634 case PROP_SELECTABLE:
635 gtk_label_set_selectable (label, g_value_get_boolean (value));
637 case PROP_MNEMONIC_WIDGET:
638 gtk_label_set_mnemonic_widget (label, (GtkWidget*) g_value_get_object (value));
641 gtk_label_set_ellipsize (label, g_value_get_enum (value));
643 case PROP_WIDTH_CHARS:
644 gtk_label_set_width_chars (label, g_value_get_int (value));
646 case PROP_SINGLE_LINE_MODE:
647 gtk_label_set_single_line_mode (label, g_value_get_boolean (value));
650 gtk_label_set_angle (label, g_value_get_double (value));
652 case PROP_MAX_WIDTH_CHARS:
653 gtk_label_set_max_width_chars (label, g_value_get_int (value));
656 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
662 gtk_label_get_property (GObject *object,
669 label = GTK_LABEL (object);
674 g_value_set_string (value, label->label);
676 case PROP_ATTRIBUTES:
677 g_value_set_boxed (value, label->attrs);
679 case PROP_USE_MARKUP:
680 g_value_set_boolean (value, label->use_markup);
682 case PROP_USE_UNDERLINE:
683 g_value_set_boolean (value, label->use_underline);
686 g_value_set_enum (value, label->jtype);
689 g_value_set_boolean (value, label->wrap);
691 case PROP_SELECTABLE:
692 g_value_set_boolean (value, gtk_label_get_selectable (label));
694 case PROP_MNEMONIC_KEYVAL:
695 g_value_set_uint (value, label->mnemonic_keyval);
697 case PROP_MNEMONIC_WIDGET:
698 g_value_set_object (value, (GObject*) label->mnemonic_widget);
700 case PROP_CURSOR_POSITION:
701 if (label->select_info)
703 gint offset = g_utf8_pointer_to_offset (label->text,
704 label->text + label->select_info->selection_end);
705 g_value_set_int (value, offset);
708 g_value_set_int (value, 0);
710 case PROP_SELECTION_BOUND:
711 if (label->select_info)
713 gint offset = g_utf8_pointer_to_offset (label->text,
714 label->text + label->select_info->selection_anchor);
715 g_value_set_int (value, offset);
718 g_value_set_int (value, 0);
721 g_value_set_enum (value, label->ellipsize);
723 case PROP_WIDTH_CHARS:
724 g_value_set_int (value, gtk_label_get_width_chars (label));
726 case PROP_SINGLE_LINE_MODE:
727 g_value_set_boolean (value, gtk_label_get_single_line_mode (label));
730 g_value_set_double (value, gtk_label_get_angle (label));
732 case PROP_MAX_WIDTH_CHARS:
733 g_value_set_int (value, gtk_label_get_max_width_chars (label));
737 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
743 gtk_label_init (GtkLabel *label)
745 GtkLabelPrivate *priv;
747 GTK_WIDGET_SET_FLAGS (label, GTK_NO_WINDOW);
749 priv = GTK_LABEL_GET_PRIVATE (label);
750 priv->width_chars = -1;
752 priv->max_width_chars = -1;
755 label->jtype = GTK_JUSTIFY_LEFT;
757 label->ellipsize = PANGO_ELLIPSIZE_NONE;
759 label->use_underline = FALSE;
760 label->use_markup = FALSE;
762 label->mnemonic_keyval = GDK_VoidSymbol;
763 label->layout = NULL;
767 label->mnemonic_widget = NULL;
768 label->mnemonic_window = NULL;
770 gtk_label_set_text (label, "");
775 * @str: The text of the label
777 * Creates a new label with the given text inside it. You can
778 * pass %NULL to get an empty label widget.
780 * Return value: the new #GtkLabel
783 gtk_label_new (const gchar *str)
787 label = g_object_new (GTK_TYPE_LABEL, NULL);
790 gtk_label_set_text (label, str);
792 return GTK_WIDGET (label);
796 * gtk_label_new_with_mnemonic:
797 * @str: The text of the label, with an underscore in front of the
800 * Creates a new #GtkLabel, containing the text in @str.
802 * If characters in @str are preceded by an underscore, they are
803 * underlined. If you need a literal underscore character in a label, use
804 * '__' (two underscores). The first underlined character represents a
805 * keyboard accelerator called a mnemonic. The mnemonic key can be used
806 * to activate another widget, chosen automatically, or explicitly using
807 * gtk_label_set_mnemonic_widget().
809 * If gtk_label_set_mnemonic_widget()
810 * is not called, then the first activatable ancestor of the #GtkLabel
811 * will be chosen as the mnemonic widget. For instance, if the
812 * label is inside a button or menu item, the button or menu item will
813 * automatically become the mnemonic widget and be activated by
816 * Return value: the new #GtkLabel
819 gtk_label_new_with_mnemonic (const gchar *str)
823 label = g_object_new (GTK_TYPE_LABEL, NULL);
826 gtk_label_set_text_with_mnemonic (label, str);
828 return GTK_WIDGET (label);
832 gtk_label_mnemonic_activate (GtkWidget *widget,
833 gboolean group_cycling)
837 if (GTK_LABEL (widget)->mnemonic_widget)
838 return gtk_widget_mnemonic_activate (GTK_LABEL (widget)->mnemonic_widget, group_cycling);
840 /* Try to find the widget to activate by traversing the
843 parent = widget->parent;
845 if (parent && GTK_IS_NOTEBOOK (parent))
850 if (GTK_WIDGET_CAN_FOCUS (parent) ||
851 (!group_cycling && GTK_WIDGET_GET_CLASS (parent)->activate_signal) ||
852 (parent->parent && GTK_IS_NOTEBOOK (parent->parent)) ||
853 (GTK_IS_MENU_ITEM (parent)))
854 return gtk_widget_mnemonic_activate (parent, group_cycling);
855 parent = parent->parent;
858 /* barf if there was nothing to activate */
859 g_warning ("Couldn't find a target for a mnemonic activation.");
860 gdk_display_beep (gtk_widget_get_display (widget));
866 gtk_label_setup_mnemonic (GtkLabel *label,
869 GtkWidget *widget = GTK_WIDGET (label);
871 GtkWidget *mnemonic_menu;
873 mnemonic_menu = g_object_get_data (G_OBJECT (label), "gtk-mnemonic-menu");
875 if (last_key != GDK_VoidSymbol)
877 if (label->mnemonic_window)
879 gtk_window_remove_mnemonic (label->mnemonic_window,
882 label->mnemonic_window = NULL;
886 _gtk_menu_shell_remove_mnemonic (GTK_MENU_SHELL (mnemonic_menu),
889 mnemonic_menu = NULL;
893 if (label->mnemonic_keyval == GDK_VoidSymbol)
896 toplevel = gtk_widget_get_toplevel (widget);
897 if (GTK_WIDGET_TOPLEVEL (toplevel))
899 GtkWidget *menu_shell;
901 menu_shell = gtk_widget_get_ancestor (widget,
902 GTK_TYPE_MENU_SHELL);
906 _gtk_menu_shell_add_mnemonic (GTK_MENU_SHELL (menu_shell),
907 label->mnemonic_keyval,
909 mnemonic_menu = menu_shell;
912 if (!(menu_shell && GTK_IS_MENU (menu_shell)))
914 gtk_window_add_mnemonic (GTK_WINDOW (toplevel),
915 label->mnemonic_keyval,
917 label->mnemonic_window = GTK_WINDOW (toplevel);
922 g_object_set_data (G_OBJECT (label), I_("gtk-mnemonic-menu"), mnemonic_menu);
926 gtk_label_hierarchy_changed (GtkWidget *widget,
927 GtkWidget *old_toplevel)
929 GtkLabel *label = GTK_LABEL (widget);
931 gtk_label_setup_mnemonic (label, label->mnemonic_keyval);
935 gtk_label_screen_changed (GtkWidget *widget,
936 GdkScreen *old_screen)
938 gtk_label_clear_layout (GTK_LABEL (widget));
942 label_mnemonic_widget_weak_notify (gpointer data,
943 GObject *where_the_object_was)
945 GtkLabel *label = data;
947 label->mnemonic_widget = NULL;
948 g_object_notify (G_OBJECT (label), "mnemonic-widget");
952 * gtk_label_set_mnemonic_widget:
953 * @label: a #GtkLabel
954 * @widget: the target #GtkWidget
956 * If the label has been set so that it has an mnemonic key (using
957 * i.e. gtk_label_set_markup_with_mnemonic(),
958 * gtk_label_set_text_with_mnemonic(), gtk_label_new_with_mnemonic()
959 * or the "use_underline" property) the label can be associated with a
960 * widget that is the target of the mnemonic. When the label is inside
961 * a widget (like a #GtkButton or a #GtkNotebook tab) it is
962 * automatically associated with the correct widget, but sometimes
963 * (i.e. when the target is a #GtkEntry next to the label) you need to
964 * set it explicitly using this function.
966 * The target widget will be accelerated by emitting "mnemonic_activate" on it.
967 * The default handler for this signal will activate the widget if there are no
968 * mnemonic collisions and toggle focus between the colliding widgets otherwise.
971 gtk_label_set_mnemonic_widget (GtkLabel *label,
974 g_return_if_fail (GTK_IS_LABEL (label));
976 g_return_if_fail (GTK_IS_WIDGET (widget));
978 if (label->mnemonic_widget)
980 gtk_widget_remove_mnemonic_label (label->mnemonic_widget, GTK_WIDGET (label));
981 g_object_weak_unref (G_OBJECT (label->mnemonic_widget),
982 label_mnemonic_widget_weak_notify,
985 label->mnemonic_widget = widget;
986 if (label->mnemonic_widget)
988 g_object_weak_ref (G_OBJECT (label->mnemonic_widget),
989 label_mnemonic_widget_weak_notify,
991 gtk_widget_add_mnemonic_label (label->mnemonic_widget, GTK_WIDGET (label));
994 g_object_notify (G_OBJECT (label), "mnemonic-widget");
998 * gtk_label_get_mnemonic_widget:
999 * @label: a #GtkLabel
1001 * Retrieves the target of the mnemonic (keyboard shortcut) of this
1002 * label. See gtk_label_set_mnemonic_widget ().
1004 * Return value: the target of the label's mnemonic, or %NULL if none
1005 * has been set and the default algorithm will be used.
1008 gtk_label_get_mnemonic_widget (GtkLabel *label)
1010 g_return_val_if_fail (GTK_IS_LABEL (label), NULL);
1012 return label->mnemonic_widget;
1016 * gtk_label_get_mnemonic_keyval:
1017 * @label: a #GtkLabel
1019 * If the label has been set so that it has an mnemonic key this function
1020 * returns the keyval used for the mnemonic accelerator. If there is no
1021 * mnemonic set up it returns #GDK_VoidSymbol.
1023 * Returns: GDK keyval usable for accelerators, or #GDK_VoidSymbol
1026 gtk_label_get_mnemonic_keyval (GtkLabel *label)
1028 g_return_val_if_fail (GTK_IS_LABEL (label), GDK_VoidSymbol);
1030 return label->mnemonic_keyval;
1034 gtk_label_set_text_internal (GtkLabel *label,
1037 g_free (label->text);
1041 gtk_label_select_region_index (label, 0, 0);
1045 gtk_label_set_label_internal (GtkLabel *label,
1048 g_free (label->label);
1052 g_object_notify (G_OBJECT (label), "label");
1056 gtk_label_set_use_markup_internal (GtkLabel *label,
1060 if (label->use_markup != val)
1062 g_object_notify (G_OBJECT (label), "use-markup");
1063 label->use_markup = val;
1068 gtk_label_set_use_underline_internal (GtkLabel *label,
1072 if (label->use_underline != val)
1074 g_object_notify (G_OBJECT (label), "use-underline");
1075 label->use_underline = val;
1080 gtk_label_set_attributes_internal (GtkLabel *label,
1081 PangoAttrList *attrs)
1084 pango_attr_list_ref (attrs);
1087 pango_attr_list_unref (label->attrs);
1089 if (!label->use_markup && !label->use_underline)
1092 pango_attr_list_ref (attrs);
1093 if (label->effective_attrs)
1094 pango_attr_list_unref (label->effective_attrs);
1095 label->effective_attrs = attrs;
1098 label->attrs = attrs;
1099 g_object_notify (G_OBJECT (label), "attributes");
1103 /* Calculates text, attrs and mnemonic_keyval from
1104 * label, use_underline and use_markup
1107 gtk_label_recalculate (GtkLabel *label)
1109 if (label->use_markup)
1110 set_markup (label, label->label, label->use_underline);
1113 if (label->use_underline)
1114 gtk_label_set_uline_text_internal (label, label->label);
1117 gtk_label_set_text_internal (label, g_strdup (label->label));
1119 pango_attr_list_ref (label->attrs);
1120 if (label->effective_attrs)
1121 pango_attr_list_unref (label->effective_attrs);
1122 label->effective_attrs = label->attrs;
1126 if (!label->use_underline)
1128 guint keyval = label->mnemonic_keyval;
1130 label->mnemonic_keyval = GDK_VoidSymbol;
1131 gtk_label_setup_mnemonic (label, keyval);
1134 gtk_label_clear_layout (label);
1135 gtk_widget_queue_resize (GTK_WIDGET (label));
1139 * gtk_label_set_text:
1140 * @label: a #GtkLabel
1141 * @str: The text you want to set.
1143 * Sets the text within the #GtkLabel widget. It overwrites any text that
1146 * This will also clear any previously set mnemonic accelerators.
1149 gtk_label_set_text (GtkLabel *label,
1152 g_return_if_fail (GTK_IS_LABEL (label));
1154 g_object_freeze_notify (G_OBJECT (label));
1156 gtk_label_set_label_internal (label, g_strdup (str ? str : ""));
1157 gtk_label_set_use_markup_internal (label, FALSE);
1158 gtk_label_set_use_underline_internal (label, FALSE);
1160 gtk_label_recalculate (label);
1162 g_object_thaw_notify (G_OBJECT (label));
1166 * gtk_label_set_attributes:
1167 * @label: a #GtkLabel
1168 * @attrs: a #PangoAttrList
1170 * Sets a #PangoAttrList; the attributes in the list are applied to the
1171 * label text. The attributes set with this function will be ignored
1172 * if the "use_underline" property or the "use_markup" property
1176 gtk_label_set_attributes (GtkLabel *label,
1177 PangoAttrList *attrs)
1179 g_return_if_fail (GTK_IS_LABEL (label));
1181 gtk_label_set_attributes_internal (label, attrs);
1183 gtk_label_clear_layout (label);
1184 gtk_widget_queue_resize (GTK_WIDGET (label));
1188 * gtk_label_get_attributes:
1189 * @label: a #GtkLabel
1191 * Gets the attribute list that was set on the label using
1192 * gtk_label_set_attributes(), if any. This function does
1193 * not reflect attributes that come from the labels markup
1194 * (see gtk_label_set_markup()). If you want to get the
1195 * effective attributes for the label, use
1196 * pango_layout_get_attribute (gtk_label_get_layout (label)).
1198 * Return value: the attribute list, or %NULL if none was set.
1201 gtk_label_get_attributes (GtkLabel *label)
1203 g_return_val_if_fail (GTK_IS_LABEL (label), NULL);
1205 return label->attrs;
1209 * gtk_label_set_label:
1210 * @label: a #GtkLabel
1211 * @str: the new text to set for the label
1213 * Sets the text of the label. The label is interpreted as
1214 * including embedded underlines and/or Pango markup depending
1215 * on the values of label->use_underline and label->use_markup.
1218 gtk_label_set_label (GtkLabel *label,
1223 g_return_if_fail (GTK_IS_LABEL (label));
1224 g_return_if_fail (str != NULL);
1226 last_keyval = label->mnemonic_keyval;
1228 gtk_label_set_label_internal (label, g_strdup (str));
1229 gtk_label_recalculate (label);
1230 if (last_keyval != label->mnemonic_keyval)
1231 gtk_label_setup_mnemonic (label, last_keyval);
1235 * gtk_label_get_label:
1236 * @label: a #GtkLabel
1238 * Fetches the text from a label widget including any embedded
1239 * underlines indicating mnemonics and Pango markup. (See
1240 * gtk_label_get_text ()).
1242 * Return value: the text of the label widget. This string is
1243 * owned by the widget and must not be modified or freed.
1245 G_CONST_RETURN gchar *
1246 gtk_label_get_label (GtkLabel *label)
1248 g_return_val_if_fail (GTK_IS_LABEL (label), NULL);
1250 return label->label;
1254 set_markup (GtkLabel *label,
1256 gboolean with_uline)
1259 GError *error = NULL;
1260 PangoAttrList *attrs = NULL;
1261 gunichar accel_char = 0;
1263 if (!pango_parse_markup (str,
1265 with_uline ? '_' : 0,
1268 with_uline ? &accel_char : NULL,
1271 g_warning ("Failed to set label from markup due to error parsing markup: %s",
1273 g_error_free (error);
1278 gtk_label_set_text_internal (label, text);
1282 if (label->effective_attrs)
1283 pango_attr_list_unref (label->effective_attrs);
1284 label->effective_attrs = attrs;
1287 if (accel_char != 0)
1288 label->mnemonic_keyval = gdk_keyval_to_lower (gdk_unicode_to_keyval (accel_char));
1290 label->mnemonic_keyval = GDK_VoidSymbol;
1294 * gtk_label_set_markup:
1295 * @label: a #GtkLabel
1296 * @str: a markup string (see <link linkend="PangoMarkupFormat">Pango markup format</link>)
1298 * Parses @str which is marked up with the <link
1299 * linkend="PangoMarkupFormat">Pango text markup language</link>, setting the
1300 * label's text and attribute list based on the parse results. If the @str is
1301 * external data, you may need to escape it with g_markup_escape_text() or
1302 * g_markup_printf_escaped()<!-- -->:
1303 * <informalexample><programlisting>
1306 * markup = g_markup_printf_escaped ("<span style=\"italic\">%s</span>", str);
1307 * gtk_label_set_markup (GTK_LABEL (label), markup);
1309 * </programlisting></informalexample>
1312 gtk_label_set_markup (GtkLabel *label,
1315 g_return_if_fail (GTK_IS_LABEL (label));
1317 gtk_label_set_label_internal (label, g_strdup (str ? str : ""));
1318 gtk_label_set_use_markup_internal (label, TRUE);
1319 gtk_label_set_use_underline_internal (label, FALSE);
1321 gtk_label_recalculate (label);
1325 * gtk_label_set_markup_with_mnemonic:
1326 * @label: a #GtkLabel
1327 * @str: a markup string (see <link linkend="PangoMarkupFormat">Pango markup format</link>)
1329 * Parses @str which is marked up with the <link linkend="PangoMarkupFormat">Pango text markup language</link>,
1330 * setting the label's text and attribute list based on the parse results.
1331 * If characters in @str are preceded by an underscore, they are underlined
1332 * indicating that they represent a keyboard accelerator called a mnemonic.
1334 * The mnemonic key can be used to activate another widget, chosen automatically,
1335 * or explicitly using gtk_label_set_mnemonic_widget().
1338 gtk_label_set_markup_with_mnemonic (GtkLabel *label,
1342 g_return_if_fail (GTK_IS_LABEL (label));
1344 last_keyval = label->mnemonic_keyval;
1345 gtk_label_set_label_internal (label, g_strdup (str ? str : ""));
1346 gtk_label_set_use_markup_internal (label, TRUE);
1347 gtk_label_set_use_underline_internal (label, TRUE);
1349 gtk_label_recalculate (label);
1350 gtk_label_setup_mnemonic (label, last_keyval);
1354 * gtk_label_get_text:
1355 * @label: a #GtkLabel
1357 * Fetches the text from a label widget, as displayed on the
1358 * screen. This does not include any embedded underlines
1359 * indicating mnemonics or Pango markup. (See gtk_label_get_label())
1361 * Return value: the text in the label widget. This is the internal
1362 * string used by the label, and must not be modified.
1364 G_CONST_RETURN gchar *
1365 gtk_label_get_text (GtkLabel *label)
1367 g_return_val_if_fail (GTK_IS_LABEL (label), NULL);
1372 static PangoAttrList *
1373 gtk_label_pattern_to_attrs (GtkLabel *label,
1374 const gchar *pattern)
1377 const char *p = label->text;
1378 const char *q = pattern;
1379 PangoAttrList *attrs;
1381 attrs = pango_attr_list_new ();
1385 while (*p && *q && *q != '_')
1387 p = g_utf8_next_char (p);
1391 while (*p && *q && *q == '_')
1393 p = g_utf8_next_char (p);
1399 PangoAttribute *attr = pango_attr_underline_new (PANGO_UNDERLINE_LOW);
1400 attr->start_index = start - label->text;
1401 attr->end_index = p - label->text;
1403 pango_attr_list_insert (attrs, attr);
1413 gtk_label_set_pattern_internal (GtkLabel *label,
1414 const gchar *pattern)
1416 PangoAttrList *attrs;
1417 g_return_if_fail (GTK_IS_LABEL (label));
1420 attrs = gtk_label_pattern_to_attrs (label, pattern);
1424 if (label->effective_attrs)
1425 pango_attr_list_unref (label->effective_attrs);
1426 label->effective_attrs = attrs;
1430 gtk_label_set_pattern (GtkLabel *label,
1431 const gchar *pattern)
1433 g_return_if_fail (GTK_IS_LABEL (label));
1435 gtk_label_set_pattern_internal (label, pattern);
1437 gtk_label_clear_layout (label);
1438 gtk_widget_queue_resize (GTK_WIDGET (label));
1443 * gtk_label_set_justify:
1444 * @label: a #GtkLabel
1445 * @jtype: a #GtkJustification
1447 * Sets the alignment of the lines in the text of the label relative to
1448 * each other. %GTK_JUSTIFY_LEFT is the default value when the
1449 * widget is first created with gtk_label_new(). If you instead want
1450 * to set the alignment of the label as a whole, use
1451 * gtk_misc_set_alignment() instead. gtk_label_set_justify() has no
1452 * effect on labels containing only a single line.
1455 gtk_label_set_justify (GtkLabel *label,
1456 GtkJustification jtype)
1458 g_return_if_fail (GTK_IS_LABEL (label));
1459 g_return_if_fail (jtype >= GTK_JUSTIFY_LEFT && jtype <= GTK_JUSTIFY_FILL);
1461 if ((GtkJustification) label->jtype != jtype)
1463 label->jtype = jtype;
1465 /* No real need to be this drastic, but easier than duplicating the code */
1466 gtk_label_clear_layout (label);
1468 g_object_notify (G_OBJECT (label), "justify");
1469 gtk_widget_queue_resize (GTK_WIDGET (label));
1474 * gtk_label_get_justify:
1475 * @label: a #GtkLabel
1477 * Returns the justification of the label. See gtk_label_set_justify ().
1479 * Return value: #GtkJustification
1482 gtk_label_get_justify (GtkLabel *label)
1484 g_return_val_if_fail (GTK_IS_LABEL (label), 0);
1486 return label->jtype;
1490 * gtk_label_set_ellipsize:
1491 * @label: a #GtkLabel
1492 * @mode: a #PangoEllipsizeMode
1494 * Sets the mode used to ellipsize (add an ellipsis: "...") to the text if there
1495 * is not enough space to render the entire string.
1500 gtk_label_set_ellipsize (GtkLabel *label,
1501 PangoEllipsizeMode mode)
1503 g_return_if_fail (GTK_IS_LABEL (label));
1504 g_return_if_fail (mode >= PANGO_ELLIPSIZE_NONE && mode <= PANGO_ELLIPSIZE_END);
1506 if ((PangoEllipsizeMode) label->ellipsize != mode)
1508 label->ellipsize = mode;
1510 /* No real need to be this drastic, but easier than duplicating the code */
1511 gtk_label_clear_layout (label);
1513 g_object_notify (G_OBJECT (label), "ellipsize");
1514 gtk_widget_queue_resize (GTK_WIDGET (label));
1519 * gtk_label_get_ellipsize:
1520 * @label: a #GtkLabel
1522 * Returns the ellipsizing position of the label. See gtk_label_set_ellipsize().
1524 * Return value: #PangoEllipsizeMode
1529 gtk_label_get_ellipsize (GtkLabel *label)
1531 g_return_val_if_fail (GTK_IS_LABEL (label), PANGO_ELLIPSIZE_NONE);
1533 return label->ellipsize;
1537 * gtk_label_set_width_chars:
1538 * @label: a #GtkLabel
1539 * @n_chars: the new desired width, in characters.
1541 * Sets the desired width in characters of @label to @n_chars.
1546 gtk_label_set_width_chars (GtkLabel *label,
1549 GtkLabelPrivate *priv;
1551 g_return_if_fail (GTK_IS_LABEL (label));
1553 priv = GTK_LABEL_GET_PRIVATE (label);
1555 if (priv->width_chars != n_chars)
1557 priv->width_chars = n_chars;
1558 g_object_notify (G_OBJECT (label), "width-chars");
1559 gtk_widget_queue_resize (GTK_WIDGET (label));
1564 * gtk_label_get_width_chars:
1565 * @label: a #GtkLabel
1567 * Retrieves the desired width of @label, in characters. See
1568 * gtk_label_set_width_chars().
1570 * Return value: the width of the label in characters.
1575 gtk_label_get_width_chars (GtkLabel *label)
1577 g_return_val_if_fail (GTK_IS_LABEL (label), -1);
1579 return GTK_LABEL_GET_PRIVATE (label)->width_chars;
1583 * gtk_label_set_max_width_chars:
1584 * @label: a #GtkLabel
1585 * @n_chars: the new desired maximum width, in characters.
1587 * Sets the desired maximum width in characters of @label to @n_chars.
1592 gtk_label_set_max_width_chars (GtkLabel *label,
1595 GtkLabelPrivate *priv;
1597 g_return_if_fail (GTK_IS_LABEL (label));
1599 priv = GTK_LABEL_GET_PRIVATE (label);
1601 if (priv->max_width_chars != n_chars)
1603 priv->max_width_chars = n_chars;
1605 g_object_notify (G_OBJECT (label), "max-width-chars");
1606 gtk_widget_queue_resize (GTK_WIDGET (label));
1611 * gtk_label_get_max_width_chars:
1612 * @label: a #GtkLabel
1614 * Retrieves the desired maximum width of @label, in characters. See
1615 * gtk_label_set_width_chars().
1617 * Return value: the maximum width of the label in characters.
1622 gtk_label_get_max_width_chars (GtkLabel *label)
1624 g_return_val_if_fail (GTK_IS_LABEL (label), -1);
1626 return GTK_LABEL_GET_PRIVATE (label)->max_width_chars;
1630 * gtk_label_set_line_wrap:
1631 * @label: a #GtkLabel
1632 * @wrap: the setting
1634 * Toggles line wrapping within the #GtkLabel widget. %TRUE makes it break
1635 * lines if text exceeds the widget's size. %FALSE lets the text get cut off
1636 * by the edge of the widget if it exceeds the widget size.
1639 gtk_label_set_line_wrap (GtkLabel *label,
1642 g_return_if_fail (GTK_IS_LABEL (label));
1644 wrap = wrap != FALSE;
1646 if (label->wrap != wrap)
1649 g_object_notify (G_OBJECT (label), "wrap");
1651 gtk_widget_queue_resize (GTK_WIDGET (label));
1656 * gtk_label_get_line_wrap:
1657 * @label: a #GtkLabel
1659 * Returns whether lines in the label are automatically wrapped. See gtk_label_set_line_wrap ().
1661 * Return value: %TRUE if the lines of the label are automatically wrapped.
1664 gtk_label_get_line_wrap (GtkLabel *label)
1666 g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
1672 gtk_label_get (GtkLabel *label,
1675 g_return_if_fail (GTK_IS_LABEL (label));
1676 g_return_if_fail (str != NULL);
1682 gtk_label_destroy (GtkObject *object)
1684 GtkLabel *label = GTK_LABEL (object);
1686 gtk_label_set_mnemonic_widget (label, NULL);
1688 GTK_OBJECT_CLASS (parent_class)->destroy (object);
1692 gtk_label_finalize (GObject *object)
1696 g_return_if_fail (GTK_IS_LABEL (object));
1698 label = GTK_LABEL (object);
1700 g_free (label->label);
1701 g_free (label->text);
1704 g_object_unref (label->layout);
1707 pango_attr_list_unref (label->attrs);
1709 if (label->effective_attrs)
1710 pango_attr_list_unref (label->effective_attrs);
1712 g_free (label->select_info);
1714 G_OBJECT_CLASS (parent_class)->finalize (object);
1718 gtk_label_clear_layout (GtkLabel *label)
1722 g_object_unref (label->layout);
1723 label->layout = NULL;
1727 typedef struct _LabelWrapWidth LabelWrapWidth;
1728 struct _LabelWrapWidth
1731 PangoFontDescription *font_desc;
1735 label_wrap_width_free (gpointer data)
1737 LabelWrapWidth *wrap_width = data;
1738 pango_font_description_free (wrap_width->font_desc);
1739 g_free (wrap_width);
1743 get_label_wrap_width (GtkLabel *label)
1745 PangoLayout *layout;
1746 GtkStyle *style = GTK_WIDGET (label)->style;
1748 LabelWrapWidth *wrap_width = g_object_get_data (G_OBJECT (style), "gtk-label-wrap-width");
1751 wrap_width = g_new0 (LabelWrapWidth, 1);
1752 g_object_set_data_full (G_OBJECT (style), I_("gtk-label-wrap-width"),
1753 wrap_width, label_wrap_width_free);
1756 if (wrap_width->font_desc && pango_font_description_equal (wrap_width->font_desc, style->font_desc))
1757 return wrap_width->width;
1759 if (wrap_width->font_desc)
1760 pango_font_description_free (wrap_width->font_desc);
1762 wrap_width->font_desc = pango_font_description_copy (style->font_desc);
1764 layout = gtk_widget_create_pango_layout (GTK_WIDGET (label),
1765 "This long string gives a good enough length for any line to have.");
1766 pango_layout_get_size (layout, &wrap_width->width, NULL);
1767 g_object_unref (layout);
1769 return wrap_width->width;
1773 gtk_label_ensure_layout (GtkLabel *label)
1776 PangoRectangle logical_rect;
1777 gint rwidth, rheight;
1780 widget = GTK_WIDGET (label);
1782 rtl = gtk_widget_get_direction(widget) == GTK_TEXT_DIR_RTL;
1783 rwidth = label->misc.xpad * 2;
1784 rheight = label->misc.ypad * 2;
1788 PangoAlignment align = PANGO_ALIGN_LEFT; /* Quiet gcc */
1789 GtkLabelPrivate *priv = GTK_LABEL_GET_PRIVATE (label);
1791 if (priv->angle != 0.0 && !label->wrap && !label->ellipsize && !label->select_info)
1793 /* We rotate the standard singleton PangoContext for the widget,
1794 * depending on the fact that it's meant pretty much exclusively
1797 PangoMatrix matrix = PANGO_MATRIX_INIT;
1799 pango_matrix_rotate (&matrix, priv->angle);
1801 pango_context_set_matrix (gtk_widget_get_pango_context (widget), &matrix);
1803 priv->have_transform = TRUE;
1807 if (priv->have_transform)
1808 pango_context_set_matrix (gtk_widget_get_pango_context (widget), NULL);
1810 priv->have_transform = FALSE;
1813 label->layout = gtk_widget_create_pango_layout (widget, label->text);
1815 if (label->effective_attrs)
1816 pango_layout_set_attributes (label->layout, label->effective_attrs);
1818 switch (label->jtype)
1820 case GTK_JUSTIFY_LEFT:
1821 align = rtl ? PANGO_ALIGN_RIGHT : PANGO_ALIGN_LEFT;
1823 case GTK_JUSTIFY_RIGHT:
1824 align = rtl ? PANGO_ALIGN_LEFT : PANGO_ALIGN_RIGHT;
1826 case GTK_JUSTIFY_CENTER:
1827 align = PANGO_ALIGN_CENTER;
1829 case GTK_JUSTIFY_FILL:
1830 /* FIXME: This just doesn't work to do this */
1831 align = rtl ? PANGO_ALIGN_RIGHT : PANGO_ALIGN_LEFT;
1832 pango_layout_set_justify (label->layout, TRUE);
1835 g_assert_not_reached();
1838 pango_layout_set_alignment (label->layout, align);
1839 pango_layout_set_ellipsize (label->layout, label->ellipsize);
1840 pango_layout_set_single_paragraph_mode (label->layout, priv->single_line_mode);
1842 if (label->ellipsize)
1843 pango_layout_set_width (label->layout,
1844 widget->allocation.width * PANGO_SCALE);
1845 else if (label->wrap)
1847 GtkWidgetAuxInfo *aux_info;
1848 gint longest_paragraph;
1851 aux_info = _gtk_widget_get_aux_info (widget, FALSE);
1852 if (aux_info && aux_info->width > 0)
1853 pango_layout_set_width (label->layout, aux_info->width * PANGO_SCALE);
1856 GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET (label));
1859 pango_layout_set_width (label->layout, -1);
1860 pango_layout_get_extents (label->layout, NULL, &logical_rect);
1862 width = logical_rect.width;
1864 /* Try to guess a reasonable maximum width */
1865 longest_paragraph = width;
1867 wrap_width = get_label_wrap_width (label);
1868 width = MIN (width, wrap_width);
1870 PANGO_SCALE * (gdk_screen_get_width (screen) + 1) / 2);
1872 pango_layout_set_width (label->layout, width);
1873 pango_layout_get_extents (label->layout, NULL, &logical_rect);
1874 width = logical_rect.width;
1875 height = logical_rect.height;
1877 /* Unfortunately, the above may leave us with a very unbalanced looking paragraph,
1878 * so we try short search for a narrower width that leaves us with the same height
1880 if (longest_paragraph > 0)
1882 gint nlines, perfect_width;
1884 nlines = pango_layout_get_line_count (label->layout);
1885 perfect_width = (longest_paragraph + nlines - 1) / nlines;
1887 if (perfect_width < width)
1889 pango_layout_set_width (label->layout, perfect_width);
1890 pango_layout_get_extents (label->layout, NULL, &logical_rect);
1892 if (logical_rect.height <= height)
1893 width = logical_rect.width;
1896 gint mid_width = (perfect_width + width) / 2;
1898 if (mid_width > perfect_width)
1900 pango_layout_set_width (label->layout, mid_width);
1901 pango_layout_get_extents (label->layout, NULL, &logical_rect);
1903 if (logical_rect.height <= height)
1904 width = logical_rect.width;
1909 pango_layout_set_width (label->layout, width);
1912 else /* !label->wrap */
1913 pango_layout_set_width (label->layout, -1);
1917 /* Gets the bounds of a layout in device coordinates. Note cut-and-paste
1918 * between here and gdkpango.c */
1920 get_rotated_layout_bounds (PangoLayout *layout,
1923 PangoContext *context = pango_layout_get_context (layout);
1924 const PangoMatrix *matrix = pango_context_get_matrix (context);
1925 gdouble x_min = 0, x_max = 0, y_min = 0, y_max = 0; /* quiet gcc */
1926 PangoRectangle logical_rect;
1929 pango_layout_get_extents (layout, NULL, &logical_rect);
1931 for (i = 0; i < 2; i++)
1933 gdouble x = (i == 0) ? logical_rect.x : logical_rect.x + logical_rect.width;
1934 for (j = 0; j < 2; j++)
1936 gdouble y = (j == 0) ? logical_rect.y : logical_rect.y + logical_rect.height;
1938 gdouble xt = (x * matrix->xx + y * matrix->xy) / PANGO_SCALE + matrix->x0;
1939 gdouble yt = (x * matrix->yx + y * matrix->yy) / PANGO_SCALE + matrix->y0;
1941 if (i == 0 && j == 0)
1960 rect->x = floor (x_min);
1961 rect->width = ceil (x_max) - rect->x;
1962 rect->y = floor (y_min);
1963 rect->height = floor (y_max) - rect->y;
1967 gtk_label_size_request (GtkWidget *widget,
1968 GtkRequisition *requisition)
1971 GtkLabelPrivate *priv;
1973 PangoRectangle logical_rect;
1974 GtkWidgetAuxInfo *aux_info;
1976 g_return_if_fail (GTK_IS_LABEL (widget));
1977 g_return_if_fail (requisition != NULL);
1979 label = GTK_LABEL (widget);
1980 priv = GTK_LABEL_GET_PRIVATE (widget);
1983 * If word wrapping is on, then the height requisition can depend
1986 * - Any width set on the widget via gtk_widget_set_usize().
1987 * - The padding of the widget (xpad, set by gtk_misc_set_padding)
1989 * Instead of trying to detect changes to these quantities, if we
1990 * are wrapping, we just rewrap for each size request. Since
1991 * size requisitions are cached by the GTK+ core, this is not
1996 gtk_label_clear_layout (label);
1998 gtk_label_ensure_layout (label);
2000 width = label->misc.xpad * 2;
2001 height = label->misc.ypad * 2;
2003 aux_info = _gtk_widget_get_aux_info (widget, FALSE);
2005 if (priv->have_transform)
2009 get_rotated_layout_bounds (label->layout, &rect);
2011 requisition->width = width + rect.width;
2012 requisition->height = height + rect.height;
2017 pango_layout_get_extents (label->layout, NULL, &logical_rect);
2019 if ((label->wrap || label->ellipsize ||
2020 priv->width_chars > 0 || priv->max_width_chars > 0) &&
2021 aux_info && aux_info->width > 0)
2022 width += aux_info->width;
2023 else if (label->ellipsize || priv->width_chars > 0 || priv->max_width_chars > 0)
2025 PangoContext *context;
2026 PangoFontMetrics *metrics;
2027 gint char_width, digit_width, char_pixels, w;
2029 context = pango_layout_get_context (label->layout);
2030 metrics = pango_context_get_metrics (context, widget->style->font_desc,
2031 pango_context_get_language (context));
2033 char_width = pango_font_metrics_get_approximate_char_width (metrics);
2034 digit_width = pango_font_metrics_get_approximate_digit_width (metrics);
2035 char_pixels = MAX (char_width, digit_width);
2036 pango_font_metrics_unref (metrics);
2038 if (priv->width_chars < 0)
2040 PangoRectangle rect;
2042 pango_layout_set_width (label->layout, -1);
2043 pango_layout_get_extents (label->layout, NULL, &rect);
2045 w = char_pixels * MAX (priv->max_width_chars, 3);
2046 w = MIN (rect.width, w);
2050 /* enforce minimum width for ellipsized labels at ~3 chars */
2051 w = char_pixels * MAX (priv->width_chars, 3);
2054 width += PANGO_PIXELS (w);
2057 width += PANGO_PIXELS (logical_rect.width);
2059 if (priv->single_line_mode)
2061 PangoContext *context;
2062 PangoFontMetrics *metrics;
2063 gint ascent, descent;
2065 context = pango_layout_get_context (label->layout);
2066 metrics = pango_context_get_metrics (context, widget->style->font_desc,
2067 pango_context_get_language (context));
2069 ascent = pango_font_metrics_get_ascent (metrics);
2070 descent = pango_font_metrics_get_descent (metrics);
2071 pango_font_metrics_unref (metrics);
2073 height += PANGO_PIXELS (ascent + descent);
2076 height += PANGO_PIXELS (logical_rect.height);
2078 requisition->width = width;
2079 requisition->height = height;
2083 gtk_label_size_allocate (GtkWidget *widget,
2084 GtkAllocation *allocation)
2087 GtkLabelPrivate *priv;
2089 label = GTK_LABEL (widget);
2090 priv = GTK_LABEL_GET_PRIVATE (widget);
2092 (* GTK_WIDGET_CLASS (parent_class)->size_allocate) (widget, allocation);
2094 if (label->ellipsize)
2097 pango_layout_set_width (label->layout, allocation->width * PANGO_SCALE);
2100 if (label->select_info && label->select_info->window)
2102 gdk_window_move_resize (label->select_info->window,
2106 allocation->height);
2111 gtk_label_state_changed (GtkWidget *widget,
2112 GtkStateType prev_state)
2116 label = GTK_LABEL (widget);
2118 if (label->select_info)
2119 gtk_label_select_region (label, 0, 0);
2121 if (GTK_WIDGET_CLASS (parent_class)->state_changed)
2122 GTK_WIDGET_CLASS (parent_class)->state_changed (widget, prev_state);
2126 gtk_label_style_set (GtkWidget *widget,
2127 GtkStyle *previous_style)
2131 g_return_if_fail (GTK_IS_LABEL (widget));
2133 label = GTK_LABEL (widget);
2135 /* We have to clear the layout, fonts etc. may have changed */
2136 gtk_label_clear_layout (label);
2140 gtk_label_direction_changed (GtkWidget *widget,
2141 GtkTextDirection previous_dir)
2143 GtkLabel *label = GTK_LABEL (widget);
2146 pango_layout_context_changed (label->layout);
2148 GTK_WIDGET_CLASS (parent_class)->direction_changed (widget, previous_dir);
2152 get_layout_location (GtkLabel *label,
2159 gint req_width, x, y;
2161 misc = GTK_MISC (label);
2162 widget = GTK_WIDGET (label);
2164 if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
2165 xalign = misc->xalign;
2167 xalign = 1.0 - misc->xalign;
2169 if (label->ellipsize)
2171 PangoRectangle ink_rect;
2173 pango_layout_get_extents (label->layout, &ink_rect, NULL);
2175 req_width = PANGO_PIXELS (ink_rect.width);
2178 req_width = widget->requisition.width;
2180 x = floor (widget->allocation.x + (gint)misc->xpad +
2181 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 drag_begin_cb (GtkWidget *widget,
2838 GdkDragContext *context,
2842 GdkPixmap *pixmap = NULL;
2844 g_signal_handlers_disconnect_by_func (widget, drag_begin_cb, NULL);
2846 label = GTK_LABEL (widget);
2848 if ((label->select_info->selection_anchor !=
2849 label->select_info->selection_end) &&
2855 start = MIN (label->select_info->selection_anchor,
2856 label->select_info->selection_end);
2857 end = MAX (label->select_info->selection_anchor,
2858 label->select_info->selection_end);
2860 len = strlen (label->text);
2868 pixmap = _gtk_text_util_create_drag_icon (widget,
2869 label->text + start,
2874 gtk_drag_set_icon_pixmap (context,
2875 gdk_drawable_get_colormap (pixmap),
2880 gtk_drag_set_icon_default (context);
2883 g_object_unref (pixmap);
2887 gtk_label_motion (GtkWidget *widget,
2888 GdkEventMotion *event)
2894 label = GTK_LABEL (widget);
2896 if (label->select_info == NULL)
2900 if ((event->state & GDK_BUTTON1_MASK) == 0)
2903 gdk_window_get_pointer (label->select_info->window,
2906 if (label->select_info->in_drag)
2908 if (gtk_drag_check_threshold (widget,
2909 label->select_info->drag_start_x,
2910 label->select_info->drag_start_y,
2911 event->x, event->y))
2913 GdkDragContext *context;
2914 GtkTargetList *target_list = gtk_target_list_new (NULL, 0);
2916 gtk_target_list_add_text_targets (target_list, 0);
2918 g_signal_connect (widget, "drag-begin",
2919 G_CALLBACK (drag_begin_cb), NULL);
2920 context = gtk_drag_begin (widget, target_list,
2922 1, (GdkEvent *)event);
2924 label->select_info->in_drag = FALSE;
2926 gtk_target_list_unref (target_list);
2931 get_layout_index (label, x, y, &index);
2933 gtk_label_select_region_index (label,
2934 label->select_info->selection_anchor,
2942 gtk_label_create_window (GtkLabel *label)
2945 GdkWindowAttr attributes;
2946 gint attributes_mask;
2948 g_assert (label->select_info);
2949 g_assert (GTK_WIDGET_REALIZED (label));
2951 if (label->select_info->window)
2954 widget = GTK_WIDGET (label);
2956 attributes.x = widget->allocation.x;
2957 attributes.y = widget->allocation.y;
2958 attributes.width = widget->allocation.width;
2959 attributes.height = widget->allocation.height;
2960 attributes.window_type = GDK_WINDOW_TEMP;
2961 attributes.wclass = GDK_INPUT_ONLY;
2962 attributes.override_redirect = TRUE;
2963 attributes.cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget),
2965 attributes.event_mask = gtk_widget_get_events (widget) |
2966 GDK_BUTTON_PRESS_MASK |
2967 GDK_BUTTON_RELEASE_MASK |
2968 GDK_BUTTON_MOTION_MASK;
2970 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_NOREDIR | GDK_WA_CURSOR;
2972 label->select_info->window = gdk_window_new (widget->window,
2973 &attributes, attributes_mask);
2974 gdk_window_set_user_data (label->select_info->window, widget);
2976 gdk_cursor_unref (attributes.cursor);
2980 gtk_label_destroy_window (GtkLabel *label)
2982 g_assert (label->select_info);
2984 if (label->select_info->window == NULL)
2987 gdk_window_set_user_data (label->select_info->window, NULL);
2988 gdk_window_destroy (label->select_info->window);
2989 label->select_info->window = NULL;
2993 * gtk_label_set_selectable:
2994 * @label: a #GtkLabel
2995 * @setting: %TRUE to allow selecting text in the label
2997 * Selectable labels allow the user to select text from the label, for
3002 gtk_label_set_selectable (GtkLabel *label,
3005 gboolean old_setting;
3007 g_return_if_fail (GTK_IS_LABEL (label));
3009 setting = setting != FALSE;
3010 old_setting = label->select_info != NULL;
3014 if (label->select_info == NULL)
3016 label->select_info = g_new0 (GtkLabelSelectionInfo, 1);
3018 GTK_WIDGET_SET_FLAGS (label, GTK_CAN_FOCUS);
3020 if (GTK_WIDGET_REALIZED (label))
3021 gtk_label_create_window (label);
3023 if (GTK_WIDGET_MAPPED (label))
3024 gdk_window_show (label->select_info->window);
3029 if (label->select_info)
3031 /* unselect, to give up the selection */
3032 gtk_label_select_region (label, 0, 0);
3034 if (label->select_info->window)
3036 gtk_label_destroy_window (label);
3039 g_free (label->select_info);
3041 label->select_info = NULL;
3043 GTK_WIDGET_UNSET_FLAGS (label, GTK_CAN_FOCUS);
3046 if (setting != old_setting)
3048 g_object_freeze_notify (G_OBJECT (label));
3049 g_object_notify (G_OBJECT (label), "selectable");
3050 g_object_notify (G_OBJECT (label), "cursor-position");
3051 g_object_notify (G_OBJECT (label), "selection-bound");
3052 g_object_thaw_notify (G_OBJECT (label));
3053 gtk_widget_queue_draw (GTK_WIDGET (label));
3058 * gtk_label_get_selectable:
3059 * @label: a #GtkLabel
3061 * Gets the value set by gtk_label_set_selectable().
3063 * Return value: %TRUE if the user can copy text from the label
3066 gtk_label_get_selectable (GtkLabel *label)
3068 g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
3070 return label->select_info != NULL;
3074 * gtk_label_set_angle:
3075 * @label: a #GtkLabel
3076 * @angle: the angle that the baseline of the label makes with
3077 * the horizontal, in degrees, measured counterclockwise
3079 * Sets the angle of rotation for the label. An angle of 90 reads from
3080 * from bottom to top, an angle of 270, from top to bottom. The angle
3081 * setting for the label is ignored if the label is selectable,
3082 * wrapped, or ellipsized.
3087 gtk_label_set_angle (GtkLabel *label,
3090 GtkLabelPrivate *priv;
3092 g_return_if_fail (GTK_IS_LABEL (label));
3094 priv = GTK_LABEL_GET_PRIVATE (label);
3096 /* Canonicalize to [0,360]. We don't canonicalize 360 to 0, because
3097 * double property ranges are inclusive, and changing 360 to 0 would
3098 * make a property editor behave strangely.
3100 if (angle < 0 || angle > 360.0)
3101 angle = angle - 360. * floor (angle / 360.);
3103 if (angle != priv->angle)
3105 priv->angle = angle;
3107 gtk_label_clear_layout (label);
3108 gtk_widget_queue_resize (GTK_WIDGET (label));
3110 g_object_notify (G_OBJECT (label), "angle");
3115 * gtk_label_get_angle:
3116 * @label: a #GtkLabel
3118 * Gets the angle of rotation for the label. See
3119 * gtk_label_set_angle.
3121 * Return value: the angle of rotation for the label
3126 gtk_label_get_angle (GtkLabel *label)
3128 GtkLabelPrivate *priv;
3130 g_return_val_if_fail (GTK_IS_LABEL (label), 0.0);
3132 priv = GTK_LABEL_GET_PRIVATE (label);
3138 gtk_label_set_selection_text (GtkLabel *label,
3139 GtkSelectionData *selection_data)
3141 if ((label->select_info->selection_anchor !=
3142 label->select_info->selection_end) &&
3148 start = MIN (label->select_info->selection_anchor,
3149 label->select_info->selection_end);
3150 end = MAX (label->select_info->selection_anchor,
3151 label->select_info->selection_end);
3153 len = strlen (label->text);
3161 gtk_selection_data_set_text (selection_data,
3162 label->text + start,
3168 gtk_label_drag_data_get (GtkWidget *widget,
3169 GdkDragContext *context,
3170 GtkSelectionData *selection_data,
3174 gtk_label_set_selection_text (GTK_LABEL (widget), selection_data);
3178 get_text_callback (GtkClipboard *clipboard,
3179 GtkSelectionData *selection_data,
3181 gpointer user_data_or_owner)
3183 gtk_label_set_selection_text (GTK_LABEL (user_data_or_owner), selection_data);
3187 clear_text_callback (GtkClipboard *clipboard,
3188 gpointer user_data_or_owner)
3192 label = GTK_LABEL (user_data_or_owner);
3194 if (label->select_info)
3196 label->select_info->selection_anchor = label->select_info->selection_end;
3198 gtk_widget_queue_draw (GTK_WIDGET (label));
3203 gtk_label_select_region_index (GtkLabel *label,
3207 static const GtkTargetEntry targets[] = {
3210 { "COMPOUND_TEXT", 0, 0 },
3211 { "UTF8_STRING", 0, 0 }
3214 g_return_if_fail (GTK_IS_LABEL (label));
3216 if (label->select_info)
3218 GtkClipboard *clipboard;
3220 if (label->select_info->selection_anchor == anchor_index &&
3221 label->select_info->selection_end == end_index)
3224 label->select_info->selection_anchor = anchor_index;
3225 label->select_info->selection_end = end_index;
3227 clipboard = gtk_widget_get_clipboard (GTK_WIDGET (label),
3228 GDK_SELECTION_PRIMARY);
3230 if (anchor_index != end_index)
3232 gtk_clipboard_set_with_owner (clipboard,
3234 G_N_ELEMENTS (targets),
3236 clear_text_callback,
3241 if (gtk_clipboard_get_owner (clipboard) == G_OBJECT (label))
3242 gtk_clipboard_clear (clipboard);
3245 gtk_widget_queue_draw (GTK_WIDGET (label));
3247 g_object_freeze_notify (G_OBJECT (label));
3248 g_object_notify (G_OBJECT (label), "cursor-position");
3249 g_object_notify (G_OBJECT (label), "selection-bound");
3250 g_object_thaw_notify (G_OBJECT (label));
3255 * gtk_label_select_region:
3256 * @label: a #GtkLabel
3257 * @start_offset: start offset (in characters not bytes)
3258 * @end_offset: end offset (in characters not bytes)
3260 * Selects a range of characters in the label, if the label is selectable.
3261 * See gtk_label_set_selectable(). If the label is not selectable,
3262 * this function has no effect. If @start_offset or
3263 * @end_offset are -1, then the end of the label will be substituted.
3267 gtk_label_select_region (GtkLabel *label,
3271 g_return_if_fail (GTK_IS_LABEL (label));
3273 if (label->text && label->select_info)
3275 if (start_offset < 0)
3276 start_offset = g_utf8_strlen (label->text, -1);
3279 end_offset = g_utf8_strlen (label->text, -1);
3281 gtk_label_select_region_index (label,
3282 g_utf8_offset_to_pointer (label->text, start_offset) - label->text,
3283 g_utf8_offset_to_pointer (label->text, end_offset) - label->text);
3288 * gtk_label_get_selection_bounds:
3289 * @label: a #GtkLabel
3290 * @start: return location for start of selection, as a character offset
3291 * @end: return location for end of selection, as a character offset
3293 * Gets the selected range of characters in the label, returning %TRUE
3294 * if there's a selection.
3296 * Return value: %TRUE if selection is non-empty
3299 gtk_label_get_selection_bounds (GtkLabel *label,
3303 g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
3305 if (label->select_info == NULL)
3307 /* not a selectable label */
3317 gint start_index, end_index;
3318 gint start_offset, end_offset;
3321 start_index = MIN (label->select_info->selection_anchor,
3322 label->select_info->selection_end);
3323 end_index = MAX (label->select_info->selection_anchor,
3324 label->select_info->selection_end);
3326 len = strlen (label->text);
3328 if (end_index > len)
3331 if (start_index > len)
3334 start_offset = g_utf8_strlen (label->text, start_index);
3335 end_offset = g_utf8_strlen (label->text, end_index);
3337 if (start_offset > end_offset)
3339 gint tmp = start_offset;
3340 start_offset = end_offset;
3345 *start = start_offset;
3350 return start_offset != end_offset;
3356 * gtk_label_get_layout:
3357 * @label: a #GtkLabel
3359 * Gets the #PangoLayout used to display the label.
3360 * The layout is useful to e.g. convert text positions to
3361 * pixel positions, in combination with gtk_label_get_layout_offsets().
3362 * The returned layout is owned by the label so need not be
3363 * freed by the caller.
3365 * Return value: the #PangoLayout for this label
3368 gtk_label_get_layout (GtkLabel *label)
3370 g_return_val_if_fail (GTK_IS_LABEL (label), NULL);
3372 gtk_label_ensure_layout (label);
3374 return label->layout;
3378 * gtk_label_get_layout_offsets:
3379 * @label: a #GtkLabel
3380 * @x: location to store X offset of layout, or %NULL
3381 * @y: location to store Y offset of layout, or %NULL
3383 * Obtains the coordinates where the label will draw the #PangoLayout
3384 * representing the text in the label; useful to convert mouse events
3385 * into coordinates inside the #PangoLayout, e.g. to take some action
3386 * if some part of the label is clicked. Of course you will need to
3387 * create a #GtkEventBox to receive the events, and pack the label
3388 * inside it, since labels are a #GTK_NO_WINDOW widget. Remember
3389 * when using the #PangoLayout functions you need to convert to
3390 * and from pixels using PANGO_PIXELS() or #PANGO_SCALE.
3394 gtk_label_get_layout_offsets (GtkLabel *label,
3398 g_return_if_fail (GTK_IS_LABEL (label));
3400 get_layout_location (label, x, y);
3404 * gtk_label_set_use_markup:
3405 * @label: a #GtkLabel
3406 * @setting: %TRUE if the label's text should be parsed for markup.
3408 * Sets whether the text of the label contains markup in <link
3409 * linkend="PangoMarkupFormat">Pango's text markup
3410 * language</link>. See gtk_label_set_markup().
3413 gtk_label_set_use_markup (GtkLabel *label,
3416 g_return_if_fail (GTK_IS_LABEL (label));
3418 gtk_label_set_use_markup_internal (label, setting);
3419 gtk_label_recalculate (label);
3423 * gtk_label_get_use_markup:
3424 * @label: a #GtkLabel
3426 * Returns whether the label's text is interpreted as marked up with
3427 * the <link linkend="PangoMarkupFormat">Pango text markup
3428 * language</link>. See gtk_label_set_use_markup ().
3430 * Return value: %TRUE if the label's text will be parsed for markup.
3433 gtk_label_get_use_markup (GtkLabel *label)
3435 g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
3437 return label->use_markup;
3441 * gtk_label_set_use_underline:
3442 * @label: a #GtkLabel
3443 * @setting: %TRUE if underlines in the text indicate mnemonics
3445 * If true, an underline in the text indicates the next character should be
3446 * used for the mnemonic accelerator key.
3449 gtk_label_set_use_underline (GtkLabel *label,
3452 g_return_if_fail (GTK_IS_LABEL (label));
3454 gtk_label_set_use_underline_internal (label, setting);
3455 gtk_label_recalculate (label);
3456 if (label->use_underline)
3457 gtk_label_setup_mnemonic (label, label->mnemonic_keyval);
3461 * gtk_label_get_use_underline:
3462 * @label: a #GtkLabel
3464 * Returns whether an embedded underline in the label indicates a
3465 * mnemonic. See gtk_label_set_use_underline ().
3467 * Return value: %TRUE whether an embedded underline in the label indicates
3468 * the mnemonic accelerator keys.
3471 gtk_label_get_use_underline (GtkLabel *label)
3473 g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
3475 return label->use_underline;
3479 * gtk_label_set_single_line_mode:
3480 * @label: a #GtkLabel
3481 * @single_line_mode: %TRUE if the label should be in single line mode
3483 * Sets whether the label is in single line mode.
3488 gtk_label_set_single_line_mode (GtkLabel *label,
3489 gboolean single_line_mode)
3491 GtkLabelPrivate *priv;
3493 g_return_if_fail (GTK_IS_LABEL (label));
3495 single_line_mode = single_line_mode != FALSE;
3497 priv = GTK_LABEL_GET_PRIVATE (label);
3498 if (priv->single_line_mode != single_line_mode)
3500 priv->single_line_mode = single_line_mode;
3502 gtk_label_clear_layout (label);
3503 gtk_widget_queue_resize (GTK_WIDGET (label));
3505 g_object_notify (G_OBJECT (label), "single-line-mode");
3510 * gtk_label_get_single_line_mode:
3511 * @label: a #GtkLabel
3513 * Returns whether the label is in single line mode.
3515 * Return value: %TRUE when the label is in single line mode.
3520 gtk_label_get_single_line_mode (GtkLabel *label)
3522 GtkLabelPrivate *priv;
3524 g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
3526 priv = GTK_LABEL_GET_PRIVATE (label);
3528 return priv->single_line_mode;
3531 /* Compute the X position for an offset that corresponds to the "more important
3532 * cursor position for that offset. We use this when trying to guess to which
3533 * end of the selection we should go to when the user hits the left or
3537 get_better_cursor (GtkLabel *label,
3542 GdkKeymap *keymap = gdk_keymap_get_for_display (gtk_widget_get_display (GTK_WIDGET (label)));
3543 PangoDirection keymap_direction = gdk_keymap_get_direction (keymap);
3544 PangoDirection cursor_direction = get_cursor_direction (label);
3545 gboolean split_cursor;
3546 PangoRectangle strong_pos, weak_pos;
3548 g_object_get (gtk_widget_get_settings (GTK_WIDGET (label)),
3549 "gtk-split-cursor", &split_cursor,
3552 gtk_label_ensure_layout (label);
3554 pango_layout_get_cursor_pos (label->layout, index,
3555 &strong_pos, &weak_pos);
3559 *x = strong_pos.x / PANGO_SCALE;
3560 *y = strong_pos.y / PANGO_SCALE;
3564 if (keymap_direction == cursor_direction)
3566 *x = strong_pos.x / PANGO_SCALE;
3567 *y = strong_pos.y / PANGO_SCALE;
3571 *x = weak_pos.x / PANGO_SCALE;
3572 *y = weak_pos.y / PANGO_SCALE;
3579 gtk_label_move_logically (GtkLabel *label,
3583 gint offset = g_utf8_pointer_to_offset (label->text,
3584 label->text + start);
3588 PangoLogAttr *log_attrs;
3592 gtk_label_ensure_layout (label);
3594 length = g_utf8_strlen (label->text, -1);
3596 pango_layout_get_log_attrs (label->layout, &log_attrs, &n_attrs);
3598 while (count > 0 && offset < length)
3602 while (offset < length && !log_attrs[offset].is_cursor_position);
3606 while (count < 0 && offset > 0)
3610 while (offset > 0 && !log_attrs[offset].is_cursor_position);
3618 return g_utf8_offset_to_pointer (label->text, offset) - label->text;
3622 gtk_label_move_visually (GtkLabel *label,
3632 int new_index, new_trailing;
3633 gboolean split_cursor;
3636 gtk_label_ensure_layout (label);
3638 g_object_get (gtk_widget_get_settings (GTK_WIDGET (label)),
3639 "gtk-split-cursor", &split_cursor,
3646 GdkKeymap *keymap = gdk_keymap_get_for_display (gtk_widget_get_display (GTK_WIDGET (label)));
3647 PangoDirection keymap_direction = gdk_keymap_get_direction (keymap);
3649 strong = keymap_direction == get_cursor_direction (label);
3654 pango_layout_move_cursor_visually (label->layout, strong, index, 0, 1, &new_index, &new_trailing);
3659 pango_layout_move_cursor_visually (label->layout, strong, index, 0, -1, &new_index, &new_trailing);
3663 if (new_index < 0 || new_index == G_MAXINT)
3668 while (new_trailing--)
3669 index = g_utf8_next_char (label->text + new_index) - label->text;
3676 gtk_label_move_forward_word (GtkLabel *label,
3679 gint new_pos = g_utf8_pointer_to_offset (label->text,
3680 label->text + start);
3683 length = g_utf8_strlen (label->text, -1);
3684 if (new_pos < length)
3686 PangoLogAttr *log_attrs;
3689 gtk_label_ensure_layout (label);
3691 pango_layout_get_log_attrs (label->layout, &log_attrs, &n_attrs);
3693 /* Find the next word end */
3695 while (new_pos < n_attrs && !log_attrs[new_pos].is_word_end)
3701 return g_utf8_offset_to_pointer (label->text, new_pos) - label->text;
3706 gtk_label_move_backward_word (GtkLabel *label,
3709 gint new_pos = g_utf8_pointer_to_offset (label->text,
3710 label->text + start);
3713 length = g_utf8_strlen (label->text, -1);
3717 PangoLogAttr *log_attrs;
3720 gtk_label_ensure_layout (label);
3722 pango_layout_get_log_attrs (label->layout, &log_attrs, &n_attrs);
3726 /* Find the previous word beginning */
3727 while (new_pos > 0 && !log_attrs[new_pos].is_word_start)
3733 return g_utf8_offset_to_pointer (label->text, new_pos) - label->text;
3737 gtk_label_move_cursor (GtkLabel *label,
3738 GtkMovementStep step,
3740 gboolean extend_selection)
3744 if (label->select_info == NULL)
3747 new_pos = label->select_info->selection_end;
3749 if (label->select_info->selection_end != label->select_info->selection_anchor &&
3752 /* If we have a current selection and aren't extending it, move to the
3753 * start/or end of the selection as appropriate
3757 case GTK_MOVEMENT_VISUAL_POSITIONS:
3760 gint anchor_x, anchor_y;
3761 gboolean end_is_left;
3763 get_better_cursor (label, label->select_info->selection_end, &end_x, &end_y);
3764 get_better_cursor (label, label->select_info->selection_anchor, &anchor_x, &anchor_y);
3766 end_is_left = (end_y < anchor_y) || (end_y == anchor_y && end_x < anchor_x);
3769 new_pos = end_is_left ? label->select_info->selection_end : label->select_info->selection_anchor;
3771 new_pos = !end_is_left ? label->select_info->selection_end : label->select_info->selection_anchor;
3775 case GTK_MOVEMENT_LOGICAL_POSITIONS:
3776 case GTK_MOVEMENT_WORDS:
3778 new_pos = MIN (label->select_info->selection_end, label->select_info->selection_anchor);
3780 new_pos = MAX (label->select_info->selection_end, label->select_info->selection_anchor);
3782 case GTK_MOVEMENT_DISPLAY_LINE_ENDS:
3783 case GTK_MOVEMENT_PARAGRAPH_ENDS:
3784 case GTK_MOVEMENT_BUFFER_ENDS:
3785 /* FIXME: Can do better here */
3786 new_pos = count < 0 ? 0 : strlen (label->text);
3788 case GTK_MOVEMENT_DISPLAY_LINES:
3789 case GTK_MOVEMENT_PARAGRAPHS:
3790 case GTK_MOVEMENT_PAGES:
3791 case GTK_MOVEMENT_HORIZONTAL_PAGES:
3799 case GTK_MOVEMENT_LOGICAL_POSITIONS:
3800 new_pos = gtk_label_move_logically (label, new_pos, count);
3802 case GTK_MOVEMENT_VISUAL_POSITIONS:
3803 new_pos = gtk_label_move_visually (label, new_pos, count);
3805 case GTK_MOVEMENT_WORDS:
3808 new_pos = gtk_label_move_forward_word (label, new_pos);
3813 new_pos = gtk_label_move_backward_word (label, new_pos);
3817 case GTK_MOVEMENT_DISPLAY_LINE_ENDS:
3818 case GTK_MOVEMENT_PARAGRAPH_ENDS:
3819 case GTK_MOVEMENT_BUFFER_ENDS:
3820 /* FIXME: Can do better here */
3821 new_pos = count < 0 ? 0 : strlen (label->text);
3823 case GTK_MOVEMENT_DISPLAY_LINES:
3824 case GTK_MOVEMENT_PARAGRAPHS:
3825 case GTK_MOVEMENT_PAGES:
3826 case GTK_MOVEMENT_HORIZONTAL_PAGES:
3831 if (extend_selection)
3832 gtk_label_select_region_index (label,
3833 label->select_info->selection_anchor,
3836 gtk_label_select_region_index (label, new_pos, new_pos);
3840 gtk_label_copy_clipboard (GtkLabel *label)
3842 if (label->text && label->select_info)
3847 start = MIN (label->select_info->selection_anchor,
3848 label->select_info->selection_end);
3849 end = MAX (label->select_info->selection_anchor,
3850 label->select_info->selection_end);
3852 len = strlen (label->text);
3861 gtk_clipboard_set_text (gtk_widget_get_clipboard (GTK_WIDGET (label),
3862 GDK_SELECTION_CLIPBOARD),
3863 label->text + start, end - start);
3868 gtk_label_select_all (GtkLabel *label)
3870 gtk_label_select_region_index (label, 0, strlen (label->text));
3873 /* Quick hack of a popup menu
3876 activate_cb (GtkWidget *menuitem,
3879 const gchar *signal = g_object_get_data (G_OBJECT (menuitem), "gtk-signal");
3880 g_signal_emit_by_name (label, signal);
3884 append_action_signal (GtkLabel *label,
3886 const gchar *stock_id,
3887 const gchar *signal,
3890 GtkWidget *menuitem = gtk_image_menu_item_new_from_stock (stock_id, NULL);
3892 g_object_set_data (G_OBJECT (menuitem), I_("gtk-signal"), (char *)signal);
3893 g_signal_connect (menuitem, "activate",
3894 G_CALLBACK (activate_cb), label);
3896 gtk_widget_set_sensitive (menuitem, sensitive);
3898 gtk_widget_show (menuitem);
3899 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
3903 popup_menu_detach (GtkWidget *attach_widget,
3907 label = GTK_LABEL (attach_widget);
3909 if (label->select_info)
3910 label->select_info->popup_menu = NULL;
3914 popup_position_func (GtkMenu *menu,
3925 label = GTK_LABEL (user_data);
3926 widget = GTK_WIDGET (label);
3928 if (label->select_info == NULL)
3931 g_return_if_fail (GTK_WIDGET_REALIZED (label));
3933 screen = gtk_widget_get_screen (widget);
3934 gdk_window_get_origin (widget->window, x, y);
3936 gtk_widget_size_request (label->select_info->popup_menu, &req);
3938 *x += widget->allocation.width / 2;
3939 *y += widget->allocation.height;
3941 *x = CLAMP (*x, 0, MAX (0, gdk_screen_get_width (screen) - req.width));
3942 *y = CLAMP (*y, 0, MAX (0, gdk_screen_get_height (screen) - req.height));
3947 gtk_label_do_popup (GtkLabel *label,
3948 GdkEventButton *event)
3950 GtkWidget *menuitem;
3951 gboolean have_selection;
3953 if (label->select_info == NULL)
3956 if (label->select_info->popup_menu)
3957 gtk_widget_destroy (label->select_info->popup_menu);
3959 label->select_info->popup_menu = gtk_menu_new ();
3961 gtk_menu_attach_to_widget (GTK_MENU (label->select_info->popup_menu),
3966 label->select_info->selection_anchor != label->select_info->selection_end;
3969 append_action_signal (label, label->select_info->popup_menu, GTK_STOCK_CUT, "cut_clipboard",
3971 append_action_signal (label, label->select_info->popup_menu, GTK_STOCK_COPY, "copy_clipboard",
3973 append_action_signal (label, label->select_info->popup_menu, GTK_STOCK_PASTE, "paste_clipboard",
3976 menuitem = gtk_image_menu_item_new_from_stock (GTK_STOCK_DELETE, NULL);
3977 gtk_widget_set_sensitive (menuitem, FALSE);
3978 gtk_widget_show (menuitem);
3979 gtk_menu_shell_append (GTK_MENU_SHELL (label->select_info->popup_menu), menuitem);
3981 menuitem = gtk_separator_menu_item_new ();
3982 gtk_widget_show (menuitem);
3983 gtk_menu_shell_append (GTK_MENU_SHELL (label->select_info->popup_menu), menuitem);
3985 menuitem = gtk_menu_item_new_with_label (_("Select All"));
3986 g_signal_connect_swapped (menuitem, "activate",
3987 G_CALLBACK (gtk_label_select_all), label);
3988 gtk_widget_show (menuitem);
3989 gtk_menu_shell_append (GTK_MENU_SHELL (label->select_info->popup_menu), menuitem);
3991 g_signal_emit (label,
3992 signals[POPULATE_POPUP],
3994 label->select_info->popup_menu);
3997 gtk_menu_popup (GTK_MENU (label->select_info->popup_menu), NULL, NULL,
3999 event->button, event->time);
4001 gtk_menu_popup (GTK_MENU (label->select_info->popup_menu), NULL, NULL,
4002 popup_position_func, label,
4003 0, gtk_get_current_event_time ());
4006 #define __GTK_LABEL_C__
4007 #include "gtkaliasdef.c"