X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtklabel.c;h=8d18cf0c8acd34621a29b0256a77b7b50b6873d8;hb=HEAD;hp=a85eabe61aed47c3318335f192517611a192444c;hpb=af7650ce1fb9ae8c33d9c76e5b34aae02b78366f;p=~andy%2Fgtk diff --git a/gtk/gtklabel.c b/gtk/gtklabel.c index a85eabe61..8d18cf0c8 100644 --- a/gtk/gtklabel.c +++ b/gtk/gtklabel.c @@ -12,8 +12,7 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free - * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * License along with this library. If not, see .Free */ /* @@ -31,7 +30,6 @@ #include "gtklabel.h" #include "gtkaccellabel.h" #include "gtkdnd.h" -#include "gtkmainprivate.h" #include "gtkmarshalers.h" #include "gtkpango.h" #include "gtkwindow.h" @@ -40,6 +38,7 @@ #include "gtkintl.h" #include "gtkseparatormenuitem.h" #include "gtktextutil.h" +#include "gtkmain.h" #include "gtkmenuitem.h" #include "gtkmenushellprivate.h" #include "gtknotebook.h" @@ -51,7 +50,14 @@ #include "gtktooltip.h" #include "gtkprivate.h" #include "gtktypebuiltins.h" +#include "gtkmain.h" +#include "a11y/gtklabelaccessibleprivate.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 @@ -60,7 +66,7 @@ * * The #GtkLabel widget displays a small amount of text. As the name * implies, most labels are used to label another widget such as a - * #GtkButton, a #GtkMenuItem, or a #GtkOptionMenu. + * #GtkButton, a #GtkMenuItem, or a #GtkComboBox. * * * GtkLabel as GtkBuildable @@ -229,26 +235,6 @@ * */ - -/*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; @@ -256,7 +242,7 @@ struct _GtkLabelPrivate GtkWindow *mnemonic_window; PangoAttrList *attrs; - PangoAttrList *effective_attrs; + PangoAttrList *markup_attrs; PangoLayout *layout; gchar *label; @@ -264,7 +250,7 @@ struct _GtkLabelPrivate gdouble angle; - guint mnemonics_visible : 1; + guint mnemonics_visible : 1; guint jtype : 2; guint wrap : 1; guint use_underline : 1; @@ -279,7 +265,6 @@ struct _GtkLabelPrivate guint mnemonic_keyval; - gint wrap_width; gint width_chars; gint max_width_chars; }; @@ -397,11 +382,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_style_updated (GtkWidget *widget); -static void gtk_label_direction_changed (GtkWidget *widget, - GtkTextDirection previous_dir); +static void gtk_label_state_flags_changed (GtkWidget *widget, + GtkStateFlags prev_state); static gint gtk_label_draw (GtkWidget *widget, cairo_t *cr); static gboolean gtk_label_focus (GtkWidget *widget, @@ -437,8 +419,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, @@ -461,11 +441,11 @@ static void gtk_label_clear_select_info (GtkLabel *label); static void gtk_label_update_cursor (GtkLabel *label); static void gtk_label_clear_layout (GtkLabel *label); static void gtk_label_ensure_layout (GtkLabel *label); -static void gtk_label_invalidate_wrap_width (GtkLabel *label); 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, @@ -513,15 +493,14 @@ 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); static void gtk_label_activate_current_link (GtkLabel *label); static GtkLabelLink *gtk_label_get_current_link (GtkLabel *label); static void gtk_label_get_link_colors (GtkWidget *widget, - GdkColor **link_color, - GdkColor **visited_link_color); + GdkColor *link_color, + GdkColor *visited_link_color); static void emit_activate_link (GtkLabel *label, GtkLabelLink *link); @@ -583,10 +562,8 @@ 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->style_updated = gtk_label_style_updated; + widget_class->state_flags_changed = gtk_label_state_flags_changed; widget_class->query_tooltip = gtk_label_query_tooltip; - widget_class->direction_changed = gtk_label_direction_changed; widget_class->draw = gtk_label_draw; widget_class->realize = gtk_label_realize; widget_class->unrealize = gtk_label_unrealize; @@ -858,7 +835,7 @@ gtk_label_class_init (GtkLabelClass *class) * * The preferred place to ellipsize the string, if the label does * not have enough room to display the entire string, specified as a - * #PangoEllisizeMode. + * #PangoEllipsizeMode. * * Note that setting this property to a value other than * %PANGO_ELLIPSIZE_NONE has the side-effect that the label requests @@ -1095,6 +1072,8 @@ gtk_label_class_init (GtkLabelClass *class) "activate-current-link", 0); g_type_class_add_private (class, sizeof (GtkLabelPrivate)); + + gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_LABEL_ACCESSIBLE); } static void @@ -1203,24 +1182,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); @@ -1260,7 +1225,6 @@ gtk_label_init (GtkLabel *label) priv->width_chars = -1; priv->max_width_chars = -1; - priv->wrap_width = -1; priv->label = NULL; priv->jtype = GTK_JUSTIFY_LEFT; @@ -1313,7 +1277,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; @@ -1349,8 +1313,16 @@ attribute_from_text (GtkBuilder *builder, attribute = pango_attr_stretch_new (g_value_get_enum (&val)); break; case PANGO_ATTR_UNDERLINE: - if (gtk_builder_value_from_string_type (builder, G_TYPE_BOOLEAN, value, &val, error)) - attribute = pango_attr_underline_new (g_value_get_boolean (&val)); + if (gtk_builder_value_from_string_type (builder, PANGO_TYPE_UNDERLINE, value, &val, NULL)) + attribute = pango_attr_underline_new (g_value_get_enum (&val)); + else + { + /* XXX: allow boolean for backwards compat, so ignore error */ + /* Deprecate this somehow */ + g_value_unset (&val); + if (gtk_builder_value_from_string_type (builder, G_TYPE_BOOLEAN, value, &val, error)) + attribute = pango_attr_underline_new (g_value_get_boolean (&val)); + } break; case PANGO_ATTR_STRIKETHROUGH: if (gtk_builder_value_from_string_type (builder, G_TYPE_BOOLEAN, value, &val, error)) @@ -1461,7 +1433,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; @@ -1534,11 +1506,12 @@ pango_start_element (GMarkupParseContext *context, } attr = attribute_from_text (data->builder, name, value, error); - attr->start_index = start_val; - attr->end_index = end_val; if (attr) { + attr->start_index = start_val; + attr->end_index = end_val; + if (!data->attrs) data->attrs = pango_attr_list_new (); @@ -1874,6 +1847,9 @@ gtk_label_screen_changed (GtkWidget *widget, GtkSettings *settings; gboolean shortcuts_connected; + /* The PangoContext is replaced when the screen changes, so clear the layouts */ + gtk_label_clear_layout (GTK_LABEL (widget)); + if (!gtk_widget_has_screen (widget)) return; @@ -1987,9 +1963,9 @@ gtk_label_get_mnemonic_widget (GtkLabel *label) * * If the label has been set so that it has an mnemonic key this function * returns the keyval used for the mnemonic accelerator. If there is no - * mnemonic set up it returns #GDK_VoidSymbol. + * mnemonic set up it returns #GDK_KEY_VoidSymbol. * - * Returns: GDK keyval usable for accelerators, or #GDK_VoidSymbol + * Returns: GDK keyval usable for accelerators, or #GDK_KEY_VoidSymbol **/ guint gtk_label_get_mnemonic_keyval (GtkLabel *label) @@ -2001,14 +1977,22 @@ gtk_label_get_mnemonic_keyval (GtkLabel *label) static void gtk_label_set_text_internal (GtkLabel *label, - gchar *str) + gchar *str) { GtkLabelPrivate *priv = label->priv; - g_free (priv->text); + if (g_strcmp0 (priv->text, str) == 0) + { + g_free (str); + return; + } + _gtk_label_accessible_text_deleted (label); + g_free (priv->text); priv->text = str; + _gtk_label_accessible_text_inserted (label); + gtk_label_select_region_index (label, 0, 0); } @@ -2055,57 +2039,21 @@ gtk_label_set_use_underline_internal (GtkLabel *label, } } -static void -gtk_label_compose_effective_attrs (GtkLabel *label) +static gboolean +my_pango_attr_list_merge_filter (PangoAttribute *attribute, + gpointer list) { - GtkLabelPrivate *priv = label->priv; - PangoAttrIterator *iter; - PangoAttribute *attr; - GSList *iter_attrs, *l; - - if (priv->attrs) - { - 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); - } + pango_attr_list_change (list, pango_attribute_copy (attribute)); + return FALSE; } static void -gtk_label_set_attributes_internal (GtkLabel *label, - PangoAttrList *attrs) +my_pango_attr_list_merge (PangoAttrList *into, + PangoAttrList *from) { - 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"); + pango_attr_list_filter (from, my_pango_attr_list_merge_filter, into); } - /* Calculates text, attrs and mnemonic_keyval from * label, use_underline and use_markup */ @@ -2115,23 +2063,23 @@ 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)); + if (priv->markup_attrs) + pango_attr_list_unref (priv->markup_attrs); + priv->markup_attrs = NULL; } + gtk_label_set_text_internal (label, g_strdup (priv->label)); } - gtk_label_compose_effective_attrs (label); - if (!priv->use_underline) priv->mnemonic_keyval = GDK_KEY_VoidSymbol; @@ -2192,11 +2140,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; - gtk_label_recalculate (label); + g_object_notify (G_OBJECT (label), "attributes"); gtk_label_clear_layout (label); gtk_widget_queue_resize (GTK_WIDGET (label)); @@ -2259,7 +2214,7 @@ gtk_label_set_label (GtkLabel *label, * 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 * +const gchar * gtk_label_get_label (GtkLabel *label) { g_return_val_if_fail (GTK_IS_LABEL (label), NULL); @@ -2272,8 +2227,7 @@ typedef struct GtkLabel *label; GList *links; GString *new_str; - GdkColor *link_color; - GdkColor *visited_link_color; + gsize text_len; } UriParserData; static void @@ -2296,7 +2250,6 @@ start_element_handler (GMarkupParseContext *context, gint line_number; gint char_number; gint i; - GdkColor *color = NULL; g_markup_parse_context_get_position (context, &line_number, &char_number); @@ -2347,22 +2300,12 @@ start_element_handler (GMarkupParseContext *context, } } - if (visited) - color = pdata->visited_link_color; - else - color = pdata->link_color; - - g_string_append_printf (pdata->new_str, - "", - color->red, - color->green, - color->blue); - link = g_new0 (GtkLabelLink, 1); 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 { @@ -2400,7 +2343,10 @@ end_element_handler (GMarkupParseContext *context, UriParserData *pdata = user_data; if (!strcmp (element_name, "a")) - g_string_append (pdata->new_str, ""); + { + GtkLabelLink *link = pdata->links->data; + link->end = pdata->text_len; + } else { g_string_append (pdata->new_str, "new_str, newtext); + pdata->text_len += text_len; g_free (newtext); } @@ -2448,21 +2395,33 @@ link_free (GtkLabelLink *link) } static void -gtk_label_get_link_colors (GtkWidget *widget, - GdkColor **link_color, - GdkColor **visited_link_color) +gtk_label_get_link_colors (GtkWidget *widget, + GdkColor *link_color, + GdkColor *visited_link_color) { GtkStyleContext *context; + GdkColor *link, *visited; context = gtk_widget_get_style_context (widget); gtk_style_context_get_style (context, - "link-color", link_color, - "visited-link-color", visited_link_color, + "link-color", &link, + "visited-link-color", &visited, NULL); - if (!*link_color) - *link_color = gdk_color_copy (&default_link_color); - if (!*visited_link_color) - *visited_link_color = gdk_color_copy (&default_visited_link_color); + if (link) + { + *link_color = *link; + gdk_color_free (link); + } + else + *link_color = default_link_color; + + if (visited) + { + *visited_link_color = *visited; + gdk_color_free (visited); + } + else + *visited_link_color = default_visited_link_color; } static gboolean @@ -2485,8 +2444,7 @@ parse_uri_markup (GtkLabel *label, pdata.label = label; pdata.links = NULL; pdata.new_str = g_string_sized_new (length); - - gtk_label_get_link_colors (GTK_WIDGET (label), &pdata.link_color, &pdata.visited_link_color); + pdata.text_len = 0; while (p != end && xml_isspace (*p)) p++; @@ -2519,18 +2477,12 @@ parse_uri_markup (GtkLabel *label, *new_str = g_string_free (pdata.new_str, FALSE); *links = pdata.links; - gdk_color_free (pdata.link_color); - gdk_color_free (pdata.visited_link_color); - return TRUE; 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); - gdk_color_free (pdata.link_color); - gdk_color_free (pdata.visited_link_color); + g_list_free_full (pdata.links, (GDestroyNotify) link_free); return FALSE; } @@ -2576,11 +2528,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); } @@ -2635,9 +2586,9 @@ gtk_label_set_markup_internal (GtkLabel *label, if (attrs) { - if (priv->effective_attrs) - pango_attr_list_unref (priv->effective_attrs); - priv->effective_attrs = attrs; + if (priv->markup_attrs) + pango_attr_list_unref (priv->markup_attrs); + priv->markup_attrs = attrs; } if (accel_char != 0) @@ -2724,7 +2675,7 @@ gtk_label_set_markup_with_mnemonic (GtkLabel *label, * Return value: the text in the label widget. This is the internal * string used by the label, and must not be modified. **/ -G_CONST_RETURN gchar * +const gchar * gtk_label_get_text (GtkLabel *label) { g_return_val_if_fail (GTK_IS_LABEL (label), NULL); @@ -2805,9 +2756,9 @@ gtk_label_set_pattern_internal (GtkLabel *label, else attrs = gtk_label_pattern_to_attrs (label, pattern); - if (priv->effective_attrs) - pango_attr_list_unref (priv->effective_attrs); - priv->effective_attrs = attrs; + if (priv->markup_attrs) + pango_attr_list_unref (priv->markup_attrs); + priv->markup_attrs = attrs; } /** @@ -2824,7 +2775,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)); @@ -2970,7 +2921,6 @@ gtk_label_set_width_chars (GtkLabel *label, { priv->width_chars = n_chars; g_object_notify (G_OBJECT (label), "width-chars"); - gtk_label_invalidate_wrap_width (label); gtk_widget_queue_resize (GTK_WIDGET (label)); } } @@ -3018,7 +2968,6 @@ gtk_label_set_max_width_chars (GtkLabel *label, priv->max_width_chars = n_chars; g_object_notify (G_OBJECT (label), "max-width-chars"); - gtk_label_invalidate_wrap_width (label); gtk_widget_queue_resize (GTK_WIDGET (label)); } } @@ -3169,8 +3118,8 @@ gtk_label_finalize (GObject *object) if (priv->attrs) pango_attr_list_unref (priv->attrs); - if (priv->effective_attrs) - pango_attr_list_unref (priv->effective_attrs); + if (priv->markup_attrs) + pango_attr_list_unref (priv->markup_attrs); gtk_label_clear_links (label); g_free (priv->select_info); @@ -3187,31 +3136,9 @@ gtk_label_clear_layout (GtkLabel *label) { g_object_unref (priv->layout); priv->layout = NULL; - - //gtk_label_clear_links (label); } } -static PangoFontMetrics * -get_font_metrics (PangoContext *context, GtkWidget *widget) -{ - GtkStyleContext *style_context; - PangoFontDescription *font; - PangoFontMetrics *retval; - - style_context = gtk_widget_get_style_context (widget); - gtk_style_context_get (style_context, 0, "font", &font, NULL); - - retval = pango_context_get_metrics (context, - font, - pango_context_get_language (context)); - - if (font != NULL) - pango_font_description_free (font); - - return retval; -} - /** * gtk_label_get_measuring_layout: * @label: the label @@ -3283,167 +3210,44 @@ gtk_label_get_measuring_layout (GtkLabel * label, return copy; } -static void -gtk_label_invalidate_wrap_width (GtkLabel *label) -{ - GtkLabelPrivate *priv = label->priv; - - priv->wrap_width = -1; -} - -static gint -get_label_wrap_width (GtkLabel *label) -{ - GtkLabelPrivate *priv = label->priv; - - if (priv->wrap_width < 0) - { - if (priv->width_chars > 0) - { - PangoLayout *layout; - PangoContext *context; - PangoFontMetrics *metrics; - PangoRectangle rect; - gint char_width, digit_width, char_pixels, text_width; - - layout = gtk_label_get_measuring_layout (label, NULL, -1); - context = pango_layout_get_context (layout); - metrics = get_font_metrics (context, GTK_WIDGET (label)); - char_width = pango_font_metrics_get_approximate_char_width (metrics); - digit_width = pango_font_metrics_get_approximate_digit_width (metrics); - char_pixels = MAX (char_width, digit_width); - pango_font_metrics_unref (metrics); - - pango_layout_get_extents (layout, NULL, &rect); - g_object_unref (layout); - - text_width = rect.width; - - priv->wrap_width = PANGO_PIXELS (MAX (text_width, char_pixels * priv->width_chars)); - } - else - { - PangoLayout *layout; - - layout = gtk_widget_create_pango_layout (GTK_WIDGET (label), - "This string is just about long enough."); - pango_layout_get_size (layout, &priv->wrap_width, NULL); - g_object_unref (layout); - } - } - - return priv->wrap_width; -} - -static PangoLayout * -gtk_label_get_layout_with_guessed_wrap_width (GtkLabel *label) -{ - GdkScreen *screen; - PangoRectangle logical_rect; - gint wrap_width, width, height, longest_paragraph; - PangoLayout *layout; - - if (!label->priv->wrap) - return gtk_label_get_measuring_layout (label, NULL, -1); - - screen = gtk_widget_get_screen (GTK_WIDGET (label)); - - layout = gtk_label_get_measuring_layout (label, NULL, -1); - pango_layout_get_extents (layout, NULL, &logical_rect); - - width = logical_rect.width; - /* Try to guess a reasonable maximum width */ - longest_paragraph = width; - - wrap_width = get_label_wrap_width (label); - width = MIN (width, wrap_width); - width = MIN (width, - PANGO_SCALE * (gdk_screen_get_width (screen) + 1) / 2); - - layout = gtk_label_get_measuring_layout (label, layout, width); - - pango_layout_get_extents (layout, NULL, &logical_rect); - width = logical_rect.width; - height = logical_rect.height; - - /* Unfortunately, the above may leave us with a very unbalanced looking paragraph, - * so we try short search for a narrower width that leaves us with the same height - */ - if (longest_paragraph > 0) - { - gint nlines, perfect_width; - - nlines = pango_layout_get_line_count (layout); - perfect_width = (longest_paragraph + nlines - 1) / nlines; - - if (perfect_width < width) - { - layout = gtk_label_get_measuring_layout (label, layout, perfect_width); - pango_layout_get_extents (layout, NULL, &logical_rect); - - if (logical_rect.height <= height) - width = logical_rect.width; - else - { - gint mid_width = (perfect_width + width) / 2; - - if (mid_width > perfect_width) - { - layout = gtk_label_get_measuring_layout (label, layout, mid_width); - pango_layout_get_extents (layout, NULL, &logical_rect); - - if (logical_rect.height <= height) - width = logical_rect.width; - } - } - } - } - - return gtk_label_get_measuring_layout (label, layout, width); -} - static void gtk_label_update_layout_width (GtkLabel *label) { GtkLabelPrivate *priv = label->priv; GtkWidget *widget = GTK_WIDGET (label); - GtkAllocation allocation; g_assert (priv->layout); - gtk_widget_get_allocation (widget, &allocation); - - if (priv->ellipsize) + if (priv->ellipsize || priv->wrap) { + GtkBorder border; PangoRectangle logical; - PangoRectangle bounds; - gint xpad, ypad; + gint width, height; - gtk_misc_get_padding (GTK_MISC (label), &xpad, &ypad); + _gtk_misc_get_padding_and_border (GTK_MISC (label), &border); - bounds.x = bounds.y = 0; - bounds.width = allocation.width - xpad * 2; - bounds.height = allocation.height - ypad * 2; - - pango_layout_set_width (priv->layout, -1); - pango_layout_get_pixel_extents (priv->layout, NULL, &logical); + width = gtk_widget_get_allocated_width (GTK_WIDGET (label)) - border.left - border.right; + height = gtk_widget_get_allocated_height (GTK_WIDGET (label)) - border.top - border.bottom; if (priv->have_transform) { PangoContext *context = gtk_widget_get_pango_context (widget); const PangoMatrix *matrix = pango_context_get_matrix (context); - const gdouble dx = matrix->xx; /* cos (M_PI * angle / 180) */ const gdouble dy = matrix->xy; /* sin (M_PI * angle / 180) */ + + pango_layout_set_width (priv->layout, -1); + pango_layout_get_pixel_extents (priv->layout, NULL, &logical); + if (fabs (dy) < 0.01) { - if (logical.width > bounds.width) - pango_layout_set_width (priv->layout, bounds.width * PANGO_SCALE); + if (logical.width > width) + pango_layout_set_width (priv->layout, width * PANGO_SCALE); } else if (fabs (dx) < 0.01) { - if (logical.width > bounds.height) - pango_layout_set_width (priv->layout, bounds.height * PANGO_SCALE); + if (logical.width > height) + pango_layout_set_width (priv->layout, height * PANGO_SCALE); } else { @@ -3451,13 +3255,13 @@ gtk_label_update_layout_width (GtkLabel *label) gboolean vertical; gint cy; - x0 = bounds.width / 2; + x0 = width / 2; y0 = dx ? x0 * dy / dx : G_MAXDOUBLE; - vertical = fabs (y0) > bounds.height / 2; + vertical = fabs (y0) > height / 2; if (vertical) { - y0 = bounds.height/2; + y0 = height/2; x0 = dy ? y0 * dx / dy : G_MAXDOUBLE; } @@ -3470,12 +3274,12 @@ gtk_label_update_layout_width (GtkLabel *label) if (vertical) { - y0 = bounds.height/2 + y1 - y0; + y0 = height/2 + y1 - y0; x0 = -y0 * dx/dy; } else { - x0 = bounds.width/2 + x1 - x0; + x0 = width/2 + x1 - x0; y0 = -x0 * dy/dx; } @@ -3483,39 +3287,15 @@ gtk_label_update_layout_width (GtkLabel *label) pango_layout_set_width (priv->layout, rint (length * PANGO_SCALE)); } } - else if (logical.width > bounds.width) - pango_layout_set_width (priv->layout, bounds.width * PANGO_SCALE); - } - else if (priv->wrap) - { - GtkWidgetAuxInfo *aux_info = _gtk_widget_get_aux_info (widget, FALSE); - gdouble angle = gtk_label_get_angle (label); - gint width; - gint aux_width = 0; - - if ((angle == 90 || angle == 270) && aux_info && aux_info->height > 0) - aux_width = aux_info->height; - else if (aux_info && aux_info->width > 0) - aux_width = aux_info->width; - - if (aux_width > 0) - pango_layout_set_width (priv->layout, aux_width * PANGO_SCALE); else { - gint xpad, ypad; - gtk_misc_get_padding (GTK_MISC (label), &xpad, &ypad); - - if (angle == 90 || angle == 270) - width = allocation.height - ypad * 2; - else - width = allocation.width - xpad * 2; - - pango_layout_set_wrap (priv->layout, priv->wrap_mode); - pango_layout_set_width (priv->layout, MAX (width, 1) * PANGO_SCALE); + pango_layout_set_width (priv->layout, width * PANGO_SCALE); } } - else /* !priv->wrap */ - pango_layout_set_width (priv->layout, -1); + else + { + pango_layout_set_width (priv->layout, -1); + } } static void @@ -3532,6 +3312,7 @@ gtk_label_ensure_layout (GtkLabel *label) if (!priv->layout) { PangoAlignment align = PANGO_ALIGN_LEFT; /* Quiet gcc */ + PangoAttrList *attrs; gdouble angle = gtk_label_get_angle (label); if (angle != 0.0 && !priv->select_info) @@ -3558,10 +3339,63 @@ gtk_label_ensure_layout (GtkLabel *label) priv->layout = gtk_widget_create_pango_layout (widget, priv->text); - if (priv->effective_attrs) - pango_layout_set_attributes (priv->layout, priv->effective_attrs); + if (priv->select_info && priv->select_info->links) + { + GdkColor link_color, visited_color; + PangoAttribute *attribute; + GList *list; + + gtk_label_get_link_colors (widget, &link_color, &visited_color); + attrs = pango_attr_list_new (); + + for (list = priv->select_info->links; list; list = list->next) + { + GtkLabelLink *link = list->data; - gtk_label_rescan_links (label); + attribute = pango_attr_underline_new (TRUE); + attribute->start_index = link->start; + attribute->end_index = link->end; + pango_attr_list_insert (attrs, attribute); + + if (link->visited) + attribute = pango_attr_foreground_new (visited_color.red, + visited_color.green, + visited_color.blue); + else + attribute = pango_attr_foreground_new (link_color.red, + link_color.green, + link_color.blue); + attribute->start_index = link->start; + attribute->end_index = link->end; + pango_attr_list_insert (attrs, attribute); + } + } + else if (priv->markup_attrs || priv->attrs) + attrs = pango_attr_list_new (); + else + attrs = NULL; + + if (priv->markup_attrs) + { + if (attrs) + my_pango_attr_list_merge (attrs, priv->markup_attrs); + else + attrs = pango_attr_list_ref (priv->markup_attrs); + } + + if (priv->attrs) + { + if (attrs) + my_pango_attr_list_merge (attrs, priv->attrs); + else + attrs = pango_attr_list_ref (priv->attrs); + } + + if (attrs) + { + pango_layout_set_attributes (priv->layout, attrs); + pango_attr_list_unref (attrs); + } switch (priv->jtype) { @@ -3584,29 +3418,13 @@ gtk_label_ensure_layout (GtkLabel *label) pango_layout_set_alignment (priv->layout, align); pango_layout_set_ellipsize (priv->layout, priv->ellipsize); + pango_layout_set_wrap (priv->layout, priv->wrap_mode); pango_layout_set_single_paragraph_mode (priv->layout, priv->single_line_mode); gtk_label_update_layout_width (label); } } -static gint -get_single_line_height (GtkWidget *widget, - PangoLayout *layout) -{ - PangoContext *context; - PangoFontMetrics *metrics; - gint ascent, descent; - - context = pango_layout_get_context (layout); - metrics = get_font_metrics (context, widget); - ascent = pango_font_metrics_get_ascent (metrics); - descent = pango_font_metrics_get_descent (metrics); - pango_font_metrics_unref (metrics); - - return ascent + descent; -} - static GtkSizeRequestMode gtk_label_get_request_mode (GtkWidget *widget) { @@ -3629,25 +3447,9 @@ get_size_for_allocation (GtkLabel *label, gint *natural_size) { PangoLayout *layout; - GtkWidgetAuxInfo *aux_info = - _gtk_widget_get_aux_info (GTK_WIDGET (label), FALSE); - gint aux_size; gint text_height; - if (aux_info) - { - if (orientation == GTK_ORIENTATION_HORIZONTAL) - aux_size = aux_info->width; - else - aux_size = aux_info->height; - } - else - aux_size = 0; - - if (aux_size > 0) - layout = gtk_label_get_measuring_layout (label, NULL, aux_size * PANGO_SCALE); - else - layout = gtk_label_get_measuring_layout (label, NULL, allocation * PANGO_SCALE); + layout = gtk_label_get_measuring_layout (label, NULL, allocation * PANGO_SCALE); pango_layout_get_pixel_size (layout, NULL, &text_height); @@ -3669,7 +3471,9 @@ get_char_pixels (GtkWidget *label, gint char_width, digit_width; context = pango_layout_get_context (layout); - metrics = get_font_metrics (context, GTK_WIDGET (label)); + metrics = pango_context_get_metrics (context, + pango_context_get_font_description (context), + pango_context_get_language (context)); char_width = pango_font_metrics_get_approximate_char_width (metrics); digit_width = pango_font_metrics_get_approximate_digit_width (metrics); pango_font_metrics_unref (metrics); @@ -3679,52 +3483,14 @@ get_char_pixels (GtkWidget *label, static void gtk_label_get_preferred_layout_size (GtkLabel *label, - PangoRectangle *required, - PangoRectangle *natural) + PangoRectangle *smallest, + PangoRectangle *widest) { GtkLabelPrivate *priv = label->priv; PangoLayout *layout; - PangoRectangle rect; - gint text_width, ellipsize_chars, guess_width; + gint char_pixels; /* "width-chars" Hard-coded minimum width: - * - minimum size should be MAX (width-chars, strlen ("...")); - * - natural size should be MAX (width-chars, strlen (priv->text)); - * - * "max-width-chars" User specified maximum size requisition - * - minimum size should be MAX (width-chars, 0) - * - natural size should be MIN (max-width-chars, strlen (priv->text)) - * - */ - - /* When calculating ->wrap sometimes we need to invent a size; Ideally we should be doing - * that stuff here instead of inside gtk_label_ensure_layout() */ - layout = gtk_label_get_layout_with_guessed_wrap_width (label); - - /* Start off with the pixel extents of the rendered layout */ - pango_layout_get_extents (layout, NULL, required); - required->x = required->y = 0; - - if (priv->single_line_mode || priv->wrap) - required->height = get_single_line_height (GTK_WIDGET (label), layout); - - *natural = *required; - - guess_width = required->width; - - layout = gtk_label_get_measuring_layout (label, layout, -1); - - /* Fetch the length of the complete unwrapped text */ - pango_layout_get_extents (layout, NULL, &rect); - text_width = rect.width; - - /* enforce minimum width for ellipsized labels at ~3 chars */ - if (priv->ellipsize) - ellipsize_chars = 3; - else - ellipsize_chars = 0; - - /* "width-chars" Hard-coded minimum width: * - minimum size should be MAX (width-chars, strlen ("...")); * - natural size should be MAX (width-chars, strlen (priv->text)); * @@ -3738,65 +3504,49 @@ gtk_label_get_preferred_layout_size (GtkLabel *label, * For wrapping labels; A reasonable minimum size is useful to naturally layout * interfaces automatically. In this case if no "width-chars" is specified, the minimum * width will default to the wrap guess that gtk_label_ensure_layout() does. - * - * In *any* case the minimum width is completely overridden if an explicit width - * request was provided. */ - if (priv->ellipsize || priv->wrap) - { - gint char_pixels; - - char_pixels = get_char_pixels (GTK_WIDGET (label), layout); - - required->width = char_pixels * MAX (priv->width_chars, ellipsize_chars); + /* Start off with the pixel extents of an as-wide-as-possible layout */ + layout = gtk_label_get_measuring_layout (label, NULL, -1); - /* Default to the minimum width regularly guessed by GTK+ if no minimum - * width was specified, only allow unwrapping of these labels. - * - * Note that when specifying a small width_chars for a long text; - * an accordingly large size will be required for the label height. - */ - if (priv->wrap && priv->width_chars <= 0) - required->width = guess_width; + if (priv->width_chars > -1 || priv->max_width_chars > -1) + char_pixels = get_char_pixels (GTK_WIDGET (label), layout); + else + char_pixels = 0; + + pango_layout_get_extents (layout, NULL, widest); + widest->width = MAX (widest->width, char_pixels * priv->width_chars); + widest->x = widest->y = 0; - if (priv->max_width_chars < 0) - { - natural->width = MAX (required->width, text_width); - } - else - { - gint max_char_width = char_pixels * priv->max_width_chars; - gint max_width = MIN (text_width, max_char_width); + if (priv->ellipsize || priv->wrap) + { + /* a layout with width 0 will be as small as humanly possible */ + layout = gtk_label_get_measuring_layout (label, + layout, + priv->width_chars > -1 ? char_pixels * priv->width_chars + : 0); - /* With max-char-width specified, we let the minimum widths of - * ellipsized text crawl up to the max-char-width - * (note that we dont want to limit the minimum width for wrapping text). - */ - if (priv->ellipsize) - required->width = MIN (text_width, max_width); + pango_layout_get_extents (layout, NULL, smallest); + smallest->width = MAX (smallest->width, char_pixels * priv->width_chars); + smallest->x = smallest->y = 0; - natural->width = MAX (required->width, max_width); - } + if (priv->max_width_chars > -1 && widest->width > char_pixels * priv->max_width_chars) + { + layout = gtk_label_get_measuring_layout (label, + layout, + MAX (smallest->width, char_pixels * priv->max_width_chars)); + pango_layout_get_extents (layout, NULL, widest); + widest->width = MAX (widest->width, char_pixels * priv->width_chars); + widest->x = widest->y = 0; + } } else { - required->width = text_width; - natural->width = required->width; + *smallest = *widest; } - /* if a width-request is set, use that as the requested label width */ - if (priv->wrap || priv->ellipsize || priv->width_chars > 0 || priv->max_width_chars > 0) - { - GtkWidgetAuxInfo *aux_info; - - aux_info = _gtk_widget_get_aux_info (GTK_WIDGET (label), FALSE); - if (aux_info && aux_info->width > 0) - { - required->width = aux_info->width * PANGO_SCALE; - natural->width = MAX (natural->width, required->width); - } - } + if (widest->width < smallest->width) + *smallest = *widest; g_object_unref (layout); } @@ -3809,36 +3559,28 @@ gtk_label_get_preferred_size (GtkWidget *widget, { GtkLabel *label = GTK_LABEL (widget); GtkLabelPrivate *priv = label->priv; - PangoRectangle required_rect; - PangoRectangle natural_rect; - gint xpad, ypad; + PangoRectangle widest_rect; + PangoRectangle smallest_rect; + GtkBorder border; - gtk_label_get_preferred_layout_size (label, &required_rect, &natural_rect); + gtk_label_get_preferred_layout_size (label, &smallest_rect, &widest_rect); /* Now that we have minimum and natural sizes in pango extents, apply a possible transform */ if (priv->have_transform) { - PangoLayout *copy; PangoContext *context; const PangoMatrix *matrix; - copy = pango_layout_copy (priv->layout); - context = pango_layout_get_context (copy); + context = pango_layout_get_context (priv->layout); matrix = pango_context_get_matrix (context); - pango_layout_set_width (copy, -1); - pango_layout_set_ellipsize (copy, PANGO_ELLIPSIZE_NONE); + pango_matrix_transform_rectangle (matrix, &widest_rect); + pango_matrix_transform_rectangle (matrix, &smallest_rect); - pango_layout_get_extents (copy, NULL, &natural_rect); - g_object_unref (copy); - - pango_matrix_transform_rectangle (matrix, &required_rect); - pango_matrix_transform_rectangle (matrix, &natural_rect); - - /* Bump the natural size in case of ellipsize to ensure pango has + /* Bump the size in case of ellipsize to ensure pango has * enough space in the angles (note, we could alternatively set the * layout to not ellipsize when we know we have been allocated our - * full natural size, or it may be that pango needs a fix here). + * full size, or it may be that pango needs a fix here). */ if (priv->ellipsize && priv->angle != 0 && priv->angle != 90 && priv->angle != 180 && priv->angle != 270 && priv->angle != 360) @@ -3846,18 +3588,20 @@ gtk_label_get_preferred_size (GtkWidget *widget, /* For some reason we only need this at about 110 degrees, and only * when gaining in height */ - natural_rect.height += ROTATION_ELLIPSIZE_PADDING * 2 * PANGO_SCALE; - natural_rect.width += ROTATION_ELLIPSIZE_PADDING * 2 * PANGO_SCALE; + widest_rect.height += ROTATION_ELLIPSIZE_PADDING * 2 * PANGO_SCALE; + widest_rect.width += ROTATION_ELLIPSIZE_PADDING * 2 * PANGO_SCALE; + smallest_rect.height += ROTATION_ELLIPSIZE_PADDING * 2 * PANGO_SCALE; + smallest_rect.width += ROTATION_ELLIPSIZE_PADDING * 2 * PANGO_SCALE; } } - required_rect.width = PANGO_PIXELS_CEIL (required_rect.width); - required_rect.height = PANGO_PIXELS_CEIL (required_rect.height); + widest_rect.width = PANGO_PIXELS_CEIL (widest_rect.width); + widest_rect.height = PANGO_PIXELS_CEIL (widest_rect.height); - natural_rect.width = PANGO_PIXELS_CEIL (natural_rect.width); - natural_rect.height = PANGO_PIXELS_CEIL (natural_rect.height); + smallest_rect.width = PANGO_PIXELS_CEIL (smallest_rect.width); + smallest_rect.height = PANGO_PIXELS_CEIL (smallest_rect.height); - gtk_misc_get_padding (GTK_MISC (label), &xpad, &ypad); + _gtk_misc_get_padding_and_border (GTK_MISC (label), &border); if (orientation == GTK_ORIENTATION_HORIZONTAL) { @@ -3872,19 +3616,19 @@ gtk_label_get_preferred_size (GtkWidget *widget, */ get_size_for_allocation (label, GTK_ORIENTATION_VERTICAL, - required_rect.height, + smallest_rect.height, minimum_size, natural_size); } else { /* Normal desired width */ - *minimum_size = required_rect.width; - *natural_size = natural_rect.width; + *minimum_size = smallest_rect.width; + *natural_size = widest_rect.width; } - *minimum_size += xpad * 2; - *natural_size += xpad * 2; + *minimum_size += border.left + border.right; + *natural_size += border.left + border.right; } else /* GTK_ORIENTATION_VERTICAL */ { @@ -3899,7 +3643,7 @@ gtk_label_get_preferred_size (GtkWidget *widget, */ get_size_for_allocation (label, GTK_ORIENTATION_HORIZONTAL, - required_rect.width, + widest_rect.width, minimum_size, natural_size); } else @@ -3907,16 +3651,15 @@ gtk_label_get_preferred_size (GtkWidget *widget, /* A vertically rotated label does w4h, so return the base * desired height (text length) */ - *minimum_size = required_rect.height; - *natural_size = natural_rect.height; + *minimum_size = MIN (smallest_rect.height, widest_rect.height); + *natural_size = MAX (smallest_rect.height, widest_rect.height); } - *minimum_size += ypad * 2; - *natural_size += ypad * 2; + *minimum_size += border.top + border.bottom; + *natural_size += border.top + border.bottom; } } - static void gtk_label_get_preferred_width (GtkWidget *widget, gint *minimum_size, @@ -3944,22 +3687,22 @@ gtk_label_get_preferred_width_for_height (GtkWidget *widget, if (priv->wrap && (priv->angle == 90 || priv->angle == 270)) { - gint xpad, ypad; + GtkBorder border; - gtk_misc_get_padding (GTK_MISC (label), &xpad, &ypad); + _gtk_misc_get_padding_and_border (GTK_MISC (label), &border); if (priv->wrap) gtk_label_clear_layout (label); get_size_for_allocation (label, GTK_ORIENTATION_VERTICAL, - MAX (1, height - (ypad * 2)), + MAX (1, height - border.top - border.bottom), minimum_width, natural_width); if (minimum_width) - *minimum_width += xpad * 2; + *minimum_width += border.right + border.left; if (natural_width) - *natural_width += xpad * 2; + *natural_width += border.right + border.left; } else GTK_WIDGET_GET_CLASS (widget)->get_preferred_width (widget, minimum_width, natural_width); @@ -3976,22 +3719,22 @@ gtk_label_get_preferred_height_for_width (GtkWidget *widget, if (priv->wrap && (priv->angle == 0 || priv->angle == 180 || priv->angle == 360)) { - gint xpad, ypad; + GtkBorder border; - gtk_misc_get_padding (GTK_MISC (label), &xpad, &ypad); + _gtk_misc_get_padding_and_border (GTK_MISC (label), &border); if (priv->wrap) gtk_label_clear_layout (label); get_size_for_allocation (label, GTK_ORIENTATION_HORIZONTAL, - MAX (1, width - xpad * 2), + MAX (1, width - border.left - border.right), minimum_height, natural_height); if (minimum_height) - *minimum_height += ypad * 2; + *minimum_height += border.top + border.bottom; if (natural_height) - *natural_height += ypad * 2; + *natural_height += border.top + border.bottom; } else GTK_WIDGET_GET_CLASS (widget)->get_preferred_height (widget, minimum_height, natural_height); @@ -4057,8 +3800,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; @@ -4071,33 +3814,8 @@ 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); -} - -static void -gtk_label_style_updated (GtkWidget *widget) -{ - GtkLabel *label = GTK_LABEL (widget); - - GTK_WIDGET_CLASS (gtk_label_parent_class)->style_updated (widget); - - /* We have to clear the layout, fonts etc. may have changed */ - gtk_label_clear_layout (label); - gtk_label_invalidate_wrap_width (label); -} - -static void -gtk_label_direction_changed (GtkWidget *widget, - GtkTextDirection previous_dir) -{ - GtkLabel *label = GTK_LABEL (widget); - GtkLabelPrivate *priv = label->priv; - - if (priv->layout) - pango_layout_context_changed (priv->layout); - - GTK_WIDGET_CLASS (gtk_label_parent_class)->direction_changed (widget, previous_dir); + 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 @@ -4109,9 +3827,9 @@ get_layout_location (GtkLabel *label, GtkMisc *misc; GtkWidget *widget; GtkLabelPrivate *priv; + GtkBorder border; gint req_width, x, y; gint req_height; - gint xpad, ypad; gfloat xalign, yalign; PangoRectangle logical; @@ -4120,7 +3838,7 @@ get_layout_location (GtkLabel *label, priv = label->priv; gtk_misc_get_alignment (misc, &xalign, &yalign); - gtk_misc_get_padding (misc, &xpad, &ypad); + _gtk_misc_get_padding_and_border (GTK_MISC (label), &border); if (gtk_widget_get_direction (widget) != GTK_TEXT_DIR_LTR) xalign = 1.0 - xalign; @@ -4139,18 +3857,12 @@ get_layout_location (GtkLabel *label, req_width = logical.width; req_height = logical.height; - req_width += 2 * xpad; - req_height += 2 * ypad; + req_width += border.left + border.right; + req_height += border.top + border.bottom; gtk_widget_get_allocation (widget, &allocation); - x = floor (allocation.x + xpad + xalign * (allocation.width - req_width)); - - if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR) - x = MAX (x, allocation.x + xpad); - else - x = MIN (x, allocation.x + allocation.width - xpad); - + x = floor (allocation.x + border.left + xalign * (allocation.width - req_width) - logical.x); /* bgo#315462 - For single-line labels, *do* align the requisition with * respect to the allocation, even if we are under-allocated. For multi-line @@ -4166,9 +3878,9 @@ get_layout_location (GtkLabel *label, * middle". You want to read the first line, at least, to get some context. */ if (pango_layout_get_line_count (priv->layout) == 1) - y = floor (allocation.y + ypad + (allocation.height - req_height) * yalign); + y = floor (allocation.y + border.top + (allocation.height - req_height) * yalign) - logical.y; else - y = floor (allocation.y + ypad + MAX ((allocation.height - req_height) * yalign, 0)); + y = floor (allocation.y + border.top + MAX ((allocation.height - req_height) * yalign, 0)) - logical.y; if (xp) *xp = x; @@ -4177,26 +3889,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) { @@ -4225,85 +3917,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) { @@ -4342,29 +3955,34 @@ gtk_label_draw (GtkWidget *widget, gtk_label_ensure_layout (label); + context = gtk_widget_get_style_context (widget); + gtk_widget_get_allocation (widget, &allocation); + + gtk_render_background (context, cr, + 0, 0, + allocation.width, allocation.height); + gtk_render_frame (context, cr, + 0, 0, + allocation.width, allocation.height); + if (priv->text && (*priv->text != '\0')) { - GdkRGBA *bg_color, *fg_color; - get_layout_location (label, &x, &y); - context = gtk_widget_get_style_context (widget); - gtk_widget_get_allocation (widget, &allocation); - 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; @@ -4387,28 +4005,20 @@ 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 (context, state, - "background-color", &bg_color, - "color", &fg_color, - NULL); + gtk_style_context_get_color (context, state, &fg_color); + gtk_style_context_get_background_color (context, state, &bg_color); - gdk_cairo_set_source_rgba (cr, bg_color); + gdk_cairo_set_source_rgba (cr, &bg_color); cairo_paint (cr); - gdk_cairo_set_source_rgba (cr, fg_color); + gdk_cairo_set_source_rgba (cr, &fg_color); cairo_move_to (cr, x, y); _gtk_pango_fill_layout (cr, priv->layout); cairo_restore (cr); cairo_region_destroy (clip); - - gdk_rgba_free (bg_color); - gdk_rgba_free (fg_color); } else if (info) { @@ -4418,19 +4028,28 @@ gtk_label_draw (GtkWidget *widget, cairo_region_t *clip; GdkRectangle rect; GdkColor *text_color; - GdkColor *link_color; - GdkColor *visited_link_color; + GdkColor link_color; + GdkColor visited_link_color; + + if (info->selectable && + gtk_widget_has_focus (widget) && + gtk_widget_is_drawable (widget)) + { + PangoDirection cursor_direction; - if (info->selectable && gtk_widget_has_focus (widget)) - gtk_label_draw_cursor (label, cr, x, y); + 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; + GdkRGBA bg_color; range[0] = active_link->start; range[1] = active_link->end; @@ -4447,34 +4066,30 @@ gtk_label_draw (GtkWidget *widget, gtk_label_get_link_colors (widget, &link_color, &visited_link_color); if (active_link->visited) - text_color = visited_link_color; + text_color = &visited_link_color; else - text_color = link_color; + 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 (context, state, - "background-color", &bg_color, - NULL); + gtk_style_context_get_background_color (context, state, &bg_color); - gdk_cairo_set_source_rgba (cr, bg_color); + gdk_cairo_set_source_rgba (cr, &bg_color); cairo_paint (cr); - gdk_cairo_set_source_color (cr, text_color); + cairo_set_source_rgb (cr, text_color->red / 65535., + text_color->green / 65535., + text_color->blue / 65535.); cairo_move_to (cr, x, y); _gtk_pango_fill_layout (cr, priv->layout); - gdk_color_free (link_color); - gdk_color_free (visited_link_color); - gdk_rgba_free (bg_color); - 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; @@ -4485,9 +4100,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); @@ -4952,16 +4564,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 == GDK_BUTTON_PRIMARY) { info->link_clicked = 1; - gtk_label_do_popup (label, event); - return TRUE; + gtk_widget_queue_draw (widget); } } @@ -4971,27 +4583,33 @@ 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 == GDK_BUTTON_PRIMARY) { if (!gtk_widget_has_focus (widget)) - { - priv->in_click = TRUE; - gtk_widget_grab_focus (widget); - priv->in_click = FALSE; - } + { + priv->in_click = TRUE; + gtk_widget_grab_focus (widget); + priv->in_click = FALSE; + } if (event->type == GDK_3BUTTON_PRESS) - { - gtk_label_select_region_index (label, 0, strlen (priv->text)); - return TRUE; - } + { + gtk_label_select_region_index (label, 0, strlen (priv->text)); + return TRUE; + } if (event->type == GDK_2BUTTON_PRESS) - { + { info->select_words = TRUE; - gtk_label_select_word (label); - return TRUE; - } + gtk_label_select_word (label); + return TRUE; + } get_layout_index (label, event->x, event->y, &index); @@ -4999,47 +4617,53 @@ gtk_label_button_press (GtkWidget *widget, max = MAX (info->selection_anchor, info->selection_end); if ((info->selection_anchor != info->selection_end) && - (event->state & GDK_SHIFT_MASK)) - { - /* extend (same as motion) */ - min = MIN (min, index); - max = MAX (max, index); + (event->state & GDK_SHIFT_MASK)) + { + if (index > min && index < max) + { + /* truncate selection, but keep it as big as possible */ + if (index - min > max - index) + max = index; + else + min = index; + } + else + { + /* extend (same as motion) */ + min = MIN (min, index); + max = MAX (max, index); + } - /* ensure the anchor is opposite index */ - if (index == min) - { - gint tmp = min; - min = max; - max = tmp; - } + /* ensure the anchor is opposite index */ + if (index == min) + { + gint tmp = min; + min = max; + max = tmp; + } - gtk_label_select_region_index (label, min, max); - } + gtk_label_select_region_index (label, min, max); + } else - { - if (event->type == GDK_3BUTTON_PRESS) - gtk_label_select_region_index (label, 0, strlen (priv->text)); - else if (event->type == GDK_2BUTTON_PRESS) - gtk_label_select_word (label); - else if (min < max && min <= index && index <= max) - { - info->in_drag = TRUE; - info->drag_start_x = event->x; - info->drag_start_y = event->y; - } - else - /* start a replacement */ - gtk_label_select_region_index (label, index, index); - } + { + if (event->type == GDK_3BUTTON_PRESS) + gtk_label_select_region_index (label, 0, strlen (priv->text)); + else if (event->type == GDK_2BUTTON_PRESS) + gtk_label_select_word (label); + else if (min < max && min <= index && index <= max) + { + info->in_drag = TRUE; + info->drag_start_x = event->x; + info->drag_start_y = event->y; + } + else + /* start a replacement */ + gtk_label_select_region_index (label, index, index); + } return TRUE; } - else if (event->button == 3 && event->type == GDK_BUTTON_PRESS) - { - gtk_label_do_popup (label, event); - return TRUE; - } return FALSE; } @@ -5066,7 +4690,7 @@ gtk_label_button_release (GtkWidget *widget, return FALSE; } - if (event->button != 1) + if (event->button != GDK_BUTTON_PRIMARY) return FALSE; if (info->active_link && @@ -5363,7 +4987,7 @@ gtk_label_create_window (GtkLabel *label) priv->select_info->window = gdk_window_new (gtk_widget_get_window (widget), &attributes, attributes_mask); - gdk_window_set_user_data (priv->select_info->window, widget); + gtk_widget_register_window (widget, priv->select_info->window); if (attributes_mask & GDK_WA_CURSOR) g_object_unref (attributes.cursor); @@ -5379,7 +5003,7 @@ gtk_label_destroy_window (GtkLabel *label) if (priv->select_info->window == NULL) return; - gdk_window_set_user_data (priv->select_info->window, NULL); + gtk_widget_unregister_window (GTK_WIDGET (label), priv->select_info->window); gdk_window_destroy (priv->select_info->window); priv->select_info->window = NULL; } @@ -5559,7 +5183,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) { @@ -5638,14 +5263,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) { @@ -5657,26 +5292,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)); } } @@ -5858,8 +5492,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)); } /** @@ -5894,8 +5532,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)); } /** @@ -6175,9 +5817,9 @@ gtk_label_move_backward_word (GtkLabel *label, static void gtk_label_move_cursor (GtkLabel *label, - GtkMovementStep step, - gint count, - gboolean extend_selection) + GtkMovementStep step, + gint count, + gboolean extend_selection) { GtkLabelPrivate *priv = label->priv; gint old_pos; @@ -6195,53 +5837,53 @@ gtk_label_move_cursor (GtkLabel *label, * start/or end of the selection as appropriate */ switch (step) - { - case GTK_MOVEMENT_VISUAL_POSITIONS: - { - gint end_x, end_y; - gint anchor_x, anchor_y; - gboolean end_is_left; - - get_better_cursor (label, priv->select_info->selection_end, &end_x, &end_y); - get_better_cursor (label, priv->select_info->selection_anchor, &anchor_x, &anchor_y); - - end_is_left = (end_y < anchor_y) || (end_y == anchor_y && end_x < anchor_x); - - if (count < 0) - new_pos = end_is_left ? priv->select_info->selection_end : priv->select_info->selection_anchor; - else - new_pos = !end_is_left ? priv->select_info->selection_end : priv->select_info->selection_anchor; - break; - } - case GTK_MOVEMENT_LOGICAL_POSITIONS: - case GTK_MOVEMENT_WORDS: - if (count < 0) - new_pos = MIN (priv->select_info->selection_end, priv->select_info->selection_anchor); - else - new_pos = MAX (priv->select_info->selection_end, priv->select_info->selection_anchor); - break; - case GTK_MOVEMENT_DISPLAY_LINE_ENDS: - case GTK_MOVEMENT_PARAGRAPH_ENDS: - case GTK_MOVEMENT_BUFFER_ENDS: - /* FIXME: Can do better here */ - new_pos = count < 0 ? 0 : strlen (priv->text); - break; - case GTK_MOVEMENT_DISPLAY_LINES: - case GTK_MOVEMENT_PARAGRAPHS: - case GTK_MOVEMENT_PAGES: - case GTK_MOVEMENT_HORIZONTAL_PAGES: - break; - } + { + case GTK_MOVEMENT_VISUAL_POSITIONS: + { + gint end_x, end_y; + gint anchor_x, anchor_y; + gboolean end_is_left; + + get_better_cursor (label, priv->select_info->selection_end, &end_x, &end_y); + get_better_cursor (label, priv->select_info->selection_anchor, &anchor_x, &anchor_y); + + end_is_left = (end_y < anchor_y) || (end_y == anchor_y && end_x < anchor_x); + + if (count < 0) + new_pos = end_is_left ? priv->select_info->selection_end : priv->select_info->selection_anchor; + else + new_pos = !end_is_left ? priv->select_info->selection_end : priv->select_info->selection_anchor; + break; + } + case GTK_MOVEMENT_LOGICAL_POSITIONS: + case GTK_MOVEMENT_WORDS: + if (count < 0) + new_pos = MIN (priv->select_info->selection_end, priv->select_info->selection_anchor); + else + new_pos = MAX (priv->select_info->selection_end, priv->select_info->selection_anchor); + break; + case GTK_MOVEMENT_DISPLAY_LINE_ENDS: + case GTK_MOVEMENT_PARAGRAPH_ENDS: + case GTK_MOVEMENT_BUFFER_ENDS: + /* FIXME: Can do better here */ + new_pos = count < 0 ? 0 : strlen (priv->text); + break; + case GTK_MOVEMENT_DISPLAY_LINES: + case GTK_MOVEMENT_PARAGRAPHS: + case GTK_MOVEMENT_PAGES: + case GTK_MOVEMENT_HORIZONTAL_PAGES: + break; + } } else { switch (step) - { - case GTK_MOVEMENT_LOGICAL_POSITIONS: - new_pos = gtk_label_move_logically (label, new_pos, count); - break; - case GTK_MOVEMENT_VISUAL_POSITIONS: - new_pos = gtk_label_move_visually (label, new_pos, count); + { + case GTK_MOVEMENT_LOGICAL_POSITIONS: + new_pos = gtk_label_move_logically (label, new_pos, count); + break; + case GTK_MOVEMENT_VISUAL_POSITIONS: + new_pos = gtk_label_move_visually (label, new_pos, count); if (new_pos == old_pos) { if (!extend_selection) @@ -6263,41 +5905,41 @@ gtk_label_move_cursor (GtkLabel *label, gtk_widget_error_bell (GTK_WIDGET (label)); } } - break; - case GTK_MOVEMENT_WORDS: - while (count > 0) - { - new_pos = gtk_label_move_forward_word (label, new_pos); - count--; - } - while (count < 0) - { - new_pos = gtk_label_move_backward_word (label, new_pos); - count++; - } + break; + case GTK_MOVEMENT_WORDS: + while (count > 0) + { + new_pos = gtk_label_move_forward_word (label, new_pos); + count--; + } + while (count < 0) + { + new_pos = gtk_label_move_backward_word (label, new_pos); + count++; + } if (new_pos == old_pos) gtk_widget_error_bell (GTK_WIDGET (label)); - break; - case GTK_MOVEMENT_DISPLAY_LINE_ENDS: - case GTK_MOVEMENT_PARAGRAPH_ENDS: - case GTK_MOVEMENT_BUFFER_ENDS: - /* FIXME: Can do better here */ - new_pos = count < 0 ? 0 : strlen (priv->text); + break; + case GTK_MOVEMENT_DISPLAY_LINE_ENDS: + case GTK_MOVEMENT_PARAGRAPH_ENDS: + case GTK_MOVEMENT_BUFFER_ENDS: + /* FIXME: Can do better here */ + new_pos = count < 0 ? 0 : strlen (priv->text); if (new_pos == old_pos) gtk_widget_error_bell (GTK_WIDGET (label)); - break; - case GTK_MOVEMENT_DISPLAY_LINES: - case GTK_MOVEMENT_PARAGRAPHS: - case GTK_MOVEMENT_PAGES: - case GTK_MOVEMENT_HORIZONTAL_PAGES: - break; - } + break; + case GTK_MOVEMENT_DISPLAY_LINES: + case GTK_MOVEMENT_PARAGRAPHS: + case GTK_MOVEMENT_PAGES: + case GTK_MOVEMENT_HORIZONTAL_PAGES: + break; + } } if (extend_selection) gtk_label_select_region_index (label, - priv->select_info->selection_anchor, - new_pos); + priv->select_info->selection_anchor, + new_pos); else gtk_label_select_region_index (label, new_pos, new_pos); } @@ -6567,67 +6209,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) @@ -6657,7 +6243,7 @@ emit_activate_link (GtkLabel *label, { link->visited = TRUE; /* FIXME: shouldn't have to redo everything here */ - gtk_label_recalculate (label); + gtk_label_clear_layout (label); } } @@ -6731,7 +6317,7 @@ gtk_label_get_current_link (GtkLabel *label) * * Since: 2.18 */ -G_CONST_RETURN gchar * +const gchar * gtk_label_get_current_uri (GtkLabel *label) { GtkLabelLink *link; @@ -6847,3 +6433,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; +}