]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtklabel.c
label: Split out function that merges attr lists
[~andy/gtk] / gtk / gtklabel.c
index 8f213aa09f2f146fca98622b314c3af7b0c7a670..8ee4a7eaaea38fccaa1d8ba892011b6a6c691bbc 100644 (file)
@@ -31,7 +31,6 @@
 #include "gtklabel.h"
 #include "gtkaccellabel.h"
 #include "gtkdnd.h"
-#include "gtkmainprivate.h"
 #include "gtkmarshalers.h"
 #include "gtkpango.h"
 #include "gtkwindow.h"
@@ -40,6 +39,7 @@
 #include "gtkintl.h"
 #include "gtkseparatormenuitem.h"
 #include "gtktextutil.h"
+#include "gtkmain.h"
 #include "gtkmenuitem.h"
 #include "gtkmenushellprivate.h"
 #include "gtknotebook.h"
 #include "gtktooltip.h"
 #include "gtkprivate.h"
 #include "gtktypebuiltins.h"
+#include "gtkmain.h"
 
 #include "a11y/gtklabelaccessible.h"
 
+/* this is in case rint() is not provided by the compiler, 
+ * such as in the case of C89 compilers, like MSVC
+ */
+#include "fallback-c89.c"
+
 /**
  * SECTION:gtklabel
  * @Short_description: A widget that displays a small to medium amount of text
  * </refsect2>
  */
 
