]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtklabel.c
Enforce the widget/child realization/mapping invariants.
[~andy/gtk] / gtk / gtklabel.c
index 79255812d3a5c7e77d8a8b359fd318432c0baf18..a47a19978a0a656d96e0bae98dbf15628a2f140c 100644 (file)
@@ -74,6 +74,8 @@ static void gtk_label_size_request      (GtkWidget        *widget,
                                         GtkRequisition   *requisition);
 static void gtk_label_size_allocate     (GtkWidget        *widget,
                                          GtkAllocation    *allocation);
+static void gtk_label_state_changed     (GtkWidget        *widget,
+                                         GtkStateType      state);
 static void gtk_label_style_set         (GtkWidget        *widget,
                                         GtkStyle         *previous_style);
 static void gtk_label_direction_changed (GtkWidget        *widget,
@@ -111,7 +113,8 @@ static void set_markup                           (GtkLabel      *label,
                                                  const gchar   *str,
                                                  gboolean       with_uline);
 static void gtk_label_recalculate                (GtkLabel      *label);
-static void gtk_label_hierarchy_changed          (GtkWidget     *widget);
+static void gtk_label_hierarchy_changed          (GtkWidget     *widget,
+                                                 GtkWidget     *old_toplevel);
 
 static void gtk_label_create_window       (GtkLabel *label);
 static void gtk_label_destroy_window      (GtkLabel *label);
@@ -123,8 +126,10 @@ static void gtk_label_select_region_index (GtkLabel *label,
                                            gint      anchor_index,
                                            gint      end_index);
 
-static gboolean gtk_label_activate_mnemonic (GtkWidget *widget,
+static gboolean gtk_label_mnemonic_activate (GtkWidget *widget,
                                             gboolean   group_cycling);
+static void     gtk_label_setup_mnemonic    (GtkLabel  *label,
+                                            guint      last_key);
 
 
 static GtkMiscClass *parent_class = NULL;
@@ -173,6 +178,7 @@ gtk_label_class_init (GtkLabelClass *class)
   
   widget_class->size_request = gtk_label_size_request;
   widget_class->size_allocate = gtk_label_size_allocate;
+  widget_class->state_changed = gtk_label_state_changed;
   widget_class->style_set = gtk_label_style_set;
   widget_class->direction_changed = gtk_label_direction_changed;
   widget_class->expose_event = gtk_label_expose;
@@ -184,7 +190,7 @@ gtk_label_class_init (GtkLabelClass *class)
   widget_class->button_release_event = gtk_label_button_release;
   widget_class->motion_notify_event = gtk_label_motion;
   widget_class->hierarchy_changed = gtk_label_hierarchy_changed;
-  widget_class->activate_mnemonic = gtk_label_activate_mnemonic;
+  widget_class->mnemonic_activate = gtk_label_mnemonic_activate;
 
   g_object_class_install_property (G_OBJECT_CLASS(object_class),
                                    PROP_LABEL,
@@ -272,26 +278,24 @@ gtk_label_set_property (GObject      *object,
                        GParamSpec   *pspec)
 {
   GtkLabel *label;
-  
+  guint last_keyval;
+
   label = GTK_LABEL (object);
+  last_keyval = label->mnemonic_keyval;
   
   switch (prop_id)
     {
     case PROP_LABEL:
-      gtk_label_set_label_internal (label,
-                                   g_strdup (g_value_get_string (value)));
-      gtk_label_recalculate (label);
+      gtk_label_set_label (label, g_value_get_string (value));
       break;
     case PROP_ATTRIBUTES:
       gtk_label_set_attributes (label, g_value_get_boxed (value));
       break;
     case PROP_USE_MARKUP:
-      gtk_label_set_use_markup_internal (label, g_value_get_boolean (value));
-      gtk_label_recalculate (label);
+      gtk_label_set_use_markup (label, g_value_get_boolean (value));
       break;
     case PROP_USE_UNDERLINE:
-      gtk_label_set_use_underline_internal (label, g_value_get_boolean (value));
-      gtk_label_recalculate (label);
+      gtk_label_set_use_underline (label, g_value_get_boolean (value));
       break;
     case PROP_JUSTIFY:
       gtk_label_set_justify (label, g_value_get_enum (value));
@@ -387,9 +391,10 @@ gtk_label_init (GtkLabel *label)
 /**
  * gtk_label_new:
  * @str: The text of the label
- * @returns: a new #GtkLabel
  *
  * Creates a new #GtkLabel, containing the text in @str.
+ *
+ * Return value: the new #GtkLabel
  **/
 GtkWidget*
 gtk_label_new (const gchar *str)
@@ -408,14 +413,23 @@ gtk_label_new (const gchar *str)
  * gtk_label_new_with_mnemonic:
  * @str: The text of the label, with an underscore in front of the
  *       mnemonic character
- * @returns: a new #GtkLabel
  *
  * Creates a new #GtkLabel, containing the text in @str.
  *
- * If characters in @str are preceded by an underscore, they are underlined
- * indicating that they represent a keyboard accelerator called a mnemonic.
- * The mnemonic key can be used to activate another widget, chosen automatically,
- * or explicitly using gtk_label_set_mnemonic_widget().
+ * If characters in @str are preceded by an underscore, they are
+ * underlined indicating that they represent a keyboard accelerator
+ * called a mnemonic.  The mnemonic key can be used to activate
+ * another widget, chosen automatically, or explicitly using
+ * gtk_label_set_mnemonic_widget().
+ * 
+ * If gtk_label_set_mnemonic_widget()
+ * is not called, then the first activatable ancestor of the #GtkLabel
+ * will be chosen as the mnemonic widget. For instance, if the
+ * label is inside a button or menu item, the button or menu item will
+ * automatically become the mnemonic widget and be activated by
+ * the mnemonic.
+ *
+ * Return value: the new #GtkLabel
  **/
 GtkWidget*
 gtk_label_new_with_mnemonic (const gchar *str)
@@ -431,13 +445,13 @@ gtk_label_new_with_mnemonic (const gchar *str)
 }
 
 static gboolean
-gtk_label_activate_mnemonic (GtkWidget *widget,
+gtk_label_mnemonic_activate (GtkWidget *widget,
                             gboolean   group_cycling)
 {
   GtkWidget *parent;
 
   if (GTK_LABEL (widget)->mnemonic_widget)
-    return gtk_widget_activate_mnemonic (GTK_LABEL (widget)->mnemonic_widget, group_cycling);
+    return gtk_widget_mnemonic_activate (GTK_LABEL (widget)->mnemonic_widget, group_cycling);
 
   /* Try to find the widget to activate by traversing the
    * widget's ancestry.
@@ -449,7 +463,7 @@ gtk_label_activate_mnemonic (GtkWidget *widget,
          (!group_cycling && GTK_WIDGET_GET_CLASS (parent)->activate_signal) ||
           (parent->parent && GTK_IS_NOTEBOOK (parent->parent)) ||
          (GTK_IS_MENU_ITEM (parent)))
-       return gtk_widget_activate_mnemonic (parent, group_cycling);
+       return gtk_widget_mnemonic_activate (parent, group_cycling);
       parent = parent->parent;
     }
 
@@ -467,16 +481,18 @@ gtk_label_setup_mnemonic (GtkLabel *label,
   GtkWidget *toplevel;
 
   if (last_key != GDK_VoidSymbol && label->mnemonic_window)
-    gtk_window_remove_mnemonic  (label->mnemonic_window,
-                                last_key,
-                                GTK_WIDGET (label));
+    {
+      gtk_window_remove_mnemonic  (label->mnemonic_window,
+                                  last_key,
+                                  GTK_WIDGET (label));
+      label->mnemonic_window = NULL;
+    }
   
   if (label->mnemonic_keyval == GDK_VoidSymbol)
     return;
   
   toplevel = gtk_widget_get_toplevel (GTK_WIDGET (label));
-  
-  if (GTK_IS_WINDOW (toplevel))
+  if (GTK_WIDGET_TOPLEVEL (toplevel))
     {
       gtk_window_add_mnemonic (GTK_WINDOW (toplevel),
                               label->mnemonic_keyval,
@@ -486,7 +502,8 @@ gtk_label_setup_mnemonic (GtkLabel *label,
 }
 
 static void
-gtk_label_hierarchy_changed (GtkWidget *widget)
+gtk_label_hierarchy_changed (GtkWidget *widget,
+                            GtkWidget *old_toplevel)
 {
   GtkLabel *label = GTK_LABEL (widget);
   
@@ -509,7 +526,7 @@ gtk_label_hierarchy_changed (GtkWidget *widget)
  * (i.e. when the target is a #GtkEntry next to the label) you need to
  * set it explicitly using this function.
  *
- * The target widget will be accelerated by emitting "activate_mnemonic" on it.
+ * The target widget will be accelerated by emitting "mnemonic_activate" on it.
  * The default handler for this signal will activate the widget if there are no
  * mnemonic collisions and toggle focus between the colliding widgets otherwise.
  **/
@@ -528,6 +545,23 @@ gtk_label_set_mnemonic_widget (GtkLabel  *label,
     gtk_widget_ref (label->mnemonic_widget);
 }
 
+/**
+ * gtk_label_get_mnemonic_widget:
+ * @label: a #GtkLabel
+ *
+ * Retrieves the target of the mnemonic (keyboard shortcut) of this
+ * label. See gtk_label_set_mnemonic_widget ().
+ *
+ * Return value: the target of the label's mnemonic, or %NULL if none
+ *               has been set and the default algorithm will be used.
+ **/
+GtkWidget *
+gtk_label_get_mnemonic_widget (GtkLabel *label)
+{
+  g_return_val_if_fail (GTK_IS_LABEL (label), NULL);
+
+  return label->mnemonic_widget;
+}
 
 /**
  * gtk_label_get_mnemonic_keyval:
@@ -571,12 +605,14 @@ gtk_label_set_label_internal (GtkLabel *label,
 
 static void
 gtk_label_set_use_markup_internal (GtkLabel *label,
-                                  gboolean val)
+                                  gboolean  val)
 {
   val = val != FALSE;
   if (label->use_markup != val)
-    g_object_notify (G_OBJECT (label), "use_markup");
-  label->use_markup = val;
+    {
+      g_object_notify (G_OBJECT (label), "use_markup");
+      label->use_markup = val;
+    }
 }
 
 static void
@@ -585,13 +621,15 @@ gtk_label_set_use_underline_internal (GtkLabel *label,
 {
   val = val != FALSE;
   if (label->use_underline != val)
-    g_object_notify (G_OBJECT (label), "use_underline");
-  label->use_underline = val;
+    {
+      g_object_notify (G_OBJECT (label), "use_underline");
+      label->use_underline = val;
+    }
 }
 
 static void
-gtk_label_set_attributes_internal (GtkLabel         *label,
-                                  PangoAttrList    *attrs)
+gtk_label_set_attributes_internal (GtkLabel      *label,
+                                  PangoAttrList *attrs)
 {
   if (attrs)
     pango_attr_list_ref (attrs);
@@ -599,6 +637,14 @@ gtk_label_set_attributes_internal (GtkLabel         *label,
   if (label->attrs)
     pango_attr_list_unref (label->attrs);
 
+  if (!label->use_markup && !label->use_underline)
+    {
+      pango_attr_list_ref (attrs);
+      if (label->effective_attrs)
+       pango_attr_list_unref (label->effective_attrs);
+      label->effective_attrs = attrs;
+    }
+
   label->attrs = attrs;
   g_object_notify (G_OBJECT (label), "attributes");
 }
@@ -611,7 +657,7 @@ static void
 gtk_label_recalculate (GtkLabel *label)
 {
   if (label->use_markup)
-      set_markup (label, label->label, label->use_underline);
+    set_markup (label, label->label, label->use_underline);
   else
     {
       if (label->use_underline)
@@ -619,7 +665,11 @@ gtk_label_recalculate (GtkLabel *label)
       else
        {
          gtk_label_set_text_internal (label, g_strdup (label->label));
-         gtk_label_set_attributes_internal (label, NULL);
+         if (label->attrs)
+           pango_attr_list_ref (label->attrs);
+         if (label->effective_attrs)
+           pango_attr_list_unref (label->effective_attrs);
+         label->effective_attrs = label->attrs;
        }
     }
 
@@ -663,7 +713,8 @@ gtk_label_set_text (GtkLabel    *label,
  * @attrs: a #PangoAttrList
  * 
  * Sets a #PangoAttrList; the attributes in the list are applied to the
- * label text.
+ * label text. The attributes set with this function will be ignored
+ * if label->use_underline or label->use_markup is %TRUE.
  **/
 void
 gtk_label_set_attributes (GtkLabel         *label,
@@ -677,6 +728,72 @@ gtk_label_set_attributes (GtkLabel         *label,
   gtk_widget_queue_resize (GTK_WIDGET (label));
 }
 
+/**
+ * gtk_label_get_attributes:
+ * @label: a #GtkLabel
+ *
+ * Gets the attribute list that was set on the label using
+ * gtk_label_set_attributes(), if any. This function does
+ * not reflect attributes that come from the labels markup
+ * (see gtk_label_set_markup()). If you want to get the
+ * effective attributes for the label, use
+ * pango_layout_get_attribute (gtk_label_get_layout (label)).
+ *
+ * Return value: the attribute list, or %NULL if none was set.
+ **/
+PangoAttrList *
+gtk_label_get_attributes (GtkLabel *label)
+{
+  g_return_val_if_fail (GTK_IS_LABEL (label), NULL);
+
+  return label->attrs;
+}
+
+/**
+ * gtk_label_set_label:
+ * @label: a #GtkLabel
+ * @str: the new text to set for the label
+ *
+ * Sets the text of the label. The label is interpreted as
+ * including embedded underlines and/or Pango markup depending
+ * on the values of label->use_underline and label->use_markup.
+ **/
+void
+gtk_label_set_label (GtkLabel    *label,
+                    const gchar *str)
+{
+  guint last_keyval;
+
+  g_return_if_fail (GTK_IS_LABEL (label));
+  g_return_if_fail (str != NULL);
+
+  last_keyval = label->mnemonic_keyval;
+
+  gtk_label_set_label_internal (label, g_strdup (str));
+  gtk_label_recalculate (label);
+  if (last_keyval != label->mnemonic_keyval)
+    gtk_label_setup_mnemonic (label, last_keyval);
+}
+
+/**
+ * gtk_label_get_label:
+ * @label: a #GtkLabel
+ *
+ * Fetches the text from a label widget including any embedded
+ * underlines indicating mnemonics and Pango markup. (See
+ * gtk_label_get_text ()).
+ *
+ * Return value: the text of the label widget. This string is
+ *   owned by the widget and must not be modified or freed.
+ **/
+G_CONST_RETURN gchar *
+gtk_label_get_label (GtkLabel *label)
+{
+  g_return_val_if_fail (GTK_IS_LABEL (label), NULL);
+
+  return label->label;
+}
+
 static void
 set_markup (GtkLabel    *label,
             const gchar *str,
@@ -706,8 +823,9 @@ set_markup (GtkLabel    *label,
 
   if (attrs)
     {
-      gtk_label_set_attributes_internal (label, attrs);
-      pango_attr_list_unref (attrs);
+      if (label->effective_attrs)
+       pango_attr_list_unref (label->effective_attrs);
+      label->effective_attrs = attrs;
     }
 
   if (accel_char != 0)
@@ -770,15 +888,16 @@ gtk_label_set_markup_with_mnemonic (GtkLabel    *label,
  * gtk_label_get_text:
  * @label: a #GtkLabel
  * 
- * Fetches the text from a label widget
+ * Fetches the text from a label widget, as displayed on the
+ * screen. This does not include any embedded underlines
+ * indicating mnemonics or Pango markup. (See gtk_label_get_label())
  * 
  * Return value: the text in the label widget. This is the internal
- * string used by the label, and must not be modified.
+ *   string used by the label, and must not be modified.
  **/
 G_CONST_RETURN gchar *
 gtk_label_get_text (GtkLabel *label)
 {
-  g_return_val_if_fail (label != NULL, NULL);
   g_return_val_if_fail (GTK_IS_LABEL (label), NULL);
 
   return label->text;
@@ -833,7 +952,9 @@ gtk_label_set_pattern_internal (GtkLabel    *label,
   
   attrs = gtk_label_pattern_to_attrs (label, pattern);
 
-  gtk_label_set_attributes_internal (label, attrs);
+  if (label->effective_attrs)
+    pango_attr_list_unref (label->effective_attrs);
+  label->effective_attrs = attrs;
 }
 
 void
@@ -849,6 +970,14 @@ gtk_label_set_pattern (GtkLabel       *label,
 }
 
 
+/**
+ * gtk_label_set_justify:
+ * @label: a #GtkLabel
+ * @jtype: a #GtkJustification
+ *
+ * Sets the alignment of the lines in the text of the label relative to
+ * each other.
+ **/
 void
 gtk_label_set_justify (GtkLabel        *label,
                       GtkJustification jtype)
@@ -868,6 +997,29 @@ gtk_label_set_justify (GtkLabel        *label,
     }
 }
 
+/**
+ * gtk_label_get_justify:
+ * @label: a #GtkLabel
+ *
+ * Returns the justification of the label. See gtk_label_set_justification ().
+ *
+ * Return value: GtkJustification
+ **/
+GtkJustification
+gtk_label_get_justify (GtkLabel *label)
+{
+  g_return_val_if_fail (GTK_IS_LABEL (label), 0);
+
+  return label->jtype;
+}
+
+/**
+ * gtk_label_set_line_wrap:
+ * @label: a #GtkLabel
+ * @wrap: the setting
+ *
+ * If true, the lines will be wrapped if the text becomes too wide.
+ */
 void
 gtk_label_set_line_wrap (GtkLabel *label,
                         gboolean  wrap)
@@ -885,11 +1037,26 @@ gtk_label_set_line_wrap (GtkLabel *label,
     }
 }
 
+/**
+ * gtk_label_get_line_wrap:
+ * @label: a #GtkLabel
+ *
+ * Returns whether lines in the label are automatically wrapped. See gtk_label_set_line_wrap ().
+ *
+ * Return value: %TRUE if the lines of the label are automatically wrapped.
+ */
+gboolean
+gtk_label_get_line_wrap (GtkLabel *label)
+{
+  g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
+
+  return label->wrap;
+}
+
 void
 gtk_label_get (GtkLabel *label,
               gchar   **str)
 {
-  g_return_if_fail (label != NULL);
   g_return_if_fail (GTK_IS_LABEL (label));
   g_return_if_fail (str != NULL);
   
@@ -924,6 +1091,9 @@ gtk_label_finalize (GObject *object)
   if (label->attrs)
     pango_attr_list_unref (label->attrs);
 
+  if (label->effective_attrs)
+    pango_attr_list_unref (label->effective_attrs);
+
   g_free (label->select_info);
 
   G_OBJECT_CLASS (parent_class)->finalize (object);
@@ -980,8 +1150,8 @@ gtk_label_ensure_layout (GtkLabel *label,
 
       label->layout = gtk_widget_create_pango_layout (widget, label->text);
 
-      if (label->attrs)
-       pango_layout_set_attributes (label->layout, label->attrs);
+      if (label->effective_attrs)
+       pango_layout_set_attributes (label->layout, label->effective_attrs);
       
       switch (label->jtype)
        {
@@ -1145,6 +1315,21 @@ gtk_label_size_allocate (GtkWidget     *widget,
     }
 }
 
+static void
+gtk_label_state_changed (GtkWidget   *widget,
+                         GtkStateType prev_state)
+{
+  GtkLabel *label;
+  
+  label = GTK_LABEL (widget);
+
+  if (label->select_info)
+    gtk_label_select_region (label, 0, 0);
+
+  if (GTK_WIDGET_CLASS (parent_class)->state_changed)
+    GTK_WIDGET_CLASS (parent_class)->state_changed (widget, prev_state);
+}
+
 static void 
 gtk_label_style_set (GtkWidget *widget,
                     GtkStyle  *previous_style)
@@ -1258,6 +1443,7 @@ gtk_label_expose (GtkWidget      *widget,
       gtk_paint_layout (widget->style,
                         widget->window,
                         GTK_WIDGET_STATE (widget),
+                       FALSE,
                         &event->area,
                         widget,
                         "label",
@@ -1738,6 +1924,15 @@ gtk_label_destroy_window (GtkLabel *label)
   label->select_info->window = NULL;
 }
 
+/**
+ * gtk_label_set_selectable:
+ * @label: a #GtkLabel
+ * @setting: %TRUE to allow selecting text in the label
+ *
+ * Selectable labels allow the user to select text from the label, for
+ * copy-and-paste.
+ * 
+ **/
 void
 gtk_label_set_selectable (GtkLabel *label,
                           gboolean  setting)
@@ -1770,6 +1965,9 @@ gtk_label_set_selectable (GtkLabel *label,
     {
       if (label->select_info)
         {
+          /* unselect, to give up the selection */
+          gtk_label_select_region (label, 0, 0);
+          
           if (label->select_info->window)
             gtk_label_destroy_window (label);
 
@@ -1785,6 +1983,14 @@ gtk_label_set_selectable (GtkLabel *label,
     }
 }
 
+/**
+ * gtk_label_get_selectable:
+ * @label: a #GtkLabel
+ * 
+ * Gets the value set by gtk_label_set_selectable().
+ * 
+ * Return value: %TRUE if the user can copy text from the label
+ **/
 gboolean
 gtk_label_get_selectable (GtkLabel *label)
 {
@@ -1809,12 +2015,21 @@ get_text_callback (GtkClipboard     *clipboard,
       label->text)
     {
       gint start, end;
+      gint len;
       
       start = MIN (label->select_info->selection_anchor,
                    label->select_info->selection_end);
       end = MAX (label->select_info->selection_anchor,
                  label->select_info->selection_end);
-      
+
+      len = strlen (label->text);
+
+      if (end > len)
+        end = len;
+
+      if (start > len)
+        start = len;
+
       str = g_strndup (label->text + start,
                        end - start);
       
@@ -1865,19 +2080,39 @@ gtk_label_select_region_index (GtkLabel *label,
       label->select_info->selection_end = end_index;
 
       clipboard = gtk_clipboard_get (GDK_SELECTION_PRIMARY);      
-
-      gtk_clipboard_set_with_owner (clipboard,
-                                    targets,
-                                    G_N_ELEMENTS (targets),
-                                    get_text_callback,
-                                    clear_text_callback,
-                                    G_OBJECT (label));
+      
+      if (anchor_index != end_index)
+        {
+          gtk_clipboard_set_with_owner (clipboard,
+                                        targets,
+                                        G_N_ELEMENTS (targets),
+                                        get_text_callback,
+                                        clear_text_callback,
+                                        G_OBJECT (label));
+        }
+      else
+        {
+          if (gtk_clipboard_get_owner (clipboard) == G_OBJECT (label))
+            gtk_clipboard_clear (clipboard);
+        }
 
       gtk_label_clear_layout (label);
       gtk_widget_queue_draw (GTK_WIDGET (label));
     }
 }
 
+/**
+ * gtk_label_select_region:
+ * @label: a #GtkLabel
+ * @start_offset: start offset (in characters not bytes)
+ * @end_offset: end offset (in characters not bytes)
+ *
+ * Selects a range of characters in the label, if the label is selectable.
+ * See gtk_label_set_selectable(). If the label is not selectable,
+ * this function has no effect. If @start_offset or
+ * @end_offset are -1, then the end of the label will be substituted.
+ * 
+ **/
 void
 gtk_label_select_region  (GtkLabel *label,
                           gint      start_offset,
@@ -1888,8 +2123,8 @@ gtk_label_select_region  (GtkLabel *label,
   if (label->text && label->select_info)
     {
       if (start_offset < 0)
-        start_offset = 0;
-
+        start_offset = g_utf8_strlen (label->text, -1);
+      
       if (end_offset < 0)
         end_offset = g_utf8_strlen (label->text, -1);
       
@@ -1899,6 +2134,96 @@ gtk_label_select_region  (GtkLabel *label,
     }
 }
 
+/**
+ * gtk_label_get_selection_bounds:
+ * @label: a #GtkLabel
+ * @start: return location for start of selection, as a character offset
+ * @end: return location for end of selection, as a character offset
+ * 
+ * Gets the selected range of characters in the label, returning %TRUE
+ * if there's a selection.
+ * 
+ * Return value: %TRUE if selection is non-empty
+ **/
+gboolean
+gtk_label_get_selection_bounds (GtkLabel  *label,
+                                gint      *start,
+                                gint      *end)
+{
+  g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
+
+  if (label->select_info == NULL)
+    {
+      /* not a selectable label */
+      if (start)
+        *start = 0;
+      if (end)
+        *end = 0;
+
+      return FALSE;
+    }
+  else
+    {
+      gint start_index, end_index;
+      gint start_offset, end_offset;
+      gint len;
+      
+      start_index = MIN (label->select_info->selection_anchor,
+                   label->select_info->selection_end);
+      end_index = MAX (label->select_info->selection_anchor,
+                 label->select_info->selection_end);
+
+      len = strlen (label->text);
+
+      if (end_index > len)
+        end_index = len;
+
+      if (start_index > len)
+        start_index = len;
+      
+      start_offset = g_utf8_strlen (label->text, start_index);
+      end_offset = g_utf8_strlen (label->text, end_index);
+
+      if (start_offset > end_offset)
+        {
+          gint tmp = start_offset;
+          start_offset = end_offset;
+          end_offset = tmp;
+        }
+      
+      if (start)
+        *start = start_offset;
+
+      if (end)
+        *end = end_offset;
+
+      return start_offset != end_offset;
+    }
+}
+
+
+/**
+ * gtk_label_get_layout:
+ * @label: a #GtkLabel
+ * 
+ * Gets the #PangoLayout used to display the label.
+ * The layout is useful to e.g. convert text positions to
+ * pixel positions, in combination with gtk_label_get_layout_offsets().
+ * The returned layout is owned by the label so need not be
+ * freed by the caller.
+ * 
+ * Return value: the #PangoLayout for this label
+ **/
+PangoLayout*
+gtk_label_get_layout (GtkLabel *label)
+{
+  g_return_val_if_fail (GTK_IS_LABEL (label), NULL);
+
+  gtk_label_ensure_layout (label, NULL, NULL);
+
+  return label->layout;
+}
+
 /**
  * gtk_label_get_layout_offsets:
  * @label: a #GtkLabel
@@ -1910,7 +2235,9 @@ gtk_label_select_region  (GtkLabel *label,
  * into coordinates inside the #PangoLayout, e.g. to take some action
  * if some part of the label is clicked. Of course you will need to
  * create a #GtkEventBox to receive the events, and pack the label
- * inside it, since labels are a #GTK_NO_WINDOW widget.
+ * inside it, since labels are a #GTK_NO_WINDOW widget. Remember
+ * when using the #PangoLayout functions you need to convert to
+ * and from pixels using PANGO_PIXELS() or #PANGO_SCALE.
  * 
  **/
 void
@@ -1923,3 +2250,75 @@ gtk_label_get_layout_offsets (GtkLabel *label,
   get_layout_location (label, x, y);
 }
 
+/**
+ * gtk_label_set_use_markup:
+ * @label: a #GtkLabel
+ * @setting: %TRUE if the label's text should be parsed for markup.
+ *
+ * Sets whether the text of the label contains markup in Pango's
+ * text markup lango. See gtk_label_set_markup().
+ **/
+void
+gtk_label_set_use_markup (GtkLabel *label,
+                         gboolean  setting)
+{
+  g_return_if_fail (GTK_IS_LABEL (label));
+
+  gtk_label_set_use_markup_internal (label, setting);
+  gtk_label_recalculate (label);
+}
+
+/**
+ * gtk_label_get_use_markup:
+ * @label: a #GtkLabel
+ *
+ * Returns whether the label's text is interpreted as marked up with the
+ * Pango text markup language. See gtk_label_set_use_markup ().
+ *
+ * Return value: %TRUE if the label's text will be parsed for markup.
+ **/
+gboolean
+gtk_label_get_use_markup (GtkLabel *label)
+{
+  g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
+  
+  return label->use_markup;
+}
+
+/**
+ * gtk_label_set_use_underline:
+ * @label: a #GtkLabel
+ * @setting: %TRUE if underlines in the text indicate mnemonics
+ *
+ * If true, an underline in the text indicates the next character should be
+ * used for the mnemonic accelerator key.
+ */
+void
+gtk_label_set_use_underline (GtkLabel *label,
+                            gboolean  setting)
+{
+  g_return_if_fail (GTK_IS_LABEL (label));
+
+  gtk_label_set_use_underline_internal (label, setting);
+  gtk_label_recalculate (label);
+  if (label->use_underline)
+    gtk_label_setup_mnemonic (label, label->mnemonic_keyval);
+}
+
+/**
+ * gtk_label_get_use_underline:
+ * @label: a #GtkLabel
+ *
+ * Returns whether an embedded underline in thef label indicates a
+ * mnemonic. See gtk_label_set_use_underline ().
+ *
+ * Return value: %TRUE whether an embedded underline in the label indicates
+ *               the mnemonic accelerator keys.
+ **/
+gboolean
+gtk_label_get_use_underline (GtkLabel *label)
+{
+  g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
+  
+  return label->use_underline;
+}