-
-/*rint() is only available in GCC and/or C99*/
-#if (__STDC_VERSION__ < 199901L && !defined __GNUC__)
-double rint(double x)
-{
-       if (ceil(x+0.5) == floor(x+0.5))
-       {
-               int a = (int)ceil(x);
-               if (a%2 == 0)
-                       return ceil(x);
-               else
-                       return floor(x);
-       }
-       else
-               return floor(x+0.5);
-}
-#endif
-
-
-
 struct _GtkLabelPrivate
 {
   GtkLabelSelectionInfo *select_info;
@@ -265,7 +251,7 @@ struct _GtkLabelPrivate
 
   gdouble  angle;
 
-  guint     mnemonics_visible : 1;
+  guint    mnemonics_visible  : 1;
   guint    jtype              : 2;
   guint    wrap               : 1;
   guint    use_underline      : 1;
@@ -397,8 +383,8 @@ static void gtk_label_finalize          (GObject          *object);
 static void gtk_label_destroy           (GtkWidget        *widget);
 static void gtk_label_size_allocate     (GtkWidget        *widget,
                                          GtkAllocation    *allocation);
-static void gtk_label_state_changed     (GtkWidget        *widget,
-                                         GtkStateType      state);
+static void gtk_label_state_flags_changed   (GtkWidget        *widget,
+                                             GtkStateFlags     prev_state);
 static void gtk_label_style_updated     (GtkWidget        *widget);
 static void gtk_label_direction_changed (GtkWidget        *widget,
                                         GtkTextDirection  previous_dir);
@@ -437,8 +423,6 @@ static void gtk_label_set_use_markup_internal    (GtkLabel      *label,
                                                  gboolean       val);
 static void gtk_label_set_use_underline_internal (GtkLabel      *label,
                                                  gboolean       val);
-static void gtk_label_set_attributes_internal    (GtkLabel      *label,
-                                                 PangoAttrList *attrs);
 static void gtk_label_set_uline_text_internal    (GtkLabel      *label,
                                                  const gchar   *str);
 static void gtk_label_set_pattern_internal       (GtkLabel      *label,
@@ -465,6 +449,7 @@ static void gtk_label_select_region_index (GtkLabel *label,
                                            gint      anchor_index,
                                            gint      end_index);
 
+
 static gboolean gtk_label_mnemonic_activate (GtkWidget         *widget,
                                             gboolean           group_cycling);
 static void     gtk_label_setup_mnemonic    (GtkLabel          *label,
@@ -512,7 +497,6 @@ static gint gtk_label_move_backward_word (GtkLabel        *label,
                                          gint             start);
 
 /* For links: */
-static void          gtk_label_rescan_links     (GtkLabel  *label);
 static void          gtk_label_clear_links      (GtkLabel  *label);
 static gboolean      gtk_label_activate_link    (GtkLabel    *label,
                                                  const gchar *uri);
@@ -582,7 +566,7 @@ gtk_label_class_init (GtkLabelClass *class)
 
   widget_class->destroy = gtk_label_destroy;
   widget_class->size_allocate = gtk_label_size_allocate;
-  widget_class->state_changed = gtk_label_state_changed;
+  widget_class->state_flags_changed = gtk_label_state_flags_changed;
   widget_class->style_updated = gtk_label_style_updated;
   widget_class->query_tooltip = gtk_label_query_tooltip;
   widget_class->direction_changed = gtk_label_direction_changed;
@@ -1204,24 +1188,10 @@ gtk_label_get_property (GObject     *object,
       g_value_set_object (value, (GObject*) priv->mnemonic_widget);
       break;
     case PROP_CURSOR_POSITION:
-      if (priv->select_info && priv->select_info->selectable)
-       {
-         gint offset = g_utf8_pointer_to_offset (priv->text,
-                                                 priv->text + priv->select_info->selection_end);
-         g_value_set_int (value, offset);
-       }
-      else
-       g_value_set_int (value, 0);
+      g_value_set_int (value, _gtk_label_get_cursor_position (label));
       break;
     case PROP_SELECTION_BOUND:
-      if (priv->select_info && priv->select_info->selectable)
-       {
-         gint offset = g_utf8_pointer_to_offset (priv->text,
-                                                 priv->text + priv->select_info->selection_anchor);
-         g_value_set_int (value, offset);
-       }
-      else
-       g_value_set_int (value, 0);
+      g_value_set_int (value, _gtk_label_get_selection_bound (label));
       break;
     case PROP_ELLIPSIZE:
       g_value_set_enum (value, priv->ellipsize);
@@ -1313,7 +1283,7 @@ attribute_from_text (GtkBuilder   *builder,
   PangoLanguage  *language;
   PangoFontDescription *font_desc;
   GdkColor       *color;
-  GValue          val = { 0, };
+  GValue          val = G_VALUE_INIT;
 
   if (!gtk_builder_value_from_string_type (builder, PANGO_TYPE_ATTR_TYPE, name, &val, error))
     return NULL;
@@ -1469,7 +1439,7 @@ pango_start_element (GMarkupParseContext *context,
                     GError             **error)
 {
   PangoParserData *data = (PangoParserData*)user_data;
-  GValue val = { 0, };
+  GValue val = G_VALUE_INIT;
   guint i;
   gint line_number, char_number;
 
@@ -2065,56 +2035,47 @@ gtk_label_set_use_underline_internal (GtkLabel *label,
 }
 
 static void
-gtk_label_compose_effective_attrs (GtkLabel *label)
+my_pango_attr_list_merge (PangoAttrList *into,
+                          PangoAttrList *from)
 {
-  GtkLabelPrivate      *priv = label->priv;
   PangoAttrIterator *iter;
   PangoAttribute    *attr;
   GSList            *iter_attrs, *l;
 
-  if (priv->attrs)
+  iter = pango_attr_list_get_iterator (into);
+
+  if (iter)
     {
-      if (priv->effective_attrs)
-       {
-         if ((iter = pango_attr_list_get_iterator (priv->attrs)))
-           {
-             do
-               {
-                 iter_attrs = pango_attr_iterator_get_attrs (iter);
-                 for (l = iter_attrs; l; l = l->next)
-                   {
-                     attr = l->data;
-                     pango_attr_list_insert (priv->effective_attrs, attr);
-                   }
-                 g_slist_free (iter_attrs);
-               }
-             while (pango_attr_iterator_next (iter));
-             pango_attr_iterator_destroy (iter);
-           }
-       }
-      else
-       priv->effective_attrs =
-         pango_attr_list_ref (priv->attrs);
+      do
+        {
+          iter_attrs = pango_attr_iterator_get_attrs (iter);
+          for (l = iter_attrs; l; l = l->next)
+            {
+              attr = l->data;
+              pango_attr_list_insert (from, attr);
+            }
+          g_slist_free (iter_attrs);
+        }
+      while (pango_attr_iterator_next (iter));
+      pango_attr_iterator_destroy (iter);
     }
 }
 
 static void
-gtk_label_set_attributes_internal (GtkLabel      *label,
-                                  PangoAttrList *attrs)
+gtk_label_compose_effective_attrs (GtkLabel *label)
 {
   GtkLabelPrivate *priv = label->priv;
 
-  if (attrs)
-    pango_attr_list_ref (attrs);
-
   if (priv->attrs)
-    pango_attr_list_unref (priv->attrs);
-  priv->attrs = attrs;
-
-  g_object_notify (G_OBJECT (label), "attributes");
+    {
+      if (priv->effective_attrs)
+        my_pango_attr_list_merge (priv->effective_attrs, priv->attrs);
+      else
+       priv->effective_attrs =
+         pango_attr_list_ref (priv->attrs);
+    }
 }
 
-
 /* Calculates text, attrs and mnemonic_keyval from
  * label, use_underline and use_markup
  */
@@ -2124,19 +2085,21 @@ gtk_label_recalculate (GtkLabel *label)
   GtkLabelPrivate *priv = label->priv;
   guint keyval = priv->mnemonic_keyval;
 
+  gtk_label_clear_links (label);
+
   if (priv->use_markup)
     gtk_label_set_markup_internal (label, priv->label, priv->use_underline);
+  else if (priv->use_underline)
+    gtk_label_set_uline_text_internal (label, priv->label);
   else
     {
-      if (priv->use_underline)
-       gtk_label_set_uline_text_internal (label, priv->label);
-      else
+      if (!priv->pattern_set)
         {
           if (priv->effective_attrs)
             pango_attr_list_unref (priv->effective_attrs);
           priv->effective_attrs = NULL;
-          gtk_label_set_text_internal (label, g_strdup (priv->label));
         }
+      gtk_label_set_text_internal (label, g_strdup (priv->label));
     }
 
   gtk_label_compose_effective_attrs (label);
@@ -2201,9 +2164,18 @@ void
 gtk_label_set_attributes (GtkLabel         *label,
                           PangoAttrList    *attrs)
 {
+  GtkLabelPrivate *priv = label->priv;
+
   g_return_if_fail (GTK_IS_LABEL (label));
 
-  gtk_label_set_attributes_internal (label, attrs);
+  if (attrs)
+    pango_attr_list_ref (attrs);
+
+  if (priv->attrs)
+    pango_attr_list_unref (priv->attrs);
+  priv->attrs = attrs;
+
+  g_object_notify (G_OBJECT (label), "attributes");
 
   gtk_label_recalculate (label);
 
@@ -2281,6 +2253,7 @@ typedef struct
   GtkLabel *label;
   GList *links;
   GString *new_str;
+  gsize text_len;
   GdkColor *link_color;
   GdkColor *visited_link_color;
 } UriParserData;
@@ -2371,7 +2344,8 @@ start_element_handler (GMarkupParseContext  *context,
       link->uri = g_strdup (uri);
       link->title = g_strdup (title);
       link->visited = visited;
-      pdata->links = g_list_append (pdata->links, link);
+      link->start = pdata->text_len;
+      pdata->links = g_list_prepend (pdata->links, link);
     }
   else
     {
@@ -2409,7 +2383,11 @@ end_element_handler (GMarkupParseContext  *context,
   UriParserData *pdata = user_data;
 
   if (!strcmp (element_name, "a"))
-    g_string_append (pdata->new_str, "</span>");
+    {
+      GtkLabelLink *link = pdata->links->data;
+      link->end = pdata->text_len;
+      g_string_append (pdata->new_str, "</span>");
+    }
   else
     {
       g_string_append (pdata->new_str, "</");
@@ -2430,6 +2408,7 @@ text_handler (GMarkupParseContext  *context,
 
   newtext = g_markup_escape_text (text, text_len);
   g_string_append (pdata->new_str, newtext);
+  pdata->text_len += text_len;
   g_free (newtext);
 }
 
@@ -2494,6 +2473,7 @@ parse_uri_markup (GtkLabel     *label,
   pdata.label = label;
   pdata.links = NULL;
   pdata.new_str = g_string_sized_new (length);
+  pdata.text_len = 0;
 
   gtk_label_get_link_colors (GTK_WIDGET (label), &pdata.link_color, &pdata.visited_link_color);
 
@@ -2536,8 +2516,7 @@ parse_uri_markup (GtkLabel     *label,
 failed:
   g_markup_parse_context_free (context);
   g_string_free (pdata.new_str, TRUE);
-  g_list_foreach (pdata.links, (GFunc)link_free, NULL);
-  g_list_free (pdata.links);
+  g_list_free_full (pdata.links, (GDestroyNotify) link_free);
   gdk_color_free (pdata.link_color);
   gdk_color_free (pdata.visited_link_color);
 
@@ -2585,11 +2564,10 @@ gtk_label_set_markup_internal (GtkLabel    *label,
       return;
     }
 
-  gtk_label_clear_links (label);
   if (links)
     {
       gtk_label_ensure_select_info (label);
-      priv->select_info->links = links;
+      priv->select_info->links = g_list_reverse (links);
       gtk_label_ensure_has_tooltip (label);
     }
 
@@ -2833,7 +2811,7 @@ void
 gtk_label_set_pattern (GtkLabel           *label,
                       const gchar *pattern)
 {
-  GtkLabelPrivate *priv = label->priv;
+  GtkLabelPrivate *priv;
 
   g_return_if_fail (GTK_IS_LABEL (label));
 
@@ -3194,8 +3172,6 @@ gtk_label_clear_layout (GtkLabel *label)
     {
       g_object_unref (priv->layout);
       priv->layout = NULL;
-
-      //gtk_label_clear_links (label);
     }
 }
 
@@ -3428,8 +3404,6 @@ gtk_label_ensure_layout (GtkLabel *label)
       if (priv->effective_attrs)
        pango_layout_set_attributes (priv->layout, priv->effective_attrs);
 
-      gtk_label_rescan_links (label);
-
       switch (priv->jtype)
        {
        case GTK_JUSTIFY_LEFT:
@@ -3863,8 +3837,8 @@ gtk_label_update_cursor (GtkLabel *label)
 }
 
 static void
-gtk_label_state_changed (GtkWidget   *widget,
-                         GtkStateType prev_state)
+gtk_label_state_flags_changed (GtkWidget     *widget,
+                               GtkStateFlags  prev_state)
 {
   GtkLabel *label = GTK_LABEL (widget);
   GtkLabelPrivate *priv = label->priv;
@@ -3877,8 +3851,11 @@ gtk_label_state_changed (GtkWidget   *widget,
       gtk_label_update_cursor (label);
     }
 
-  if (GTK_WIDGET_CLASS (gtk_label_parent_class)->state_changed)
-    GTK_WIDGET_CLASS (gtk_label_parent_class)->state_changed (widget, prev_state);
+  /* We have to clear the layout, fonts etc. may have changed */
+  gtk_label_clear_layout (label);
+
+  if (GTK_WIDGET_CLASS (gtk_label_parent_class)->state_flags_changed)
+    GTK_WIDGET_CLASS (gtk_label_parent_class)->state_flags_changed (widget, prev_state);
 }
 
 static void
@@ -3977,26 +3954,6 @@ get_layout_location (GtkLabel  *label,
     *yp = y;
 }
 
-static void
-draw_insertion_cursor (GtkLabel      *label,
-                       cairo_t       *cr,
-                      GdkRectangle  *cursor_location,
-                      gboolean       is_primary,
-                      PangoDirection direction,
-                      gboolean       draw_arrow)
-{
-  GtkWidget *widget = GTK_WIDGET (label);
-  GtkTextDirection text_dir;
-
-  if (direction == PANGO_DIRECTION_LTR)
-    text_dir = GTK_TEXT_DIR_LTR;
-  else
-    text_dir = GTK_TEXT_DIR_RTL;
-
-  gtk_draw_insertion_cursor (widget, cr, cursor_location,
-                            is_primary, text_dir, draw_arrow);
-}
-
 static PangoDirection
 get_cursor_direction (GtkLabel *label)
 {
@@ -4025,85 +3982,6 @@ get_cursor_direction (GtkLabel *label)
   return PANGO_DIRECTION_LTR;
 }
 
-static void
-gtk_label_draw_cursor (GtkLabel  *label, cairo_t *cr, gint xoffset, gint yoffset)
-{
-  GtkLabelPrivate *priv = label->priv;
-  GtkWidget *widget;
-
-  if (priv->select_info == NULL)
-    return;
-
-  widget = GTK_WIDGET (label);
-  
-  if (gtk_widget_is_drawable (widget))
-    {
-      PangoDirection keymap_direction;
-      PangoDirection cursor_direction;
-      PangoRectangle strong_pos, weak_pos;
-      gboolean split_cursor;
-      PangoRectangle *cursor1 = NULL;
-      PangoRectangle *cursor2 = NULL;
-      GdkRectangle cursor_location;
-      PangoDirection dir1 = PANGO_DIRECTION_NEUTRAL;
-      PangoDirection dir2 = PANGO_DIRECTION_NEUTRAL;
-
-      keymap_direction = gdk_keymap_get_direction (gdk_keymap_get_for_display (gtk_widget_get_display (widget)));
-      cursor_direction = get_cursor_direction (label);
-
-      gtk_label_ensure_layout (label);
-      
-      pango_layout_get_cursor_pos (priv->layout, priv->select_info->selection_end,
-                                  &strong_pos, &weak_pos);
-
-      g_object_get (gtk_widget_get_settings (widget),
-                   "gtk-split-cursor", &split_cursor,
-                   NULL);
-
-      dir1 = cursor_direction;
-      
-      if (split_cursor)
-       {
-         cursor1 = &strong_pos;
-
-         if (strong_pos.x != weak_pos.x ||
-             strong_pos.y != weak_pos.y)
-           {
-             dir2 = (cursor_direction == PANGO_DIRECTION_LTR) ? PANGO_DIRECTION_RTL : PANGO_DIRECTION_LTR;
-             cursor2 = &weak_pos;
-           }
-       }
-      else
-       {
-         if (keymap_direction == cursor_direction)
-           cursor1 = &strong_pos;
-         else
-           cursor1 = &weak_pos;
-       }
-      
-      cursor_location.x = xoffset + PANGO_PIXELS (cursor1->x);
-      cursor_location.y = yoffset + PANGO_PIXELS (cursor1->y);
-      cursor_location.width = 0;
-      cursor_location.height = PANGO_PIXELS (cursor1->height);
-
-      draw_insertion_cursor (label, cr,
-                            &cursor_location, TRUE, dir1,
-                            dir2 != PANGO_DIRECTION_NEUTRAL);
-      
-      if (dir2 != PANGO_DIRECTION_NEUTRAL)
-       {
-         cursor_location.x = xoffset + PANGO_PIXELS (cursor2->x);
-         cursor_location.y = yoffset + PANGO_PIXELS (cursor2->y);
-         cursor_location.width = 0;
-         cursor_location.height = PANGO_PIXELS (cursor2->height);
-
-         draw_insertion_cursor (label, cr,
-                                &cursor_location, FALSE, dir2,
-                                TRUE);
-       }
-    }
-}
-
 static GtkLabelLink *
 gtk_label_get_focus_link (GtkLabel *label)
 {
@@ -4144,8 +4022,6 @@ gtk_label_draw (GtkWidget *widget,
 
   if (priv->text && (*priv->text != '\0'))
     {
-      GdkRGBA bg_color, fg_color;
-
       get_layout_location (label, &x, &y);
 
       context = gtk_widget_get_style_context (widget);
@@ -4153,18 +4029,18 @@ gtk_label_draw (GtkWidget *widget,
 
       cairo_translate (cr, -allocation.x, -allocation.y);
 
-      state = gtk_widget_get_state_flags (widget);
-      gtk_style_context_set_state (context, state);
-
       gtk_render_layout (context, cr,
                          x, y,
                          priv->layout);
 
+      state = gtk_widget_get_state_flags (widget);
+
       if (info &&
           (info->selection_anchor != info->selection_end))
         {
           gint range[2];
           cairo_region_t *clip;
+          GdkRGBA bg_color, fg_color;
 
           range[0] = info->selection_anchor;
           range[1] = info->selection_end;
@@ -4187,10 +4063,7 @@ gtk_label_draw (GtkWidget *widget,
           gdk_cairo_region (cr, clip);
           cairo_clip (cr);
 
-          state = GTK_STATE_FLAG_SELECTED;
-
-          if (gtk_widget_has_focus (widget))
-            state |= GTK_STATE_FLAG_FOCUSED;
+          state |= GTK_STATE_FLAG_SELECTED;
 
           gtk_style_context_get_color (context, state, &fg_color);
           gtk_style_context_get_background_color (context, state, &bg_color);
@@ -4216,13 +4089,22 @@ gtk_label_draw (GtkWidget *widget,
           GdkColor *link_color;
           GdkColor *visited_link_color;
 
-          if (info->selectable && gtk_widget_has_focus (widget))
-            gtk_label_draw_cursor (label, cr, x, y);
+          if (info->selectable &&
+              gtk_widget_has_focus (widget) &&
+              gtk_widget_is_drawable (widget))
+            {
+              PangoDirection cursor_direction;
+
+              cursor_direction = get_cursor_direction (label);
+              gtk_render_insertion_cursor (context, cr,
+                                           x, y,
+                                           priv->layout, priv->select_info->selection_end,
+                                           cursor_direction);
+            }
 
           focus_link = gtk_label_get_focus_link (label);
           active_link = info->active_link;
 
-
           if (active_link)
             {
               GdkRGBA bg_color;
@@ -4247,9 +4129,9 @@ gtk_label_draw (GtkWidget *widget,
                 text_color = link_color;
 
               if (info->link_clicked)
-                state = GTK_STATE_FLAG_ACTIVE;
+                state |= GTK_STATE_FLAG_ACTIVE;
               else
-                state = GTK_STATE_FLAG_PRELIGHT;
+                state |= GTK_STATE_FLAG_PRELIGHT;
 
               gtk_style_context_get_background_color (context, state, &bg_color);
 
@@ -4266,7 +4148,7 @@ gtk_label_draw (GtkWidget *widget,
               cairo_restore (cr);
             }
 
-          if (focus_link && gtk_widget_has_focus (widget))
+          if (focus_link && gtk_widget_has_visible_focus (widget))
             {
               range[0] = focus_link->start;
               range[1] = focus_link->end;
@@ -4277,9 +4159,6 @@ gtk_label_draw (GtkWidget *widget,
                                                        1);
               cairo_region_get_extents (clip, &rect);
 
-              state = gtk_widget_get_state_flags (widget);
-              gtk_style_context_set_state (context, state);
-
               gtk_render_focus (context, cr,
                                 rect.x, rect.y,
                                 rect.width, rect.height);
@@ -4744,16 +4623,16 @@ gtk_label_button_press (GtkWidget      *widget,
 
   if (info->active_link)
     {
-      if (event->button == 1)
+      if (gdk_event_triggers_context_menu ((GdkEvent *) event))
         {
           info->link_clicked = 1;
-          gtk_widget_queue_draw (widget);
+          gtk_label_do_popup (label, event);
+          return TRUE;
         }
-      else if (event->button == 3 && event->type == GDK_BUTTON_PRESS)
+      else if (event->button == 1)
         {
           info->link_clicked = 1;
-          gtk_label_do_popup (label, event);
-          return TRUE;
+          gtk_widget_queue_draw (widget);
         }
     }
 
@@ -4763,7 +4642,13 @@ gtk_label_button_press (GtkWidget      *widget,
   info->in_drag = FALSE;
   info->select_words = FALSE;
 
-  if (event->button == 1)
+  if (gdk_event_triggers_context_menu ((GdkEvent *) event))
+    {
+      gtk_label_do_popup (label, event);
+
+      return TRUE;
+    }
+  else if (event->button == 1)
     {
       if (!gtk_widget_has_focus (widget))
         {
@@ -4837,12 +4722,7 @@ gtk_label_button_press (GtkWidget      *widget,
 
       return TRUE;
     }
-  else if (event->button == 3 && event->type == GDK_BUTTON_PRESS)
-    {
-      gtk_label_do_popup (label, event);
 
-      return TRUE;
-    }
   return FALSE;
 }
 
@@ -5362,7 +5242,8 @@ gtk_label_set_selection_text (GtkLabel         *label,
 {
   GtkLabelPrivate *priv = label->priv;
 
-  if ((priv->select_info->selection_anchor !=
+  if (priv->select_info &&
+      (priv->select_info->selection_anchor !=
        priv->select_info->selection_end) &&
       priv->text)
     {
@@ -5441,14 +5322,24 @@ gtk_label_select_region_index (GtkLabel *label,
       GtkClipboard *clipboard;
 
       if (priv->select_info->selection_anchor == anchor_index &&
-         priv->select_info->selection_end == end_index)
-       return;
+          priv->select_info->selection_end == end_index)
+        return;
+
+      g_object_freeze_notify (G_OBJECT (label));
+
+      if (priv->select_info->selection_anchor != anchor_index)
+        g_object_notify (G_OBJECT (label), "selection-bound");
+      if (priv->select_info->selection_end != end_index)
+        g_object_notify (G_OBJECT (label), "cursor-position");
 
       priv->select_info->selection_anchor = anchor_index;
       priv->select_info->selection_end = end_index;
 
-      clipboard = gtk_widget_get_clipboard (GTK_WIDGET (label),
-                                           GDK_SELECTION_PRIMARY);
+      if (gtk_widget_has_screen (GTK_WIDGET (label)))
+        clipboard = gtk_widget_get_clipboard (GTK_WIDGET (label),
+                                              GDK_SELECTION_PRIMARY);
+      else
+        clipboard = NULL;
 
       if (anchor_index != end_index)
         {
@@ -5460,26 +5351,25 @@ gtk_label_select_region_index (GtkLabel *label,
           gtk_target_list_add_text_targets (list, 0);
           targets = gtk_target_table_new_from_list (list, &n_targets);
 
-          gtk_clipboard_set_with_owner (clipboard,
-                                        targets, n_targets,
-                                        get_text_callback,
-                                        clear_text_callback,
-                                        G_OBJECT (label));
+          if (clipboard)
+            gtk_clipboard_set_with_owner (clipboard,
+                                          targets, n_targets,
+                                          get_text_callback,
+                                          clear_text_callback,
+                                          G_OBJECT (label));
 
           gtk_target_table_free (targets, n_targets);
           gtk_target_list_unref (list);
         }
       else
         {
-          if (gtk_clipboard_get_owner (clipboard) == G_OBJECT (label))
+          if (clipboard &&
+              gtk_clipboard_get_owner (clipboard) == G_OBJECT (label))
             gtk_clipboard_clear (clipboard);
         }
 
       gtk_widget_queue_draw (GTK_WIDGET (label));
 
-      g_object_freeze_notify (G_OBJECT (label));
-      g_object_notify (G_OBJECT (label), "cursor-position");
-      g_object_notify (G_OBJECT (label), "selection-bound");
       g_object_thaw_notify (G_OBJECT (label));
     }
 }
@@ -5661,8 +5551,12 @@ gtk_label_set_use_markup (GtkLabel *label,
 {
   g_return_if_fail (GTK_IS_LABEL (label));
 
+  g_object_freeze_notify (G_OBJECT (label));
+
   gtk_label_set_use_markup_internal (label, setting);
   gtk_label_recalculate (label);
+
+  g_object_thaw_notify (G_OBJECT (label));
 }
 
 /**
@@ -5697,8 +5591,12 @@ gtk_label_set_use_underline (GtkLabel *label,
 {
   g_return_if_fail (GTK_IS_LABEL (label));
 
+  g_object_freeze_notify (G_OBJECT (label));
+
   gtk_label_set_use_underline_internal (label, setting);
   gtk_label_recalculate (label);
+
+  g_object_thaw_notify (G_OBJECT (label));
 }
 
 /**
@@ -6370,67 +6268,11 @@ gtk_label_clear_links (GtkLabel *label)
   if (!priv->select_info)
     return;
 
-  g_list_foreach (priv->select_info->links, (GFunc)link_free, NULL);
-  g_list_free (priv->select_info->links);
+  g_list_free_full (priv->select_info->links, (GDestroyNotify) link_free);
   priv->select_info->links = NULL;
   priv->select_info->active_link = NULL;
 }
 
-static void
-gtk_label_rescan_links (GtkLabel *label)
-{
-  GtkLabelPrivate *priv = label->priv;
-  PangoLayout *layout = priv->layout;
-  PangoAttrList *attlist;
-  PangoAttrIterator *iter;
-  GList *links;
-
-  if (!priv->select_info || !priv->select_info->links)
-    return;
-
-  attlist = pango_layout_get_attributes (layout);
-
-  if (attlist == NULL)
-    return;
-
-  iter = pango_attr_list_get_iterator (attlist);
-
-  links = priv->select_info->links;
-
-  do
-    {
-      PangoAttribute *underline;
-      PangoAttribute *color;
-
-      underline = pango_attr_iterator_get (iter, PANGO_ATTR_UNDERLINE);
-      color = pango_attr_iterator_get (iter, PANGO_ATTR_FOREGROUND);
-
-      if (underline != NULL && color != NULL)
-        {
-          gint start, end;
-          PangoRectangle start_pos;
-          PangoRectangle end_pos;
-          GtkLabelLink *link;
-
-          pango_attr_iterator_range (iter, &start, &end);
-          pango_layout_index_to_pos (layout, start, &start_pos);
-          pango_layout_index_to_pos (layout, end, &end_pos);
-
-          if (links == NULL)
-            {
-              g_warning ("Ran out of links");
-              break;
-            }
-          link = links->data;
-          links = links->next;
-          link->start = start;
-          link->end = end;
-        }
-      } while (pango_attr_iterator_next (iter));
-
-    pango_attr_iterator_destroy (iter);
-}
-
 static gboolean
 gtk_label_activate_link (GtkLabel    *label,
                          const gchar *uri)
@@ -6650,3 +6492,27 @@ gtk_label_query_tooltip (GtkWidget  *widget,
                                                                    keyboard_tip,
                                                                    tooltip);
 }
+
+gint
+_gtk_label_get_cursor_position (GtkLabel *label)
+{
+  GtkLabelPrivate *priv = label->priv;
+
+  if (priv->select_info && priv->select_info->selectable)
+    return g_utf8_pointer_to_offset (priv->text,
+                                     priv->text + priv->select_info->selection_end);
+
+  return 0;
+}
+
+gint
+_gtk_label_get_selection_bound (GtkLabel *label)
+{
+  GtkLabelPrivate *priv = label->priv;
+
+  if (priv->select_info && priv->select_info->selectable)
+    return g_utf8_pointer_to_offset (priv->text,
+                                     priv->text + priv->select_info->selection_anchor);
+
+  return 0;
+}