]> Pileus Git - ~andy/gtk/blob - gtk/gtklabel.c
label: Split out function that merges attr lists
[~andy/gtk] / gtk / gtklabel.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free
16  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18
19 /*
20  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
21  * file for a list of people on the GTK+ Team.  See the ChangeLog
22  * files for a list of changes.  These files are distributed with
23  * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
24  */
25
26 #include "config.h"
27
28 #include <math.h>
29 #include <string.h>
30
31 #include "gtklabel.h"
32 #include "gtkaccellabel.h"
33 #include "gtkdnd.h"
34 #include "gtkmarshalers.h"
35 #include "gtkpango.h"
36 #include "gtkwindow.h"
37 #include "gtkclipboard.h"
38 #include "gtkimagemenuitem.h"
39 #include "gtkintl.h"
40 #include "gtkseparatormenuitem.h"
41 #include "gtktextutil.h"
42 #include "gtkmain.h"
43 #include "gtkmenuitem.h"
44 #include "gtkmenushellprivate.h"
45 #include "gtknotebook.h"
46 #include "gtkstock.h"
47 #include "gtkbindings.h"
48 #include "gtkbuildable.h"
49 #include "gtkimage.h"
50 #include "gtkshow.h"
51 #include "gtktooltip.h"
52 #include "gtkprivate.h"
53 #include "gtktypebuiltins.h"
54 #include "gtkmain.h"
55
56 #include "a11y/gtklabelaccessible.h"
57
58 /* this is in case rint() is not provided by the compiler, 
59  * such as in the case of C89 compilers, like MSVC
60  */
61 #include "fallback-c89.c"
62
63 /**
64  * SECTION:gtklabel
65  * @Short_description: A widget that displays a small to medium amount of text
66  * @Title: GtkLabel
67  *
68  * The #GtkLabel widget displays a small amount of text. As the name
69  * implies, most labels are used to label another widget such as a
70  * #GtkButton, a #GtkMenuItem, or a #GtkOptionMenu.
71  *
72  * <refsect2 id="GtkLabel-BUILDER-UI">
73  * <title>GtkLabel as GtkBuildable</title>
74  * <para>
75  * The GtkLabel implementation of the GtkBuildable interface supports a
76  * custom &lt;attributes&gt; element, which supports any number of &lt;attribute&gt;
77  * elements. the &lt;attribute&gt; element has attributes named name, value,
78  * start and end and allows you to specify #PangoAttribute values for this label.
79  *
80  * <example>
81  * <title>A UI definition fragment specifying Pango attributes</title>
82  * <programlisting><![CDATA[
83  * <object class="GtkLabel">
84  *   <attributes>
85  *     <attribute name="weight" value="PANGO_WEIGHT_BOLD"/>
86  *     <attribute name="background" value="red" start="5" end="10"/>"
87  *   </attributes>
88  * </object>
89  * ]]></programlisting>
90  * </example>
91  * The start and end attributes specify the range of characters to which the
92  * Pango attribute applies. If start and end are not specified, the attribute is
93  * applied to the whole text. Note that specifying ranges does not make much
94  * sense with translatable attributes. Use markup embedded in the translatable
95  * content instead.
96  * </para>
97  * </refsect2>
98  * <refsect2>
99  * <title>Mnemonics</title>
100  * <para>
101  * Labels may contain <firstterm>mnemonics</firstterm>. Mnemonics are
102  * underlined characters in the label, used for keyboard navigation.
103  * Mnemonics are created by providing a string with an underscore before
104  * the mnemonic character, such as <literal>"_File"</literal>, to the
105  * functions gtk_label_new_with_mnemonic() or
106  * gtk_label_set_text_with_mnemonic().
107  *
108  * Mnemonics automatically activate any activatable widget the label is
109  * inside, such as a #GtkButton; if the label is not inside the
110  * mnemonic's target widget, you have to tell the label about the target
111  * using gtk_label_set_mnemonic_widget(). Here's a simple example where
112  * the label is inside a button:
113  *
114  * <informalexample>
115  * <programlisting>
116  *   // Pressing Alt+H will activate this button
117  *   button = gtk_button_new (<!-- -->);
118  *   label = gtk_label_new_with_mnemonic ("_Hello");
119  *   gtk_container_add (GTK_CONTAINER (button), label);
120  * </programlisting>
121  * </informalexample>
122  *
123  * There's a convenience function to create buttons with a mnemonic label
124  * already inside:
125  *
126  * <informalexample>
127  * <programlisting>
128  *   // Pressing Alt+H will activate this button
129  *   button = gtk_button_new_with_mnemonic ("_Hello");
130  * </programlisting>
131  * </informalexample>
132  *
133  * To create a mnemonic for a widget alongside the label, such as a
134  * #GtkEntry, you have to point the label at the entry with
135  * gtk_label_set_mnemonic_widget():
136  *
137  * <informalexample>
138  * <programlisting>
139  *   // Pressing Alt+H will focus the entry
140  *   entry = gtk_entry_new (<!-- -->);
141  *   label = gtk_label_new_with_mnemonic ("_Hello");
142  *   gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry);
143  * </programlisting>
144  * </informalexample>
145  * </para>
146  * </refsect2>
147  * <refsect2>
148  * <title>Markup (styled text)</title>
149  * <para>
150  * To make it easy to format text in a label (changing colors, fonts,
151  * etc.), label text can be provided in a simple <link
152  * linkend="PangoMarkupFormat">markup format</link>.
153  * Here's how to create a label with a small font:
154  *
155  * <informalexample>
156  * <programlisting>
157  *   label = gtk_label_new (NULL);
158  *   gtk_label_set_markup (GTK_LABEL (label), "<small>Small text</small>");
159  * </programlisting>
160  * </informalexample>
161  *
162  * (See <link
163  * linkend="PangoMarkupFormat">complete documentation</link> of available
164  * tags in the Pango manual.)
165  *
166  * The markup passed to gtk_label_set_markup() must be valid; for example,
167  * literal &lt;, &gt; and &amp; characters must be escaped as \&lt;,
168  * \gt;, and \&amp;. If you pass text obtained from the user, file,
169  * or a network to gtk_label_set_markup(), you'll want to escape it with
170  * g_markup_escape_text() or g_markup_printf_escaped().
171  *
172  * Markup strings are just a convenient way to set the #PangoAttrList on
173  * a label; gtk_label_set_attributes() may be a simpler way to set
174  * attributes in some cases. Be careful though; #PangoAttrList tends to
175  * cause internationalization problems, unless you're applying attributes
176  * to the entire string (i.e. unless you set the range of each attribute
177  * to [0, %G_MAXINT)). The reason is that specifying the start_index and
178  * end_index for a #PangoAttribute requires knowledge of the exact string
179  * being displayed, so translations will cause problems.
180  * </para>
181  * </refsect2>
182  * <refsect2>
183  * <title>Selectable labels</title>
184  * Labels can be made selectable with gtk_label_set_selectable().
185  * Selectable labels allow the user to copy the label contents to
186  * the clipboard. Only labels that contain useful-to-copy information
187  * &mdash; such as error messages &mdash; should be made selectable.
188  * </refsect2>
189  * <refsect2 id="label-text-layout">
190  * <title>Text layout</title>
191  * <para>
192  * A label can contain any number of paragraphs, but will have
193  * performance problems if it contains more than a small number.
194  * Paragraphs are separated by newlines or other paragraph separators
195  * understood by Pango.
196  *
197  * Labels can automatically wrap text if you call
198  * gtk_label_set_line_wrap().
199  *
200  * gtk_label_set_justify() sets how the lines in a label align
201  * with one another. If you want to set how the label as a whole
202  * aligns in its available space, see gtk_misc_set_alignment().
203  *
204  * The #GtkLabel:width-chars and #GtkLabel:max-width-chars properties
205  * can be used to control the size allocation of ellipsized or wrapped
206  * labels. For ellipsizing labels, if either is specified (and less
207  * than the actual text size), it is used as the minimum width, and the actual
208  * text size is used as the natural width of the label. For wrapping labels,
209  * width-chars is used as the minimum width, if specified, and max-width-chars
210  * is used as the natural width. Even if max-width-chars specified, wrapping
211  * labels will be rewrapped to use all of the available width.
212  *
213  * <note><para>
214  * Note that the interpretation of #GtkLabel:width-chars and
215  * #GtkLabel:max-width-chars has changed a bit with the introduction of
216  * <link linkend="geometry-management">width-for-height geometry management.</link>
217  * </para></note>
218  * </para>
219  * </refsect2>
220  * <refsect2>
221  * <title>Links</title>
222  * <para>
223  * Since 2.18, GTK+ supports markup for clickable hyperlinks in addition
224  * to regular Pango markup. The markup for links is borrowed from HTML, using the
225  * <tag>a</tag> with href and title attributes. GTK+ renders links similar to the
226  * way they appear in web browsers, with colored, underlined text. The title
227  * attribute is displayed as a tooltip on the link. An example looks like this:
228  *
229  * <informalexample><programlisting>
230  * gtk_label_set_markup (label, "Go to the <a href="http://www.gtk.org" title="&lt;i&gt;Our&lt;/i&gt; website">GTK+ website</a> for more...");
231  * </programlisting></informalexample>
232  *
233  * It is possible to implement custom handling for links and their tooltips with
234  * the #GtkLabel::activate-link signal and the gtk_label_get_current_uri() function.
235  * </para>
236  * </refsect2>
237  */
238
239 struct _GtkLabelPrivate
240 {
241   GtkLabelSelectionInfo *select_info;
242   GtkWidget *mnemonic_widget;
243   GtkWindow *mnemonic_window;
244
245   PangoAttrList *attrs;
246   PangoAttrList *effective_attrs;
247   PangoLayout   *layout;
248
249   gchar   *label;
250   gchar   *text;
251
252   gdouble  angle;
253
254   guint    mnemonics_visible  : 1;
255   guint    jtype              : 2;
256   guint    wrap               : 1;
257   guint    use_underline      : 1;
258   guint    use_markup         : 1;
259   guint    ellipsize          : 3;
260   guint    single_line_mode   : 1;
261   guint    have_transform     : 1;
262   guint    in_click           : 1;
263   guint    wrap_mode          : 3;
264   guint    pattern_set        : 1;
265   guint    track_links        : 1;
266
267   guint    mnemonic_keyval;
268
269   gint     width_chars;
270   gint     max_width_chars;
271 };
272
273 /* Notes about the handling of links:
274  *
275  * Links share the GtkLabelSelectionInfo struct with selectable labels.
276  * There are some new fields for links. The links field contains the list
277  * of GtkLabelLink structs that describe the links which are embedded in
278  * the label. The active_link field points to the link under the mouse
279  * pointer. For keyboard navigation, the 'focus' link is determined by
280  * finding the link which contains the selection_anchor position.
281  * The link_clicked field is used with button press and release events
282  * to ensure that pressing inside a link and releasing outside of it
283  * does not activate the link.
284  *
285  * Links are rendered with the link-color/visited-link-color colors
286  * that are determined by the style and with an underline. When the mouse
287  * pointer is over a link, the pointer is changed to indicate the link,
288  * and the background behind the link is rendered with the base[PRELIGHT]
289  * color. While a button is pressed over a link, the background is rendered
290  * with the base[ACTIVE] color.
291  *
292  * Labels with links accept keyboard focus, and it is possible to move
293  * the focus between the embedded links using Tab/Shift-Tab. The focus
294  * is indicated by a focus rectangle that is drawn around the link text.
295  * Pressing Enter activates the focussed link, and there is a suitable
296  * context menu for links that can be opened with the Menu key. Pressing
297  * Control-C copies the link URI to the clipboard.
298  *
299  * In selectable labels with links, link functionality is only available
300  * when the selection is empty.
301  */
302 typedef struct
303 {
304   gchar *uri;
305   gchar *title;     /* the title attribute, used as tooltip */
306   gboolean visited; /* get set when the link is activated; this flag
307                      * gets preserved over later set_markup() calls
308                      */
309   gint start;       /* position of the link in the PangoLayout */
310   gint end;
311 } GtkLabelLink;
312
313 struct _GtkLabelSelectionInfo
314 {
315   GdkWindow *window;
316   gint selection_anchor;
317   gint selection_end;
318   GtkWidget *popup_menu;
319
320   GList *links;
321   GtkLabelLink *active_link;
322
323   gint drag_start_x;
324   gint drag_start_y;
325
326   guint in_drag      : 1;
327   guint select_words : 1;
328   guint selectable   : 1;
329   guint link_clicked : 1;
330 };
331
332 enum {
333   MOVE_CURSOR,
334   COPY_CLIPBOARD,
335   POPULATE_POPUP,
336   ACTIVATE_LINK,
337   ACTIVATE_CURRENT_LINK,
338   LAST_SIGNAL
339 };
340
341 enum {
342   PROP_0,
343   PROP_LABEL,
344   PROP_ATTRIBUTES,
345   PROP_USE_MARKUP,
346   PROP_USE_UNDERLINE,
347   PROP_JUSTIFY,
348   PROP_PATTERN,
349   PROP_WRAP,
350   PROP_WRAP_MODE,
351   PROP_SELECTABLE,
352   PROP_MNEMONIC_KEYVAL,
353   PROP_MNEMONIC_WIDGET,
354   PROP_CURSOR_POSITION,
355   PROP_SELECTION_BOUND,
356   PROP_ELLIPSIZE,
357   PROP_WIDTH_CHARS,
358   PROP_SINGLE_LINE_MODE,
359   PROP_ANGLE,
360   PROP_MAX_WIDTH_CHARS,
361   PROP_TRACK_VISITED_LINKS
362 };
363
364 /* When rotating ellipsizable text we want the natural size to request 
365  * more to ensure the label wont ever ellipsize in an allocation of full natural size.
366  * */
367 #define ROTATION_ELLIPSIZE_PADDING 2
368
369 static guint signals[LAST_SIGNAL] = { 0 };
370
371 static const GdkColor default_link_color = { 0, 0, 0, 0xeeee };
372 static const GdkColor default_visited_link_color = { 0, 0x5555, 0x1a1a, 0x8b8b };
373
374 static void gtk_label_set_property      (GObject          *object,
375                                          guint             prop_id,
376                                          const GValue     *value,
377                                          GParamSpec       *pspec);
378 static void gtk_label_get_property      (GObject          *object,
379                                          guint             prop_id,
380                                          GValue           *value,
381                                          GParamSpec       *pspec);
382 static void gtk_label_finalize          (GObject          *object);
383 static void gtk_label_destroy           (GtkWidget        *widget);
384 static void gtk_label_size_allocate     (GtkWidget        *widget,
385                                          GtkAllocation    *allocation);
386 static void gtk_label_state_flags_changed   (GtkWidget        *widget,
387                                              GtkStateFlags     prev_state);
388 static void gtk_label_style_updated     (GtkWidget        *widget);
389 static void gtk_label_direction_changed (GtkWidget        *widget,
390                                          GtkTextDirection  previous_dir);
391 static gint gtk_label_draw              (GtkWidget        *widget,
392                                          cairo_t          *cr);
393 static gboolean gtk_label_focus         (GtkWidget         *widget,
394                                          GtkDirectionType   direction);
395
396 static void gtk_label_realize           (GtkWidget        *widget);
397 static void gtk_label_unrealize         (GtkWidget        *widget);
398 static void gtk_label_map               (GtkWidget        *widget);
399 static void gtk_label_unmap             (GtkWidget        *widget);
400
401 static gboolean gtk_label_button_press      (GtkWidget        *widget,
402                                              GdkEventButton   *event);
403 static gboolean gtk_label_button_release    (GtkWidget        *widget,
404                                              GdkEventButton   *event);
405 static gboolean gtk_label_motion            (GtkWidget        *widget,
406                                              GdkEventMotion   *event);
407 static gboolean gtk_label_leave_notify      (GtkWidget        *widget,
408                                              GdkEventCrossing *event);
409
410 static void     gtk_label_grab_focus        (GtkWidget        *widget);
411
412 static gboolean gtk_label_query_tooltip     (GtkWidget        *widget,
413                                              gint              x,
414                                              gint              y,
415                                              gboolean          keyboard_tip,
416                                              GtkTooltip       *tooltip);
417
418 static void gtk_label_set_text_internal          (GtkLabel      *label,
419                                                   gchar         *str);
420 static void gtk_label_set_label_internal         (GtkLabel      *label,
421                                                   gchar         *str);
422 static void gtk_label_set_use_markup_internal    (GtkLabel      *label,
423                                                   gboolean       val);
424 static void gtk_label_set_use_underline_internal (GtkLabel      *label,
425                                                   gboolean       val);
426 static void gtk_label_set_uline_text_internal    (GtkLabel      *label,
427                                                   const gchar   *str);
428 static void gtk_label_set_pattern_internal       (GtkLabel      *label,
429                                                   const gchar   *pattern,
430                                                   gboolean       is_mnemonic);
431 static void gtk_label_set_markup_internal        (GtkLabel      *label,
432                                                   const gchar   *str,
433                                                   gboolean       with_uline);
434 static void gtk_label_recalculate                (GtkLabel      *label);
435 static void gtk_label_hierarchy_changed          (GtkWidget     *widget,
436                                                   GtkWidget     *old_toplevel);
437 static void gtk_label_screen_changed             (GtkWidget     *widget,
438                                                   GdkScreen     *old_screen);
439 static gboolean gtk_label_popup_menu             (GtkWidget     *widget);
440
441 static void gtk_label_create_window       (GtkLabel *label);
442 static void gtk_label_destroy_window      (GtkLabel *label);
443 static void gtk_label_ensure_select_info  (GtkLabel *label);
444 static void gtk_label_clear_select_info   (GtkLabel *label);
445 static void gtk_label_update_cursor       (GtkLabel *label);
446 static void gtk_label_clear_layout        (GtkLabel *label);
447 static void gtk_label_ensure_layout       (GtkLabel *label);
448 static void gtk_label_select_region_index (GtkLabel *label,
449                                            gint      anchor_index,
450                                            gint      end_index);
451
452
453 static gboolean gtk_label_mnemonic_activate (GtkWidget         *widget,
454                                              gboolean           group_cycling);
455 static void     gtk_label_setup_mnemonic    (GtkLabel          *label,
456                                              guint              last_key);
457 static void     gtk_label_drag_data_get     (GtkWidget         *widget,
458                                              GdkDragContext    *context,
459                                              GtkSelectionData  *selection_data,
460                                              guint              info,
461                                              guint              time);
462
463 static void     gtk_label_buildable_interface_init     (GtkBuildableIface *iface);
464 static gboolean gtk_label_buildable_custom_tag_start   (GtkBuildable     *buildable,
465                                                         GtkBuilder       *builder,
466                                                         GObject          *child,
467                                                         const gchar      *tagname,
468                                                         GMarkupParser    *parser,
469                                                         gpointer         *data);
470
471 static void     gtk_label_buildable_custom_finished    (GtkBuildable     *buildable,
472                                                         GtkBuilder       *builder,
473                                                         GObject          *child,
474                                                         const gchar      *tagname,
475                                                         gpointer          user_data);
476
477
478 static void connect_mnemonics_visible_notify    (GtkLabel   *label);
479 static gboolean      separate_uline_pattern     (const gchar  *str,
480                                                  guint        *accel_key,
481                                                  gchar       **new_str,
482                                                  gchar       **pattern);
483
484
485 /* For selectable labels: */
486 static void gtk_label_move_cursor        (GtkLabel        *label,
487                                           GtkMovementStep  step,
488                                           gint             count,
489                                           gboolean         extend_selection);
490 static void gtk_label_copy_clipboard     (GtkLabel        *label);
491 static void gtk_label_select_all         (GtkLabel        *label);
492 static void gtk_label_do_popup           (GtkLabel        *label,
493                                           GdkEventButton  *event);
494 static gint gtk_label_move_forward_word  (GtkLabel        *label,
495                                           gint             start);
496 static gint gtk_label_move_backward_word (GtkLabel        *label,
497                                           gint             start);
498
499 /* For links: */
500 static void          gtk_label_clear_links      (GtkLabel  *label);
501 static gboolean      gtk_label_activate_link    (GtkLabel    *label,
502                                                  const gchar *uri);
503 static void          gtk_label_activate_current_link (GtkLabel *label);
504 static GtkLabelLink *gtk_label_get_current_link (GtkLabel  *label);
505 static void          gtk_label_get_link_colors  (GtkWidget  *widget,
506                                                  GdkColor  **link_color,
507                                                  GdkColor  **visited_link_color);
508 static void          emit_activate_link         (GtkLabel     *label,
509                                                  GtkLabelLink *link);
510
511 static GtkSizeRequestMode gtk_label_get_request_mode                (GtkWidget           *widget);
512 static void               gtk_label_get_preferred_width             (GtkWidget           *widget,
513                                                                      gint                *minimum_size,
514                                                                      gint                *natural_size);
515 static void               gtk_label_get_preferred_height            (GtkWidget           *widget,
516                                                                      gint                *minimum_size,
517                                                                      gint                *natural_size);
518 static void               gtk_label_get_preferred_width_for_height  (GtkWidget           *widget,
519                                                                      gint                 height,
520                                                                      gint                *minimum_width,
521                                                                      gint                *natural_width);
522 static void               gtk_label_get_preferred_height_for_width  (GtkWidget           *widget,
523                                                                      gint                 width,
524                                                                      gint                *minimum_height,
525                                                                      gint                *natural_height);
526
527 static GtkBuildableIface *buildable_parent_iface = NULL;
528
529 G_DEFINE_TYPE_WITH_CODE (GtkLabel, gtk_label, GTK_TYPE_MISC,
530                          G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
531                                                 gtk_label_buildable_interface_init))
532
533 static void
534 add_move_binding (GtkBindingSet  *binding_set,
535                   guint           keyval,
536                   guint           modmask,
537                   GtkMovementStep step,
538                   gint            count)
539 {
540   g_return_if_fail ((modmask & GDK_SHIFT_MASK) == 0);
541   
542   gtk_binding_entry_add_signal (binding_set, keyval, modmask,
543                                 "move-cursor", 3,
544                                 G_TYPE_ENUM, step,
545                                 G_TYPE_INT, count,
546                                 G_TYPE_BOOLEAN, FALSE);
547
548   /* Selection-extending version */
549   gtk_binding_entry_add_signal (binding_set, keyval, modmask | GDK_SHIFT_MASK,
550                                 "move-cursor", 3,
551                                 G_TYPE_ENUM, step,
552                                 G_TYPE_INT, count,
553                                 G_TYPE_BOOLEAN, TRUE);
554 }
555
556 static void
557 gtk_label_class_init (GtkLabelClass *class)
558 {
559   GObjectClass *gobject_class = G_OBJECT_CLASS (class);
560   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
561   GtkBindingSet *binding_set;
562
563   gobject_class->set_property = gtk_label_set_property;
564   gobject_class->get_property = gtk_label_get_property;
565   gobject_class->finalize = gtk_label_finalize;
566
567   widget_class->destroy = gtk_label_destroy;
568   widget_class->size_allocate = gtk_label_size_allocate;
569   widget_class->state_flags_changed = gtk_label_state_flags_changed;
570   widget_class->style_updated = gtk_label_style_updated;
571   widget_class->query_tooltip = gtk_label_query_tooltip;
572   widget_class->direction_changed = gtk_label_direction_changed;
573   widget_class->draw = gtk_label_draw;
574   widget_class->realize = gtk_label_realize;
575   widget_class->unrealize = gtk_label_unrealize;
576   widget_class->map = gtk_label_map;
577   widget_class->unmap = gtk_label_unmap;
578   widget_class->button_press_event = gtk_label_button_press;
579   widget_class->button_release_event = gtk_label_button_release;
580   widget_class->motion_notify_event = gtk_label_motion;
581   widget_class->leave_notify_event = gtk_label_leave_notify;
582   widget_class->hierarchy_changed = gtk_label_hierarchy_changed;
583   widget_class->screen_changed = gtk_label_screen_changed;
584   widget_class->mnemonic_activate = gtk_label_mnemonic_activate;
585   widget_class->drag_data_get = gtk_label_drag_data_get;
586   widget_class->grab_focus = gtk_label_grab_focus;
587   widget_class->popup_menu = gtk_label_popup_menu;
588   widget_class->focus = gtk_label_focus;
589   widget_class->get_request_mode = gtk_label_get_request_mode;
590   widget_class->get_preferred_width = gtk_label_get_preferred_width;
591   widget_class->get_preferred_height = gtk_label_get_preferred_height;
592   widget_class->get_preferred_width_for_height = gtk_label_get_preferred_width_for_height;
593   widget_class->get_preferred_height_for_width = gtk_label_get_preferred_height_for_width;
594
595   class->move_cursor = gtk_label_move_cursor;
596   class->copy_clipboard = gtk_label_copy_clipboard;
597   class->activate_link = gtk_label_activate_link;
598
599   /**
600    * GtkLabel::move-cursor:
601    * @entry: the object which received the signal
602    * @step: the granularity of the move, as a #GtkMovementStep
603    * @count: the number of @step units to move
604    * @extend_selection: %TRUE if the move should extend the selection
605    *
606    * The ::move-cursor signal is a
607    * <link linkend="keybinding-signals">keybinding signal</link>
608    * which gets emitted when the user initiates a cursor movement.
609    * If the cursor is not visible in @entry, this signal causes
610    * the viewport to be moved instead.
611    *
612    * Applications should not connect to it, but may emit it with
613    * g_signal_emit_by_name() if they need to control the cursor
614    * programmatically.
615    *
616    * The default bindings for this signal come in two variants,
617    * the variant with the Shift modifier extends the selection,
618    * the variant without the Shift modifer does not.
619    * There are too many key combinations to list them all here.
620    * <itemizedlist>
621    * <listitem>Arrow keys move by individual characters/lines</listitem>
622    * <listitem>Ctrl-arrow key combinations move by words/paragraphs</listitem>
623    * <listitem>Home/End keys move to the ends of the buffer</listitem>
624    * </itemizedlist>
625    */
626   signals[MOVE_CURSOR] = 
627     g_signal_new (I_("move-cursor"),
628                   G_OBJECT_CLASS_TYPE (gobject_class),
629                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
630                   G_STRUCT_OFFSET (GtkLabelClass, move_cursor),
631                   NULL, NULL,
632                   _gtk_marshal_VOID__ENUM_INT_BOOLEAN,
633                   G_TYPE_NONE, 3,
634                   GTK_TYPE_MOVEMENT_STEP,
635                   G_TYPE_INT,
636                   G_TYPE_BOOLEAN);
637
638    /**
639    * GtkLabel::copy-clipboard:
640    * @label: the object which received the signal
641    *
642    * The ::copy-clipboard signal is a
643    * <link linkend="keybinding-signals">keybinding signal</link>
644    * which gets emitted to copy the selection to the clipboard.
645    *
646    * The default binding for this signal is Ctrl-c.
647    */ 
648   signals[COPY_CLIPBOARD] =
649     g_signal_new (I_("copy-clipboard"),
650                   G_OBJECT_CLASS_TYPE (gobject_class),
651                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
652                   G_STRUCT_OFFSET (GtkLabelClass, copy_clipboard),
653                   NULL, NULL,
654                   _gtk_marshal_VOID__VOID,
655                   G_TYPE_NONE, 0);
656   
657   /**
658    * GtkLabel::populate-popup:
659    * @label: The label on which the signal is emitted
660    * @menu: the menu that is being populated
661    *
662    * The ::populate-popup signal gets emitted before showing the
663    * context menu of the label. Note that only selectable labels
664    * have context menus.
665    *
666    * If you need to add items to the context menu, connect
667    * to this signal and append your menuitems to the @menu.
668    */
669   signals[POPULATE_POPUP] =
670     g_signal_new (I_("populate-popup"),
671                   G_OBJECT_CLASS_TYPE (gobject_class),
672                   G_SIGNAL_RUN_LAST,
673                   G_STRUCT_OFFSET (GtkLabelClass, populate_popup),
674                   NULL, NULL,
675                   _gtk_marshal_VOID__OBJECT,
676                   G_TYPE_NONE, 1,
677                   GTK_TYPE_MENU);
678
679     /**
680      * GtkLabel::activate-current-link:
681      * @label: The label on which the signal was emitted
682      *
683      * A <link linkend="keybinding-signals">keybinding signal</link>
684      * which gets emitted when the user activates a link in the label.
685      *
686      * Applications may also emit the signal with g_signal_emit_by_name()
687      * if they need to control activation of URIs programmatically.
688      *
689      * The default bindings for this signal are all forms of the Enter key.
690      *
691      * Since: 2.18
692      */
693     signals[ACTIVATE_CURRENT_LINK] =
694       g_signal_new_class_handler ("activate-current-link",
695                                   G_TYPE_FROM_CLASS (gobject_class),
696                                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
697                                   G_CALLBACK (gtk_label_activate_current_link),
698                                   NULL, NULL,
699                                   _gtk_marshal_VOID__VOID,
700                                   G_TYPE_NONE, 0);
701
702     /**
703      * GtkLabel::activate-link:
704      * @label: The label on which the signal was emitted
705      * @uri: the URI that is activated
706      *
707      * The signal which gets emitted to activate a URI.
708      * Applications may connect to it to override the default behaviour,
709      * which is to call gtk_show_uri().
710      *
711      * Returns: %TRUE if the link has been activated
712      *
713      * Since: 2.18
714      */
715     signals[ACTIVATE_LINK] =
716       g_signal_new ("activate-link",
717                     G_TYPE_FROM_CLASS (gobject_class),
718                     G_SIGNAL_RUN_LAST,
719                     G_STRUCT_OFFSET (GtkLabelClass, activate_link),
720                     _gtk_boolean_handled_accumulator, NULL,
721                     _gtk_marshal_BOOLEAN__STRING,
722                     G_TYPE_BOOLEAN, 1, G_TYPE_STRING);
723
724   g_object_class_install_property (gobject_class,
725                                    PROP_LABEL,
726                                    g_param_spec_string ("label",
727                                                         P_("Label"),
728                                                         P_("The text of the label"),
729                                                         "",
730                                                         GTK_PARAM_READWRITE));
731   g_object_class_install_property (gobject_class,
732                                    PROP_ATTRIBUTES,
733                                    g_param_spec_boxed ("attributes",
734                                                        P_("Attributes"),
735                                                        P_("A list of style attributes to apply to the text of the label"),
736                                                        PANGO_TYPE_ATTR_LIST,
737                                                        GTK_PARAM_READWRITE));
738   g_object_class_install_property (gobject_class,
739                                    PROP_USE_MARKUP,
740                                    g_param_spec_boolean ("use-markup",
741                                                          P_("Use markup"),
742                                                          P_("The text of the label includes XML markup. See pango_parse_markup()"),
743                                                         FALSE,
744                                                         GTK_PARAM_READWRITE));
745   g_object_class_install_property (gobject_class,
746                                    PROP_USE_UNDERLINE,
747                                    g_param_spec_boolean ("use-underline",
748                                                          P_("Use underline"),
749                                                          P_("If set, an underline in the text indicates the next character should be used for the mnemonic accelerator key"),
750                                                         FALSE,
751                                                         GTK_PARAM_READWRITE));
752
753   g_object_class_install_property (gobject_class,
754                                    PROP_JUSTIFY,
755                                    g_param_spec_enum ("justify",
756                                                       P_("Justification"),
757                                                       P_("The alignment of the lines in the text of the label relative to each other. This does NOT affect the alignment of the label within its allocation. See GtkMisc::xalign for that"),
758                                                       GTK_TYPE_JUSTIFICATION,
759                                                       GTK_JUSTIFY_LEFT,
760                                                       GTK_PARAM_READWRITE));
761
762   g_object_class_install_property (gobject_class,
763                                    PROP_PATTERN,
764                                    g_param_spec_string ("pattern",
765                                                         P_("Pattern"),
766                                                         P_("A string with _ characters in positions correspond to characters in the text to underline"),
767                                                         NULL,
768                                                         GTK_PARAM_WRITABLE));
769
770   g_object_class_install_property (gobject_class,
771                                    PROP_WRAP,
772                                    g_param_spec_boolean ("wrap",
773                                                         P_("Line wrap"),
774                                                         P_("If set, wrap lines if the text becomes too wide"),
775                                                         FALSE,
776                                                         GTK_PARAM_READWRITE));
777   /**
778    * GtkLabel:wrap-mode:
779    *
780    * If line wrapping is on (see the #GtkLabel:wrap property) this controls 
781    * how the line wrapping is done. The default is %PANGO_WRAP_WORD, which 
782    * means wrap on word boundaries.
783    *
784    * Since: 2.10
785    */
786   g_object_class_install_property (gobject_class,
787                                    PROP_WRAP_MODE,
788                                    g_param_spec_enum ("wrap-mode",
789                                                       P_("Line wrap mode"),
790                                                       P_("If wrap is set, controls how linewrapping is done"),
791                                                       PANGO_TYPE_WRAP_MODE,
792                                                       PANGO_WRAP_WORD,
793                                                       GTK_PARAM_READWRITE));
794   g_object_class_install_property (gobject_class,
795                                    PROP_SELECTABLE,
796                                    g_param_spec_boolean ("selectable",
797                                                         P_("Selectable"),
798                                                         P_("Whether the label text can be selected with the mouse"),
799                                                         FALSE,
800                                                         GTK_PARAM_READWRITE));
801   g_object_class_install_property (gobject_class,
802                                    PROP_MNEMONIC_KEYVAL,
803                                    g_param_spec_uint ("mnemonic-keyval",
804                                                       P_("Mnemonic key"),
805                                                       P_("The mnemonic accelerator key for this label"),
806                                                       0,
807                                                       G_MAXUINT,
808                                                       GDK_KEY_VoidSymbol,
809                                                       GTK_PARAM_READABLE));
810   g_object_class_install_property (gobject_class,
811                                    PROP_MNEMONIC_WIDGET,
812                                    g_param_spec_object ("mnemonic-widget",
813                                                         P_("Mnemonic widget"),
814                                                         P_("The widget to be activated when the label's mnemonic "
815                                                           "key is pressed"),
816                                                         GTK_TYPE_WIDGET,
817                                                         GTK_PARAM_READWRITE));
818
819   g_object_class_install_property (gobject_class,
820                                    PROP_CURSOR_POSITION,
821                                    g_param_spec_int ("cursor-position",
822                                                      P_("Cursor Position"),
823                                                      P_("The current position of the insertion cursor in chars"),
824                                                      0,
825                                                      G_MAXINT,
826                                                      0,
827                                                      GTK_PARAM_READABLE));
828   
829   g_object_class_install_property (gobject_class,
830                                    PROP_SELECTION_BOUND,
831                                    g_param_spec_int ("selection-bound",
832                                                      P_("Selection Bound"),
833                                                      P_("The position of the opposite end of the selection from the cursor in chars"),
834                                                      0,
835                                                      G_MAXINT,
836                                                      0,
837                                                      GTK_PARAM_READABLE));
838   
839   /**
840    * GtkLabel:ellipsize:
841    *
842    * The preferred place to ellipsize the string, if the label does 
843    * not have enough room to display the entire string, specified as a 
844    * #PangoEllisizeMode. 
845    *
846    * Note that setting this property to a value other than 
847    * %PANGO_ELLIPSIZE_NONE has the side-effect that the label requests 
848    * only enough space to display the ellipsis "...". In particular, this 
849    * means that ellipsizing labels do not work well in notebook tabs, unless 
850    * the tab's #GtkNotebook:tab-expand property is set to %TRUE. Other ways
851    * to set a label's width are gtk_widget_set_size_request() and
852    * gtk_label_set_width_chars().
853    *
854    * Since: 2.6
855    */
856   g_object_class_install_property (gobject_class,
857                                    PROP_ELLIPSIZE,
858                                    g_param_spec_enum ("ellipsize",
859                                                       P_("Ellipsize"),
860                                                       P_("The preferred place to ellipsize the string, if the label does not have enough room to display the entire string"),
861                                                       PANGO_TYPE_ELLIPSIZE_MODE,
862                                                       PANGO_ELLIPSIZE_NONE,
863                                                       GTK_PARAM_READWRITE));
864
865   /**
866    * GtkLabel:width-chars:
867    *
868    * The desired width of the label, in characters. If this property is set to
869    * -1, the width will be calculated automatically.
870    *
871    * See the section on <link linkend="label-text-layout">text layout</link>
872    * for details of how #GtkLabel:width-chars and #GtkLabel:max-width-chars
873    * determine the width of ellipsized and wrapped labels.
874    *
875    * Since: 2.6
876    **/
877   g_object_class_install_property (gobject_class,
878                                    PROP_WIDTH_CHARS,
879                                    g_param_spec_int ("width-chars",
880                                                      P_("Width In Characters"),
881                                                      P_("The desired width of the label, in characters"),
882                                                      -1,
883                                                      G_MAXINT,
884                                                      -1,
885                                                      GTK_PARAM_READWRITE));
886   
887   /**
888    * GtkLabel:single-line-mode:
889    * 
890    * Whether the label is in single line mode. In single line mode,
891    * the height of the label does not depend on the actual text, it
892    * is always set to ascent + descent of the font. This can be an
893    * advantage in situations where resizing the label because of text 
894    * changes would be distracting, e.g. in a statusbar.
895    *
896    * Since: 2.6
897    **/
898   g_object_class_install_property (gobject_class,
899                                    PROP_SINGLE_LINE_MODE,
900                                    g_param_spec_boolean ("single-line-mode",
901                                                         P_("Single Line Mode"),
902                                                         P_("Whether the label is in single line mode"),
903                                                         FALSE,
904                                                         GTK_PARAM_READWRITE));
905
906   /**
907    * GtkLabel:angle:
908    * 
909    * The angle that the baseline of the label makes with the horizontal,
910    * in degrees, measured counterclockwise. An angle of 90 reads from
911    * from bottom to top, an angle of 270, from top to bottom. Ignored
912    * if the label is selectable, wrapped, or ellipsized.
913    *
914    * Since: 2.6
915    **/
916   g_object_class_install_property (gobject_class,
917                                    PROP_ANGLE,
918                                    g_param_spec_double ("angle",
919                                                         P_("Angle"),
920                                                         P_("Angle at which the label is rotated"),
921                                                         0.0,
922                                                         360.0,
923                                                         0.0, 
924                                                         GTK_PARAM_READWRITE));
925   
926   /**
927    * GtkLabel:max-width-chars:
928    * 
929    * The desired maximum width of the label, in characters. If this property 
930    * is set to -1, the width will be calculated automatically.
931    *
932    * See the section on <link linkend="label-text-layout">text layout</link>
933    * for details of how #GtkLabel:width-chars and #GtkLabel:max-width-chars
934    * determine the width of ellipsized and wrapped labels.
935    *
936    * Since: 2.6
937    **/
938   g_object_class_install_property (gobject_class,
939                                    PROP_MAX_WIDTH_CHARS,
940                                    g_param_spec_int ("max-width-chars",
941                                                      P_("Maximum Width In Characters"),
942                                                      P_("The desired maximum width of the label, in characters"),
943                                                      -1,
944                                                      G_MAXINT,
945                                                      -1,
946                                                      GTK_PARAM_READWRITE));
947
948   /**
949    * GtkLabel:track-visited-links:
950    *
951    * Set this property to %TRUE to make the label track which links
952    * have been clicked. It will then apply the ::visited-link-color
953    * color, instead of ::link-color.
954    *
955    * Since: 2.18
956    */
957   g_object_class_install_property (gobject_class,
958                                    PROP_TRACK_VISITED_LINKS,
959                                    g_param_spec_boolean ("track-visited-links",
960                                                          P_("Track visited links"),
961                                                          P_("Whether visited links should be tracked"),
962                                                          TRUE,
963                                                          GTK_PARAM_READWRITE));
964   /*
965    * Key bindings
966    */
967
968   binding_set = gtk_binding_set_by_class (class);
969
970   /* Moving the insertion point */
971   add_move_binding (binding_set, GDK_KEY_Right, 0,
972                     GTK_MOVEMENT_VISUAL_POSITIONS, 1);
973   
974   add_move_binding (binding_set, GDK_KEY_Left, 0,
975                     GTK_MOVEMENT_VISUAL_POSITIONS, -1);
976
977   add_move_binding (binding_set, GDK_KEY_KP_Right, 0,
978                     GTK_MOVEMENT_VISUAL_POSITIONS, 1);
979   
980   add_move_binding (binding_set, GDK_KEY_KP_Left, 0,
981                     GTK_MOVEMENT_VISUAL_POSITIONS, -1);
982   
983   add_move_binding (binding_set, GDK_KEY_f, GDK_CONTROL_MASK,
984                     GTK_MOVEMENT_LOGICAL_POSITIONS, 1);
985   
986   add_move_binding (binding_set, GDK_KEY_b, GDK_CONTROL_MASK,
987                     GTK_MOVEMENT_LOGICAL_POSITIONS, -1);
988   
989   add_move_binding (binding_set, GDK_KEY_Right, GDK_CONTROL_MASK,
990                     GTK_MOVEMENT_WORDS, 1);
991
992   add_move_binding (binding_set, GDK_KEY_Left, GDK_CONTROL_MASK,
993                     GTK_MOVEMENT_WORDS, -1);
994
995   add_move_binding (binding_set, GDK_KEY_KP_Right, GDK_CONTROL_MASK,
996                     GTK_MOVEMENT_WORDS, 1);
997
998   add_move_binding (binding_set, GDK_KEY_KP_Left, GDK_CONTROL_MASK,
999                     GTK_MOVEMENT_WORDS, -1);
1000
1001   /* select all */
1002   gtk_binding_entry_add_signal (binding_set, GDK_KEY_a, GDK_CONTROL_MASK,
1003                                 "move-cursor", 3,
1004                                 G_TYPE_ENUM, GTK_MOVEMENT_PARAGRAPH_ENDS,
1005                                 G_TYPE_INT, -1,
1006                                 G_TYPE_BOOLEAN, FALSE);
1007
1008   gtk_binding_entry_add_signal (binding_set, GDK_KEY_a, GDK_CONTROL_MASK,
1009                                 "move-cursor", 3,
1010                                 G_TYPE_ENUM, GTK_MOVEMENT_PARAGRAPH_ENDS,
1011                                 G_TYPE_INT, 1,
1012                                 G_TYPE_BOOLEAN, TRUE);
1013
1014   gtk_binding_entry_add_signal (binding_set, GDK_KEY_slash, GDK_CONTROL_MASK,
1015                                 "move-cursor", 3,
1016                                 G_TYPE_ENUM, GTK_MOVEMENT_PARAGRAPH_ENDS,
1017                                 G_TYPE_INT, -1,
1018                                 G_TYPE_BOOLEAN, FALSE);
1019
1020   gtk_binding_entry_add_signal (binding_set, GDK_KEY_slash, GDK_CONTROL_MASK,
1021                                 "move-cursor", 3,
1022                                 G_TYPE_ENUM, GTK_MOVEMENT_PARAGRAPH_ENDS,
1023                                 G_TYPE_INT, 1,
1024                                 G_TYPE_BOOLEAN, TRUE);
1025
1026   /* unselect all */
1027   gtk_binding_entry_add_signal (binding_set, GDK_KEY_a, GDK_SHIFT_MASK | GDK_CONTROL_MASK,
1028                                 "move-cursor", 3,
1029                                 G_TYPE_ENUM, GTK_MOVEMENT_PARAGRAPH_ENDS,
1030                                 G_TYPE_INT, 0,
1031                                 G_TYPE_BOOLEAN, FALSE);
1032
1033   gtk_binding_entry_add_signal (binding_set, GDK_KEY_backslash, GDK_CONTROL_MASK,
1034                                 "move-cursor", 3,
1035                                 G_TYPE_ENUM, GTK_MOVEMENT_PARAGRAPH_ENDS,
1036                                 G_TYPE_INT, 0,
1037                                 G_TYPE_BOOLEAN, FALSE);
1038
1039   add_move_binding (binding_set, GDK_KEY_f, GDK_MOD1_MASK,
1040                     GTK_MOVEMENT_WORDS, 1);
1041
1042   add_move_binding (binding_set, GDK_KEY_b, GDK_MOD1_MASK,
1043                     GTK_MOVEMENT_WORDS, -1);
1044
1045   add_move_binding (binding_set, GDK_KEY_Home, 0,
1046                     GTK_MOVEMENT_DISPLAY_LINE_ENDS, -1);
1047
1048   add_move_binding (binding_set, GDK_KEY_End, 0,
1049                     GTK_MOVEMENT_DISPLAY_LINE_ENDS, 1);
1050
1051   add_move_binding (binding_set, GDK_KEY_KP_Home, 0,
1052                     GTK_MOVEMENT_DISPLAY_LINE_ENDS, -1);
1053
1054   add_move_binding (binding_set, GDK_KEY_KP_End, 0,
1055                     GTK_MOVEMENT_DISPLAY_LINE_ENDS, 1);
1056   
1057   add_move_binding (binding_set, GDK_KEY_Home, GDK_CONTROL_MASK,
1058                     GTK_MOVEMENT_BUFFER_ENDS, -1);
1059
1060   add_move_binding (binding_set, GDK_KEY_End, GDK_CONTROL_MASK,
1061                     GTK_MOVEMENT_BUFFER_ENDS, 1);
1062
1063   add_move_binding (binding_set, GDK_KEY_KP_Home, GDK_CONTROL_MASK,
1064                     GTK_MOVEMENT_BUFFER_ENDS, -1);
1065
1066   add_move_binding (binding_set, GDK_KEY_KP_End, GDK_CONTROL_MASK,
1067                     GTK_MOVEMENT_BUFFER_ENDS, 1);
1068
1069   /* copy */
1070   gtk_binding_entry_add_signal (binding_set, GDK_KEY_c, GDK_CONTROL_MASK,
1071                                 "copy-clipboard", 0);
1072
1073   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Return, 0,
1074                                 "activate-current-link", 0);
1075   gtk_binding_entry_add_signal (binding_set, GDK_KEY_ISO_Enter, 0,
1076                                 "activate-current-link", 0);
1077   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Enter, 0,
1078                                 "activate-current-link", 0);
1079
1080   g_type_class_add_private (class, sizeof (GtkLabelPrivate));
1081
1082   gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_LABEL_ACCESSIBLE);
1083 }
1084
1085 static void 
1086 gtk_label_set_property (GObject      *object,
1087                         guint         prop_id,
1088                         const GValue *value,
1089                         GParamSpec   *pspec)
1090 {
1091   GtkLabel *label = GTK_LABEL (object);
1092
1093   switch (prop_id)
1094     {
1095     case PROP_LABEL:
1096       gtk_label_set_label (label, g_value_get_string (value));
1097       break;
1098     case PROP_ATTRIBUTES:
1099       gtk_label_set_attributes (label, g_value_get_boxed (value));
1100       break;
1101     case PROP_USE_MARKUP:
1102       gtk_label_set_use_markup (label, g_value_get_boolean (value));
1103       break;
1104     case PROP_USE_UNDERLINE:
1105       gtk_label_set_use_underline (label, g_value_get_boolean (value));
1106       break;
1107     case PROP_JUSTIFY:
1108       gtk_label_set_justify (label, g_value_get_enum (value));
1109       break;
1110     case PROP_PATTERN:
1111       gtk_label_set_pattern (label, g_value_get_string (value));
1112       break;
1113     case PROP_WRAP:
1114       gtk_label_set_line_wrap (label, g_value_get_boolean (value));
1115       break;      
1116     case PROP_WRAP_MODE:
1117       gtk_label_set_line_wrap_mode (label, g_value_get_enum (value));
1118       break;      
1119     case PROP_SELECTABLE:
1120       gtk_label_set_selectable (label, g_value_get_boolean (value));
1121       break;      
1122     case PROP_MNEMONIC_WIDGET:
1123       gtk_label_set_mnemonic_widget (label, (GtkWidget*) g_value_get_object (value));
1124       break;
1125     case PROP_ELLIPSIZE:
1126       gtk_label_set_ellipsize (label, g_value_get_enum (value));
1127       break;
1128     case PROP_WIDTH_CHARS:
1129       gtk_label_set_width_chars (label, g_value_get_int (value));
1130       break;
1131     case PROP_SINGLE_LINE_MODE:
1132       gtk_label_set_single_line_mode (label, g_value_get_boolean (value));
1133       break;      
1134     case PROP_ANGLE:
1135       gtk_label_set_angle (label, g_value_get_double (value));
1136       break;
1137     case PROP_MAX_WIDTH_CHARS:
1138       gtk_label_set_max_width_chars (label, g_value_get_int (value));
1139       break;
1140     case PROP_TRACK_VISITED_LINKS:
1141       gtk_label_set_track_visited_links (label, g_value_get_boolean (value));
1142       break;
1143     default:
1144       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1145       break;
1146     }
1147 }
1148
1149 static void 
1150 gtk_label_get_property (GObject     *object,
1151                         guint        prop_id,
1152                         GValue      *value,
1153                         GParamSpec  *pspec)
1154 {
1155   GtkLabel *label = GTK_LABEL (object);
1156   GtkLabelPrivate *priv = label->priv;
1157
1158   switch (prop_id)
1159     {
1160     case PROP_LABEL:
1161       g_value_set_string (value, priv->label);
1162       break;
1163     case PROP_ATTRIBUTES:
1164       g_value_set_boxed (value, priv->attrs);
1165       break;
1166     case PROP_USE_MARKUP:
1167       g_value_set_boolean (value, priv->use_markup);
1168       break;
1169     case PROP_USE_UNDERLINE:
1170       g_value_set_boolean (value, priv->use_underline);
1171       break;
1172     case PROP_JUSTIFY:
1173       g_value_set_enum (value, priv->jtype);
1174       break;
1175     case PROP_WRAP:
1176       g_value_set_boolean (value, priv->wrap);
1177       break;
1178     case PROP_WRAP_MODE:
1179       g_value_set_enum (value, priv->wrap_mode);
1180       break;
1181     case PROP_SELECTABLE:
1182       g_value_set_boolean (value, gtk_label_get_selectable (label));
1183       break;
1184     case PROP_MNEMONIC_KEYVAL:
1185       g_value_set_uint (value, priv->mnemonic_keyval);
1186       break;
1187     case PROP_MNEMONIC_WIDGET:
1188       g_value_set_object (value, (GObject*) priv->mnemonic_widget);
1189       break;
1190     case PROP_CURSOR_POSITION:
1191       g_value_set_int (value, _gtk_label_get_cursor_position (label));
1192       break;
1193     case PROP_SELECTION_BOUND:
1194       g_value_set_int (value, _gtk_label_get_selection_bound (label));
1195       break;
1196     case PROP_ELLIPSIZE:
1197       g_value_set_enum (value, priv->ellipsize);
1198       break;
1199     case PROP_WIDTH_CHARS:
1200       g_value_set_int (value, gtk_label_get_width_chars (label));
1201       break;
1202     case PROP_SINGLE_LINE_MODE:
1203       g_value_set_boolean (value, gtk_label_get_single_line_mode (label));
1204       break;
1205     case PROP_ANGLE:
1206       g_value_set_double (value, gtk_label_get_angle (label));
1207       break;
1208     case PROP_MAX_WIDTH_CHARS:
1209       g_value_set_int (value, gtk_label_get_max_width_chars (label));
1210       break;
1211     case PROP_TRACK_VISITED_LINKS:
1212       g_value_set_boolean (value, gtk_label_get_track_visited_links (label));
1213       break;
1214     default:
1215       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1216       break;
1217     }
1218 }
1219
1220 static void
1221 gtk_label_init (GtkLabel *label)
1222 {
1223   GtkLabelPrivate *priv;
1224
1225   label->priv = G_TYPE_INSTANCE_GET_PRIVATE (label,
1226                                              GTK_TYPE_LABEL,
1227                                              GtkLabelPrivate);
1228   priv = label->priv;
1229
1230   gtk_widget_set_has_window (GTK_WIDGET (label), FALSE);
1231
1232   priv->width_chars = -1;
1233   priv->max_width_chars = -1;
1234   priv->label = NULL;
1235
1236   priv->jtype = GTK_JUSTIFY_LEFT;
1237   priv->wrap = FALSE;
1238   priv->wrap_mode = PANGO_WRAP_WORD;
1239   priv->ellipsize = PANGO_ELLIPSIZE_NONE;
1240
1241   priv->use_underline = FALSE;
1242   priv->use_markup = FALSE;
1243   priv->pattern_set = FALSE;
1244   priv->track_links = TRUE;
1245
1246   priv->mnemonic_keyval = GDK_KEY_VoidSymbol;
1247   priv->layout = NULL;
1248   priv->text = NULL;
1249   priv->attrs = NULL;
1250
1251   priv->mnemonic_widget = NULL;
1252   priv->mnemonic_window = NULL;
1253
1254   priv->mnemonics_visible = TRUE;
1255
1256   gtk_label_set_text (label, "");
1257 }
1258
1259
1260 static void
1261 gtk_label_buildable_interface_init (GtkBuildableIface *iface)
1262 {
1263   buildable_parent_iface = g_type_interface_peek_parent (iface);
1264
1265   iface->custom_tag_start = gtk_label_buildable_custom_tag_start;
1266   iface->custom_finished = gtk_label_buildable_custom_finished;
1267 }
1268
1269 typedef struct {
1270   GtkBuilder    *builder;
1271   GObject       *object;
1272   PangoAttrList *attrs;
1273 } PangoParserData;
1274
1275 static PangoAttribute *
1276 attribute_from_text (GtkBuilder   *builder,
1277                      const gchar  *name, 
1278                      const gchar  *value,
1279                      GError      **error)
1280 {
1281   PangoAttribute *attribute = NULL;
1282   PangoAttrType   type;
1283   PangoLanguage  *language;
1284   PangoFontDescription *font_desc;
1285   GdkColor       *color;
1286   GValue          val = G_VALUE_INIT;
1287
1288   if (!gtk_builder_value_from_string_type (builder, PANGO_TYPE_ATTR_TYPE, name, &val, error))
1289     return NULL;
1290
1291   type = g_value_get_enum (&val);
1292   g_value_unset (&val);
1293
1294   switch (type)
1295     {
1296       /* PangoAttrLanguage */
1297     case PANGO_ATTR_LANGUAGE:
1298       if ((language = pango_language_from_string (value)))
1299         {
1300           attribute = pango_attr_language_new (language);
1301           g_value_init (&val, G_TYPE_INT);
1302         }
1303       break;
1304       /* PangoAttrInt */
1305     case PANGO_ATTR_STYLE:
1306       if (gtk_builder_value_from_string_type (builder, PANGO_TYPE_STYLE, value, &val, error))
1307         attribute = pango_attr_style_new (g_value_get_enum (&val));
1308       break;
1309     case PANGO_ATTR_WEIGHT:
1310       if (gtk_builder_value_from_string_type (builder, PANGO_TYPE_WEIGHT, value, &val, error))
1311         attribute = pango_attr_weight_new (g_value_get_enum (&val));
1312       break;
1313     case PANGO_ATTR_VARIANT:
1314       if (gtk_builder_value_from_string_type (builder, PANGO_TYPE_VARIANT, value, &val, error))
1315         attribute = pango_attr_variant_new (g_value_get_enum (&val));
1316       break;
1317     case PANGO_ATTR_STRETCH:
1318       if (gtk_builder_value_from_string_type (builder, PANGO_TYPE_STRETCH, value, &val, error))
1319         attribute = pango_attr_stretch_new (g_value_get_enum (&val));
1320       break;
1321     case PANGO_ATTR_UNDERLINE:
1322       if (gtk_builder_value_from_string_type (builder, PANGO_TYPE_UNDERLINE, value, &val, NULL))
1323         attribute = pango_attr_underline_new (g_value_get_enum (&val));
1324       else
1325         {
1326           /* XXX: allow boolean for backwards compat, so ignore error */
1327           /* Deprecate this somehow */
1328           g_value_unset (&val);
1329           if (gtk_builder_value_from_string_type (builder, G_TYPE_BOOLEAN, value, &val, error))
1330             attribute = pango_attr_underline_new (g_value_get_boolean (&val));
1331         }
1332       break;
1333     case PANGO_ATTR_STRIKETHROUGH:      
1334       if (gtk_builder_value_from_string_type (builder, G_TYPE_BOOLEAN, value, &val, error))
1335         attribute = pango_attr_strikethrough_new (g_value_get_boolean (&val));
1336       break;
1337     case PANGO_ATTR_GRAVITY:
1338       if (gtk_builder_value_from_string_type (builder, PANGO_TYPE_GRAVITY, value, &val, error))
1339         attribute = pango_attr_gravity_new (g_value_get_enum (&val));
1340       break;
1341     case PANGO_ATTR_GRAVITY_HINT:
1342       if (gtk_builder_value_from_string_type (builder, PANGO_TYPE_GRAVITY_HINT, 
1343                                               value, &val, error))
1344         attribute = pango_attr_gravity_hint_new (g_value_get_enum (&val));
1345       break;
1346       /* PangoAttrString */       
1347     case PANGO_ATTR_FAMILY:
1348       attribute = pango_attr_family_new (value);
1349       g_value_init (&val, G_TYPE_INT);
1350       break;
1351
1352       /* PangoAttrSize */         
1353     case PANGO_ATTR_SIZE:
1354       if (gtk_builder_value_from_string_type (builder, G_TYPE_INT, 
1355                                               value, &val, error))
1356         attribute = pango_attr_size_new (g_value_get_int (&val));
1357       break;
1358     case PANGO_ATTR_ABSOLUTE_SIZE:
1359       if (gtk_builder_value_from_string_type (builder, G_TYPE_INT, 
1360                                               value, &val, error))
1361         attribute = pango_attr_size_new_absolute (g_value_get_int (&val));
1362       break;
1363     
1364       /* PangoAttrFontDesc */
1365     case PANGO_ATTR_FONT_DESC:
1366       if ((font_desc = pango_font_description_from_string (value)))
1367         {
1368           attribute = pango_attr_font_desc_new (font_desc);
1369           pango_font_description_free (font_desc);
1370           g_value_init (&val, G_TYPE_INT);
1371         }
1372       break;
1373
1374       /* PangoAttrColor */
1375     case PANGO_ATTR_FOREGROUND:
1376       if (gtk_builder_value_from_string_type (builder, GDK_TYPE_COLOR, 
1377                                               value, &val, error))
1378         {
1379           color = g_value_get_boxed (&val);
1380           attribute = pango_attr_foreground_new (color->red, color->green, color->blue);
1381         }
1382       break;
1383     case PANGO_ATTR_BACKGROUND: 
1384       if (gtk_builder_value_from_string_type (builder, GDK_TYPE_COLOR, 
1385                                               value, &val, error))
1386         {
1387           color = g_value_get_boxed (&val);
1388           attribute = pango_attr_background_new (color->red, color->green, color->blue);
1389         }
1390       break;
1391     case PANGO_ATTR_UNDERLINE_COLOR:
1392       if (gtk_builder_value_from_string_type (builder, GDK_TYPE_COLOR, 
1393                                               value, &val, error))
1394         {
1395           color = g_value_get_boxed (&val);
1396           attribute = pango_attr_underline_color_new (color->red, color->green, color->blue);
1397         }
1398       break;
1399     case PANGO_ATTR_STRIKETHROUGH_COLOR:
1400       if (gtk_builder_value_from_string_type (builder, GDK_TYPE_COLOR, 
1401                                               value, &val, error))
1402         {
1403           color = g_value_get_boxed (&val);
1404           attribute = pango_attr_strikethrough_color_new (color->red, color->green, color->blue);
1405         }
1406       break;
1407       
1408       /* PangoAttrShape */
1409     case PANGO_ATTR_SHAPE:
1410       /* Unsupported for now */
1411       break;
1412       /* PangoAttrFloat */
1413     case PANGO_ATTR_SCALE:
1414       if (gtk_builder_value_from_string_type (builder, G_TYPE_DOUBLE, 
1415                                               value, &val, error))
1416         attribute = pango_attr_scale_new (g_value_get_double (&val));
1417       break;
1418
1419     case PANGO_ATTR_INVALID:
1420     case PANGO_ATTR_LETTER_SPACING:
1421     case PANGO_ATTR_RISE:
1422     case PANGO_ATTR_FALLBACK:
1423     default:
1424       break;
1425     }
1426
1427   g_value_unset (&val);
1428
1429   return attribute;
1430 }
1431
1432
1433 static void
1434 pango_start_element (GMarkupParseContext *context,
1435                      const gchar         *element_name,
1436                      const gchar        **names,
1437                      const gchar        **values,
1438                      gpointer             user_data,
1439                      GError             **error)
1440 {
1441   PangoParserData *data = (PangoParserData*)user_data;
1442   GValue val = G_VALUE_INIT;
1443   guint i;
1444   gint line_number, char_number;
1445
1446   if (strcmp (element_name, "attribute") == 0)
1447     {
1448       PangoAttribute *attr = NULL;
1449       const gchar *name = NULL;
1450       const gchar *value = NULL;
1451       const gchar *start = NULL;
1452       const gchar *end = NULL;
1453       guint start_val = 0;
1454       guint end_val   = G_MAXUINT;
1455
1456       for (i = 0; names[i]; i++)
1457         {
1458           if (strcmp (names[i], "name") == 0)
1459             name = values[i];
1460           else if (strcmp (names[i], "value") == 0)
1461             value = values[i];
1462           else if (strcmp (names[i], "start") == 0)
1463             start = values[i];
1464           else if (strcmp (names[i], "end") == 0)
1465             end = values[i];
1466           else
1467             {
1468               g_markup_parse_context_get_position (context,
1469                                                    &line_number,
1470                                                    &char_number);
1471               g_set_error (error,
1472                            GTK_BUILDER_ERROR,
1473                            GTK_BUILDER_ERROR_INVALID_ATTRIBUTE,
1474                            "%s:%d:%d '%s' is not a valid attribute of <%s>",
1475                            "<input>",
1476                            line_number, char_number, names[i], "attribute");
1477               return;
1478             }
1479         }
1480
1481       if (!name || !value)
1482         {
1483           g_markup_parse_context_get_position (context,
1484                                                &line_number,
1485                                                &char_number);
1486           g_set_error (error,
1487                        GTK_BUILDER_ERROR,
1488                        GTK_BUILDER_ERROR_MISSING_ATTRIBUTE,
1489                        "%s:%d:%d <%s> requires attribute \"%s\"",
1490                        "<input>",
1491                        line_number, char_number, "attribute",
1492                        name ? "value" : "name");
1493           return;
1494         }
1495
1496       if (start)
1497         {
1498           if (!gtk_builder_value_from_string_type (data->builder, G_TYPE_UINT, 
1499                                                    start, &val, error))
1500             return;
1501           start_val = g_value_get_uint (&val);
1502           g_value_unset (&val);
1503         }
1504
1505       if (end)
1506         {
1507           if (!gtk_builder_value_from_string_type (data->builder, G_TYPE_UINT, 
1508                                                    end, &val, error))
1509             return;
1510           end_val = g_value_get_uint (&val);
1511           g_value_unset (&val);
1512         }
1513
1514       attr = attribute_from_text (data->builder, name, value, error);
1515
1516       if (attr)
1517         {
1518           attr->start_index = start_val;
1519           attr->end_index   = end_val;
1520
1521           if (!data->attrs)
1522             data->attrs = pango_attr_list_new ();
1523
1524           pango_attr_list_insert (data->attrs, attr);
1525         }
1526     }
1527   else if (strcmp (element_name, "attributes") == 0)
1528     ;
1529   else
1530     g_warning ("Unsupported tag for GtkLabel: %s\n", element_name);
1531 }
1532
1533 static const GMarkupParser pango_parser =
1534   {
1535     pango_start_element,
1536   };
1537
1538 static gboolean
1539 gtk_label_buildable_custom_tag_start (GtkBuildable     *buildable,
1540                                       GtkBuilder       *builder,
1541                                       GObject          *child,
1542                                       const gchar      *tagname,
1543                                       GMarkupParser    *parser,
1544                                       gpointer         *data)
1545 {
1546   if (buildable_parent_iface->custom_tag_start (buildable, builder, child, 
1547                                                 tagname, parser, data))
1548     return TRUE;
1549
1550   if (strcmp (tagname, "attributes") == 0)
1551     {
1552       PangoParserData *parser_data;
1553
1554       parser_data = g_slice_new0 (PangoParserData);
1555       parser_data->builder = g_object_ref (builder);
1556       parser_data->object = g_object_ref (buildable);
1557       *parser = pango_parser;
1558       *data = parser_data;
1559       return TRUE;
1560     }
1561   return FALSE;
1562 }
1563
1564 static void
1565 gtk_label_buildable_custom_finished (GtkBuildable *buildable,
1566                                      GtkBuilder   *builder,
1567                                      GObject      *child,
1568                                      const gchar  *tagname,
1569                                      gpointer      user_data)
1570 {
1571   PangoParserData *data;
1572
1573   buildable_parent_iface->custom_finished (buildable, builder, child, 
1574                                            tagname, user_data);
1575
1576   if (strcmp (tagname, "attributes") == 0)
1577     {
1578       data = (PangoParserData*)user_data;
1579
1580       if (data->attrs)
1581         {
1582           gtk_label_set_attributes (GTK_LABEL (buildable), data->attrs);
1583           pango_attr_list_unref (data->attrs);
1584         }
1585
1586       g_object_unref (data->object);
1587       g_object_unref (data->builder);
1588       g_slice_free (PangoParserData, data);
1589     }
1590 }
1591
1592
1593 /**
1594  * gtk_label_new:
1595  * @str: The text of the label
1596  *
1597  * Creates a new label with the given text inside it. You can
1598  * pass %NULL to get an empty label widget.
1599  *
1600  * Return value: the new #GtkLabel
1601  **/
1602 GtkWidget*
1603 gtk_label_new (const gchar *str)
1604 {
1605   GtkLabel *label;
1606   
1607   label = g_object_new (GTK_TYPE_LABEL, NULL);
1608
1609   if (str && *str)
1610     gtk_label_set_text (label, str);
1611   
1612   return GTK_WIDGET (label);
1613 }
1614
1615 /**
1616  * gtk_label_new_with_mnemonic:
1617  * @str: The text of the label, with an underscore in front of the
1618  *       mnemonic character
1619  *
1620  * Creates a new #GtkLabel, containing the text in @str.
1621  *
1622  * If characters in @str are preceded by an underscore, they are
1623  * underlined. If you need a literal underscore character in a label, use
1624  * '__' (two underscores). The first underlined character represents a 
1625  * keyboard accelerator called a mnemonic. The mnemonic key can be used 
1626  * to activate another widget, chosen automatically, or explicitly using
1627  * gtk_label_set_mnemonic_widget().
1628  * 
1629  * If gtk_label_set_mnemonic_widget() is not called, then the first 
1630  * activatable ancestor of the #GtkLabel will be chosen as the mnemonic 
1631  * widget. For instance, if the label is inside a button or menu item, 
1632  * the button or menu item will automatically become the mnemonic widget 
1633  * and be activated by the mnemonic.
1634  *
1635  * Return value: the new #GtkLabel
1636  **/
1637 GtkWidget*
1638 gtk_label_new_with_mnemonic (const gchar *str)
1639 {
1640   GtkLabel *label;
1641   
1642   label = g_object_new (GTK_TYPE_LABEL, NULL);
1643
1644   if (str && *str)
1645     gtk_label_set_text_with_mnemonic (label, str);
1646   
1647   return GTK_WIDGET (label);
1648 }
1649
1650 static gboolean
1651 gtk_label_mnemonic_activate (GtkWidget *widget,
1652                              gboolean   group_cycling)
1653 {
1654   GtkLabel *label = GTK_LABEL (widget);
1655   GtkLabelPrivate *priv = label->priv;
1656   GtkWidget *parent;
1657
1658   if (priv->mnemonic_widget)
1659     return gtk_widget_mnemonic_activate (priv->mnemonic_widget, group_cycling);
1660
1661   /* Try to find the widget to activate by traversing the
1662    * widget's ancestry.
1663    */
1664   parent = gtk_widget_get_parent (widget);
1665
1666   if (GTK_IS_NOTEBOOK (parent))
1667     return FALSE;
1668   
1669   while (parent)
1670     {
1671       if (gtk_widget_get_can_focus (parent) ||
1672           (!group_cycling && GTK_WIDGET_GET_CLASS (parent)->activate_signal) ||
1673           GTK_IS_NOTEBOOK (gtk_widget_get_parent (parent)) ||
1674           GTK_IS_MENU_ITEM (parent))
1675         return gtk_widget_mnemonic_activate (parent, group_cycling);
1676       parent = gtk_widget_get_parent (parent);
1677     }
1678
1679   /* barf if there was nothing to activate */
1680   g_warning ("Couldn't find a target for a mnemonic activation.");
1681   gtk_widget_error_bell (widget);
1682
1683   return FALSE;
1684 }
1685
1686 static void
1687 gtk_label_setup_mnemonic (GtkLabel *label,
1688                           guint     last_key)
1689 {
1690   GtkLabelPrivate *priv = label->priv;
1691   GtkWidget *widget = GTK_WIDGET (label);
1692   GtkWidget *toplevel;
1693   GtkWidget *mnemonic_menu;
1694   
1695   mnemonic_menu = g_object_get_data (G_OBJECT (label), "gtk-mnemonic-menu");
1696   
1697   if (last_key != GDK_KEY_VoidSymbol)
1698     {
1699       if (priv->mnemonic_window)
1700         {
1701           gtk_window_remove_mnemonic  (priv->mnemonic_window,
1702                                        last_key,
1703                                        widget);
1704           priv->mnemonic_window = NULL;
1705         }
1706       if (mnemonic_menu)
1707         {
1708           _gtk_menu_shell_remove_mnemonic (GTK_MENU_SHELL (mnemonic_menu),
1709                                            last_key,
1710                                            widget);
1711           mnemonic_menu = NULL;
1712         }
1713     }
1714   
1715   if (priv->mnemonic_keyval == GDK_KEY_VoidSymbol)
1716       goto done;
1717
1718   connect_mnemonics_visible_notify (GTK_LABEL (widget));
1719
1720   toplevel = gtk_widget_get_toplevel (widget);
1721   if (gtk_widget_is_toplevel (toplevel))
1722     {
1723       GtkWidget *menu_shell;
1724       
1725       menu_shell = gtk_widget_get_ancestor (widget,
1726                                             GTK_TYPE_MENU_SHELL);
1727
1728       if (menu_shell)
1729         {
1730           _gtk_menu_shell_add_mnemonic (GTK_MENU_SHELL (menu_shell),
1731                                         priv->mnemonic_keyval,
1732                                         widget);
1733           mnemonic_menu = menu_shell;
1734         }
1735       
1736       if (!GTK_IS_MENU (menu_shell))
1737         {
1738           gtk_window_add_mnemonic (GTK_WINDOW (toplevel),
1739                                    priv->mnemonic_keyval,
1740                                    widget);
1741           priv->mnemonic_window = GTK_WINDOW (toplevel);
1742         }
1743     }
1744   
1745  done:
1746   g_object_set_data (G_OBJECT (label), I_("gtk-mnemonic-menu"), mnemonic_menu);
1747 }
1748
1749 static void
1750 gtk_label_hierarchy_changed (GtkWidget *widget,
1751                              GtkWidget *old_toplevel)
1752 {
1753   GtkLabel *label = GTK_LABEL (widget);
1754   GtkLabelPrivate *priv = label->priv;
1755
1756   gtk_label_setup_mnemonic (label, priv->mnemonic_keyval);
1757 }
1758
1759 static void
1760 label_shortcut_setting_apply (GtkLabel *label)
1761 {
1762   gtk_label_recalculate (label);
1763   if (GTK_IS_ACCEL_LABEL (label))
1764     gtk_accel_label_refetch (GTK_ACCEL_LABEL (label));
1765 }
1766
1767 static void
1768 label_shortcut_setting_traverse_container (GtkWidget *widget,
1769                                            gpointer   data)
1770 {
1771   if (GTK_IS_LABEL (widget))
1772     label_shortcut_setting_apply (GTK_LABEL (widget));
1773   else if (GTK_IS_CONTAINER (widget))
1774     gtk_container_forall (GTK_CONTAINER (widget),
1775                           label_shortcut_setting_traverse_container, data);
1776 }
1777
1778 static void
1779 label_shortcut_setting_changed (GtkSettings *settings)
1780 {
1781   GList *list, *l;
1782
1783   list = gtk_window_list_toplevels ();
1784
1785   for (l = list; l ; l = l->next)
1786     {
1787       GtkWidget *widget = l->data;
1788
1789       if (gtk_widget_get_settings (widget) == settings)
1790         gtk_container_forall (GTK_CONTAINER (widget),
1791                               label_shortcut_setting_traverse_container, NULL);
1792     }
1793
1794   g_list_free (list);
1795 }
1796
1797 static void
1798 mnemonics_visible_apply (GtkWidget *widget,
1799                          gboolean   mnemonics_visible)
1800 {
1801   GtkLabel *label = GTK_LABEL (widget);
1802   GtkLabelPrivate *priv = label->priv;
1803
1804   mnemonics_visible = mnemonics_visible != FALSE;
1805
1806   if (priv->mnemonics_visible != mnemonics_visible)
1807     {
1808       priv->mnemonics_visible = mnemonics_visible;
1809
1810       gtk_label_recalculate (label);
1811     }
1812 }
1813
1814 static void
1815 label_mnemonics_visible_traverse_container (GtkWidget *widget,
1816                                             gpointer   data)
1817 {
1818   gboolean mnemonics_visible = GPOINTER_TO_INT (data);
1819
1820   _gtk_label_mnemonics_visible_apply_recursively (widget, mnemonics_visible);
1821 }
1822
1823 void
1824 _gtk_label_mnemonics_visible_apply_recursively (GtkWidget *widget,
1825                                                 gboolean   mnemonics_visible)
1826 {
1827   if (GTK_IS_LABEL (widget))
1828     mnemonics_visible_apply (widget, mnemonics_visible);
1829   else if (GTK_IS_CONTAINER (widget))
1830     gtk_container_forall (GTK_CONTAINER (widget),
1831                           label_mnemonics_visible_traverse_container,
1832                           GINT_TO_POINTER (mnemonics_visible));
1833 }
1834
1835 static void
1836 label_mnemonics_visible_changed (GtkWindow  *window,
1837                                  GParamSpec *pspec,
1838                                  gpointer    data)
1839 {
1840   gboolean mnemonics_visible;
1841
1842   g_object_get (window, "mnemonics-visible", &mnemonics_visible, NULL);
1843
1844   gtk_container_forall (GTK_CONTAINER (window),
1845                         label_mnemonics_visible_traverse_container,
1846                         GINT_TO_POINTER (mnemonics_visible));
1847 }
1848
1849 static void
1850 gtk_label_screen_changed (GtkWidget *widget,
1851                           GdkScreen *old_screen)
1852 {
1853   GtkSettings *settings;
1854   gboolean shortcuts_connected;
1855
1856   if (!gtk_widget_has_screen (widget))
1857     return;
1858
1859   settings = gtk_widget_get_settings (widget);
1860
1861   shortcuts_connected =
1862     GPOINTER_TO_INT (g_object_get_data (G_OBJECT (settings),
1863                                         "gtk-label-shortcuts-connected"));
1864
1865   if (! shortcuts_connected)
1866     {
1867       g_signal_connect (settings, "notify::gtk-enable-mnemonics",
1868                         G_CALLBACK (label_shortcut_setting_changed),
1869                         NULL);
1870       g_signal_connect (settings, "notify::gtk-enable-accels",
1871                         G_CALLBACK (label_shortcut_setting_changed),
1872                         NULL);
1873
1874       g_object_set_data (G_OBJECT (settings), "gtk-label-shortcuts-connected",
1875                          GINT_TO_POINTER (TRUE));
1876     }
1877
1878   label_shortcut_setting_apply (GTK_LABEL (widget));
1879 }
1880
1881
1882 static void
1883 label_mnemonic_widget_weak_notify (gpointer      data,
1884                                    GObject      *where_the_object_was)
1885 {
1886   GtkLabel *label = data;
1887   GtkLabelPrivate *priv = label->priv;
1888
1889   priv->mnemonic_widget = NULL;
1890   g_object_notify (G_OBJECT (label), "mnemonic-widget");
1891 }
1892
1893 /**
1894  * gtk_label_set_mnemonic_widget:
1895  * @label: a #GtkLabel
1896  * @widget: (allow-none): the target #GtkWidget
1897  *
1898  * If the label has been set so that it has an mnemonic key (using
1899  * i.e. gtk_label_set_markup_with_mnemonic(),
1900  * gtk_label_set_text_with_mnemonic(), gtk_label_new_with_mnemonic()
1901  * or the "use_underline" property) the label can be associated with a
1902  * widget that is the target of the mnemonic. When the label is inside
1903  * a widget (like a #GtkButton or a #GtkNotebook tab) it is
1904  * automatically associated with the correct widget, but sometimes
1905  * (i.e. when the target is a #GtkEntry next to the label) you need to
1906  * set it explicitly using this function.
1907  *
1908  * The target widget will be accelerated by emitting the 
1909  * GtkWidget::mnemonic-activate signal on it. The default handler for 
1910  * this signal will activate the widget if there are no mnemonic collisions 
1911  * and toggle focus between the colliding widgets otherwise.
1912  **/
1913 void
1914 gtk_label_set_mnemonic_widget (GtkLabel  *label,
1915                                GtkWidget *widget)
1916 {
1917   GtkLabelPrivate *priv;
1918
1919   g_return_if_fail (GTK_IS_LABEL (label));
1920
1921   priv = label->priv;
1922
1923   if (widget)
1924     g_return_if_fail (GTK_IS_WIDGET (widget));
1925
1926   if (priv->mnemonic_widget)
1927     {
1928       gtk_widget_remove_mnemonic_label (priv->mnemonic_widget, GTK_WIDGET (label));
1929       g_object_weak_unref (G_OBJECT (priv->mnemonic_widget),
1930                            label_mnemonic_widget_weak_notify,
1931                            label);
1932     }
1933   priv->mnemonic_widget = widget;
1934   if (priv->mnemonic_widget)
1935     {
1936       g_object_weak_ref (G_OBJECT (priv->mnemonic_widget),
1937                          label_mnemonic_widget_weak_notify,
1938                          label);
1939       gtk_widget_add_mnemonic_label (priv->mnemonic_widget, GTK_WIDGET (label));
1940     }
1941   
1942   g_object_notify (G_OBJECT (label), "mnemonic-widget");
1943 }
1944
1945 /**
1946  * gtk_label_get_mnemonic_widget:
1947  * @label: a #GtkLabel
1948  *
1949  * Retrieves the target of the mnemonic (keyboard shortcut) of this
1950  * label. See gtk_label_set_mnemonic_widget().
1951  *
1952  * Return value: (transfer none): the target of the label's mnemonic,
1953  *     or %NULL if none has been set and the default algorithm will be used.
1954  **/
1955 GtkWidget *
1956 gtk_label_get_mnemonic_widget (GtkLabel *label)
1957 {
1958   g_return_val_if_fail (GTK_IS_LABEL (label), NULL);
1959
1960   return label->priv->mnemonic_widget;
1961 }
1962
1963 /**
1964  * gtk_label_get_mnemonic_keyval:
1965  * @label: a #GtkLabel
1966  *
1967  * If the label has been set so that it has an mnemonic key this function
1968  * returns the keyval used for the mnemonic accelerator. If there is no
1969  * mnemonic set up it returns #GDK_VoidSymbol.
1970  *
1971  * Returns: GDK keyval usable for accelerators, or #GDK_VoidSymbol
1972  **/
1973 guint
1974 gtk_label_get_mnemonic_keyval (GtkLabel *label)
1975 {
1976   g_return_val_if_fail (GTK_IS_LABEL (label), GDK_KEY_VoidSymbol);
1977
1978   return label->priv->mnemonic_keyval;
1979 }
1980
1981 static void
1982 gtk_label_set_text_internal (GtkLabel *label,
1983                              gchar    *str)
1984 {
1985   GtkLabelPrivate *priv = label->priv;
1986
1987   g_free (priv->text);
1988
1989   priv->text = str;
1990
1991   gtk_label_select_region_index (label, 0, 0);
1992 }
1993
1994 static void
1995 gtk_label_set_label_internal (GtkLabel *label,
1996                               gchar    *str)
1997 {
1998   GtkLabelPrivate *priv = label->priv;
1999
2000   g_free (priv->label);
2001
2002   priv->label = str;
2003
2004   g_object_notify (G_OBJECT (label), "label");
2005 }
2006
2007 static void
2008 gtk_label_set_use_markup_internal (GtkLabel *label,
2009                                    gboolean  val)
2010 {
2011   GtkLabelPrivate *priv = label->priv;
2012
2013   val = val != FALSE;
2014   if (priv->use_markup != val)
2015     {
2016       priv->use_markup = val;
2017
2018       g_object_notify (G_OBJECT (label), "use-markup");
2019     }
2020 }
2021
2022 static void
2023 gtk_label_set_use_underline_internal (GtkLabel *label,
2024                                       gboolean val)
2025 {
2026   GtkLabelPrivate *priv = label->priv;
2027
2028   val = val != FALSE;
2029   if (priv->use_underline != val)
2030     {
2031       priv->use_underline = val;
2032
2033       g_object_notify (G_OBJECT (label), "use-underline");
2034     }
2035 }
2036
2037 static void
2038 my_pango_attr_list_merge (PangoAttrList *into,
2039                           PangoAttrList *from)
2040 {
2041   PangoAttrIterator *iter;
2042   PangoAttribute    *attr;
2043   GSList            *iter_attrs, *l;
2044
2045   iter = pango_attr_list_get_iterator (into);
2046
2047   if (iter)
2048     {
2049       do
2050         {
2051           iter_attrs = pango_attr_iterator_get_attrs (iter);
2052           for (l = iter_attrs; l; l = l->next)
2053             {
2054               attr = l->data;
2055               pango_attr_list_insert (from, attr);
2056             }
2057           g_slist_free (iter_attrs);
2058         }
2059       while (pango_attr_iterator_next (iter));
2060       pango_attr_iterator_destroy (iter);
2061     }
2062 }
2063
2064 static void
2065 gtk_label_compose_effective_attrs (GtkLabel *label)
2066 {
2067   GtkLabelPrivate *priv = label->priv;
2068
2069   if (priv->attrs)
2070     {
2071       if (priv->effective_attrs)
2072         my_pango_attr_list_merge (priv->effective_attrs, priv->attrs);
2073       else
2074         priv->effective_attrs =
2075           pango_attr_list_ref (priv->attrs);
2076     }
2077 }
2078
2079 /* Calculates text, attrs and mnemonic_keyval from
2080  * label, use_underline and use_markup
2081  */
2082 static void
2083 gtk_label_recalculate (GtkLabel *label)
2084 {
2085   GtkLabelPrivate *priv = label->priv;
2086   guint keyval = priv->mnemonic_keyval;
2087
2088   gtk_label_clear_links (label);
2089
2090   if (priv->use_markup)
2091     gtk_label_set_markup_internal (label, priv->label, priv->use_underline);
2092   else if (priv->use_underline)
2093     gtk_label_set_uline_text_internal (label, priv->label);
2094   else
2095     {
2096       if (!priv->pattern_set)
2097         {
2098           if (priv->effective_attrs)
2099             pango_attr_list_unref (priv->effective_attrs);
2100           priv->effective_attrs = NULL;
2101         }
2102       gtk_label_set_text_internal (label, g_strdup (priv->label));
2103     }
2104
2105   gtk_label_compose_effective_attrs (label);
2106
2107   if (!priv->use_underline)
2108     priv->mnemonic_keyval = GDK_KEY_VoidSymbol;
2109
2110   if (keyval != priv->mnemonic_keyval)
2111     {
2112       gtk_label_setup_mnemonic (label, keyval);
2113       g_object_notify (G_OBJECT (label), "mnemonic-keyval");
2114     }
2115
2116   gtk_label_clear_layout (label);
2117   gtk_label_clear_select_info (label);
2118   gtk_widget_queue_resize (GTK_WIDGET (label));
2119 }
2120
2121 /**
2122  * gtk_label_set_text:
2123  * @label: a #GtkLabel
2124  * @str: The text you want to set
2125  *
2126  * Sets the text within the #GtkLabel widget. It overwrites any text that
2127  * was there before.  
2128  *
2129  * This will also clear any previously set mnemonic accelerators.
2130  **/
2131 void
2132 gtk_label_set_text (GtkLabel    *label,
2133                     const gchar *str)
2134 {
2135   g_return_if_fail (GTK_IS_LABEL (label));
2136   
2137   g_object_freeze_notify (G_OBJECT (label));
2138
2139   gtk_label_set_label_internal (label, g_strdup (str ? str : ""));
2140   gtk_label_set_use_markup_internal (label, FALSE);
2141   gtk_label_set_use_underline_internal (label, FALSE);
2142   
2143   gtk_label_recalculate (label);
2144
2145   g_object_thaw_notify (G_OBJECT (label));
2146 }
2147
2148 /**
2149  * gtk_label_set_attributes:
2150  * @label: a #GtkLabel
2151  * @attrs: a #PangoAttrList
2152  * 
2153  * Sets a #PangoAttrList; the attributes in the list are applied to the
2154  * label text. 
2155  *
2156  * <note><para>The attributes set with this function will be applied
2157  * and merged with any other attributes previously effected by way
2158  * of the #GtkLabel:use-underline or #GtkLabel:use-markup properties.
2159  * While it is not recommended to mix markup strings with manually set
2160  * attributes, if you must; know that the attributes will be applied
2161  * to the label after the markup string is parsed.</para></note>
2162  **/
2163 void
2164 gtk_label_set_attributes (GtkLabel         *label,
2165                           PangoAttrList    *attrs)
2166 {
2167   GtkLabelPrivate *priv = label->priv;
2168
2169   g_return_if_fail (GTK_IS_LABEL (label));
2170
2171   if (attrs)
2172     pango_attr_list_ref (attrs);
2173
2174   if (priv->attrs)
2175     pango_attr_list_unref (priv->attrs);
2176   priv->attrs = attrs;
2177
2178   g_object_notify (G_OBJECT (label), "attributes");
2179
2180   gtk_label_recalculate (label);
2181
2182   gtk_label_clear_layout (label);
2183   gtk_widget_queue_resize (GTK_WIDGET (label));
2184 }
2185
2186 /**
2187  * gtk_label_get_attributes:
2188  * @label: a #GtkLabel
2189  *
2190  * Gets the attribute list that was set on the label using
2191  * gtk_label_set_attributes(), if any. This function does
2192  * not reflect attributes that come from the labels markup
2193  * (see gtk_label_set_markup()). If you want to get the
2194  * effective attributes for the label, use
2195  * pango_layout_get_attribute (gtk_label_get_layout (label)).
2196  *
2197  * Return value: (transfer none): the attribute list, or %NULL
2198  *     if none was set.
2199  **/
2200 PangoAttrList *
2201 gtk_label_get_attributes (GtkLabel *label)
2202 {
2203   g_return_val_if_fail (GTK_IS_LABEL (label), NULL);
2204
2205   return label->priv->attrs;
2206 }
2207
2208 /**
2209  * gtk_label_set_label:
2210  * @label: a #GtkLabel
2211  * @str: the new text to set for the label
2212  *
2213  * Sets the text of the label. The label is interpreted as
2214  * including embedded underlines and/or Pango markup depending
2215  * on the values of the #GtkLabel:use-underline" and
2216  * #GtkLabel:use-markup properties.
2217  **/
2218 void
2219 gtk_label_set_label (GtkLabel    *label,
2220                      const gchar *str)
2221 {
2222   g_return_if_fail (GTK_IS_LABEL (label));
2223
2224   g_object_freeze_notify (G_OBJECT (label));
2225
2226   gtk_label_set_label_internal (label, g_strdup (str ? str : ""));
2227   gtk_label_recalculate (label);
2228
2229   g_object_thaw_notify (G_OBJECT (label));
2230 }
2231
2232 /**
2233  * gtk_label_get_label:
2234  * @label: a #GtkLabel
2235  *
2236  * Fetches the text from a label widget including any embedded
2237  * underlines indicating mnemonics and Pango markup. (See
2238  * gtk_label_get_text()).
2239  *
2240  * Return value: the text of the label widget. This string is
2241  *   owned by the widget and must not be modified or freed.
2242  **/
2243 const gchar *
2244 gtk_label_get_label (GtkLabel *label)
2245 {
2246   g_return_val_if_fail (GTK_IS_LABEL (label), NULL);
2247
2248   return label->priv->label;
2249 }
2250
2251 typedef struct
2252 {
2253   GtkLabel *label;
2254   GList *links;
2255   GString *new_str;
2256   gsize text_len;
2257   GdkColor *link_color;
2258   GdkColor *visited_link_color;
2259 } UriParserData;
2260
2261 static void
2262 start_element_handler (GMarkupParseContext  *context,
2263                        const gchar          *element_name,
2264                        const gchar         **attribute_names,
2265                        const gchar         **attribute_values,
2266                        gpointer              user_data,
2267                        GError              **error)
2268 {
2269   GtkLabelPrivate *priv;
2270   UriParserData *pdata = user_data;
2271
2272   if (strcmp (element_name, "a") == 0)
2273     {
2274       GtkLabelLink *link;
2275       const gchar *uri = NULL;
2276       const gchar *title = NULL;
2277       gboolean visited = FALSE;
2278       gint line_number;
2279       gint char_number;
2280       gint i;
2281       GdkColor *color = NULL;
2282
2283       g_markup_parse_context_get_position (context, &line_number, &char_number);
2284
2285       for (i = 0; attribute_names[i] != NULL; i++)
2286         {
2287           const gchar *attr = attribute_names[i];
2288
2289           if (strcmp (attr, "href") == 0)
2290             uri = attribute_values[i];
2291           else if (strcmp (attr, "title") == 0)
2292             title = attribute_values[i];
2293           else
2294             {
2295               g_set_error (error,
2296                            G_MARKUP_ERROR,
2297                            G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE,
2298                            "Attribute '%s' is not allowed on the <a> tag "
2299                            "on line %d char %d",
2300                             attr, line_number, char_number);
2301               return;
2302             }
2303         }
2304
2305       if (uri == NULL)
2306         {
2307           g_set_error (error,
2308                        G_MARKUP_ERROR,
2309                        G_MARKUP_ERROR_INVALID_CONTENT,
2310                        "Attribute 'href' was missing on the <a> tag "
2311                        "on line %d char %d",
2312                        line_number, char_number);
2313           return;
2314         }
2315
2316       visited = FALSE;
2317       priv = pdata->label->priv;
2318       if (priv->track_links && priv->select_info)
2319         {
2320           GList *l;
2321           for (l = priv->select_info->links; l; l = l->next)
2322             {
2323               link = l->data;
2324               if (strcmp (uri, link->uri) == 0)
2325                 {
2326                   visited = link->visited;
2327                   break;
2328                 }
2329             }
2330         }
2331
2332       if (visited)
2333         color = pdata->visited_link_color;
2334       else
2335         color = pdata->link_color;
2336
2337       g_string_append_printf (pdata->new_str,
2338                               "<span color=\"#%04x%04x%04x\" underline=\"single\">",
2339                               color->red,
2340                               color->green,
2341                               color->blue);
2342
2343       link = g_new0 (GtkLabelLink, 1);
2344       link->uri = g_strdup (uri);
2345       link->title = g_strdup (title);
2346       link->visited = visited;
2347       link->start = pdata->text_len;
2348       pdata->links = g_list_prepend (pdata->links, link);
2349     }
2350   else
2351     {
2352       gint i;
2353
2354       g_string_append_c (pdata->new_str, '<');
2355       g_string_append (pdata->new_str, element_name);
2356
2357       for (i = 0; attribute_names[i] != NULL; i++)
2358         {
2359           const gchar *attr  = attribute_names[i];
2360           const gchar *value = attribute_values[i];
2361           gchar *newvalue;
2362
2363           newvalue = g_markup_escape_text (value, -1);
2364
2365           g_string_append_c (pdata->new_str, ' ');
2366           g_string_append (pdata->new_str, attr);
2367           g_string_append (pdata->new_str, "=\"");
2368           g_string_append (pdata->new_str, newvalue);
2369           g_string_append_c (pdata->new_str, '\"');
2370
2371           g_free (newvalue);
2372         }
2373       g_string_append_c (pdata->new_str, '>');
2374     }
2375 }
2376
2377 static void
2378 end_element_handler (GMarkupParseContext  *context,
2379                      const gchar          *element_name,
2380                      gpointer              user_data,
2381                      GError              **error)
2382 {
2383   UriParserData *pdata = user_data;
2384
2385   if (!strcmp (element_name, "a"))
2386     {
2387       GtkLabelLink *link = pdata->links->data;
2388       link->end = pdata->text_len;
2389       g_string_append (pdata->new_str, "</span>");
2390     }
2391   else
2392     {
2393       g_string_append (pdata->new_str, "</");
2394       g_string_append (pdata->new_str, element_name);
2395       g_string_append_c (pdata->new_str, '>');
2396     }
2397 }
2398
2399 static void
2400 text_handler (GMarkupParseContext  *context,
2401               const gchar          *text,
2402               gsize                 text_len,
2403               gpointer              user_data,
2404               GError              **error)
2405 {
2406   UriParserData *pdata = user_data;
2407   gchar *newtext;
2408
2409   newtext = g_markup_escape_text (text, text_len);
2410   g_string_append (pdata->new_str, newtext);
2411   pdata->text_len += text_len;
2412   g_free (newtext);
2413 }
2414
2415 static const GMarkupParser markup_parser =
2416 {
2417   start_element_handler,
2418   end_element_handler,
2419   text_handler,
2420   NULL,
2421   NULL
2422 };
2423
2424 static gboolean
2425 xml_isspace (gchar c)
2426 {
2427   return (c == ' ' || c == '\t' || c == '\n' || c == '\r');
2428 }
2429
2430 static void
2431 link_free (GtkLabelLink *link)
2432 {
2433   g_free (link->uri);
2434   g_free (link->title);
2435   g_free (link);
2436 }
2437
2438 static void
2439 gtk_label_get_link_colors (GtkWidget  *widget,
2440                            GdkColor  **link_color,
2441                            GdkColor  **visited_link_color)
2442 {
2443   GtkStyleContext *context;
2444
2445   context = gtk_widget_get_style_context (widget);
2446   gtk_style_context_get_style (context,
2447                                "link-color", link_color,
2448                                "visited-link-color", visited_link_color,
2449                                 NULL);
2450   if (!*link_color)
2451     *link_color = gdk_color_copy (&default_link_color);
2452   if (!*visited_link_color)
2453     *visited_link_color = gdk_color_copy (&default_visited_link_color);
2454 }
2455
2456 static gboolean
2457 parse_uri_markup (GtkLabel     *label,
2458                   const gchar  *str,
2459                   gchar       **new_str,
2460                   GList       **links,
2461                   GError      **error)
2462 {
2463   GMarkupParseContext *context = NULL;
2464   const gchar *p, *end;
2465   gboolean needs_root = TRUE;
2466   gsize length;
2467   UriParserData pdata;
2468
2469   length = strlen (str);
2470   p = str;
2471   end = str + length;
2472
2473   pdata.label = label;
2474   pdata.links = NULL;
2475   pdata.new_str = g_string_sized_new (length);
2476   pdata.text_len = 0;
2477
2478   gtk_label_get_link_colors (GTK_WIDGET (label), &pdata.link_color, &pdata.visited_link_color);
2479
2480   while (p != end && xml_isspace (*p))
2481     p++;
2482
2483   if (end - p >= 8 && strncmp (p, "<markup>", 8) == 0)
2484     needs_root = FALSE;
2485
2486   context = g_markup_parse_context_new (&markup_parser, 0, &pdata, NULL);
2487
2488   if (needs_root)
2489     {
2490       if (!g_markup_parse_context_parse (context, "<markup>", -1, error))
2491         goto failed;
2492     }
2493
2494   if (!g_markup_parse_context_parse (context, str, length, error))
2495     goto failed;
2496
2497   if (needs_root)
2498     {
2499       if (!g_markup_parse_context_parse (context, "</markup>", -1, error))
2500         goto failed;
2501     }
2502
2503   if (!g_markup_parse_context_end_parse (context, error))
2504     goto failed;
2505
2506   g_markup_parse_context_free (context);
2507
2508   *new_str = g_string_free (pdata.new_str, FALSE);
2509   *links = pdata.links;
2510
2511   gdk_color_free (pdata.link_color);
2512   gdk_color_free (pdata.visited_link_color);
2513
2514   return TRUE;
2515
2516 failed:
2517   g_markup_parse_context_free (context);
2518   g_string_free (pdata.new_str, TRUE);
2519   g_list_free_full (pdata.links, (GDestroyNotify) link_free);
2520   gdk_color_free (pdata.link_color);
2521   gdk_color_free (pdata.visited_link_color);
2522
2523   return FALSE;
2524 }
2525
2526 static void
2527 gtk_label_ensure_has_tooltip (GtkLabel *label)
2528 {
2529   GtkLabelPrivate *priv = label->priv;
2530   GList *l;
2531   gboolean has_tooltip = FALSE;
2532
2533   for (l = priv->select_info->links; l; l = l->next)
2534     {
2535       GtkLabelLink *link = l->data;
2536       if (link->title)
2537         {
2538           has_tooltip = TRUE;
2539           break;
2540         }
2541     }
2542
2543   gtk_widget_set_has_tooltip (GTK_WIDGET (label), has_tooltip);
2544 }
2545
2546 static void
2547 gtk_label_set_markup_internal (GtkLabel    *label,
2548                                const gchar *str,
2549                                gboolean     with_uline)
2550 {
2551   GtkLabelPrivate *priv = label->priv;
2552   gchar *text = NULL;
2553   GError *error = NULL;
2554   PangoAttrList *attrs = NULL;
2555   gunichar accel_char = 0;
2556   gchar *new_str;
2557   GList *links = NULL;
2558
2559   if (!parse_uri_markup (label, str, &new_str, &links, &error))
2560     {
2561       g_warning ("Failed to set text from markup due to error parsing markup: %s",
2562                  error->message);
2563       g_error_free (error);
2564       return;
2565     }
2566
2567   if (links)
2568     {
2569       gtk_label_ensure_select_info (label);
2570       priv->select_info->links = g_list_reverse (links);
2571       gtk_label_ensure_has_tooltip (label);
2572     }
2573
2574   if (with_uline)
2575     {
2576       gboolean enable_mnemonics;
2577       gboolean auto_mnemonics;
2578
2579       g_object_get (gtk_widget_get_settings (GTK_WIDGET (label)),
2580                     "gtk-enable-mnemonics", &enable_mnemonics,
2581                     "gtk-auto-mnemonics", &auto_mnemonics,
2582                     NULL);
2583
2584       if (!(enable_mnemonics && priv->mnemonics_visible &&
2585             (!auto_mnemonics ||
2586              (gtk_widget_is_sensitive (GTK_WIDGET (label)) &&
2587               (!priv->mnemonic_widget ||
2588                gtk_widget_is_sensitive (priv->mnemonic_widget))))))
2589         {
2590           gchar *tmp;
2591           gchar *pattern;
2592           guint key;
2593
2594           if (separate_uline_pattern (new_str, &key, &tmp, &pattern))
2595             {
2596               g_free (new_str);
2597               new_str = tmp;
2598               g_free (pattern);
2599             }
2600         }
2601     }
2602
2603   if (!pango_parse_markup (new_str,
2604                            -1,
2605                            with_uline ? '_' : 0,
2606                            &attrs,
2607                            &text,
2608                            with_uline ? &accel_char : NULL,
2609                            &error))
2610     {
2611       g_warning ("Failed to set text from markup due to error parsing markup: %s",
2612                  error->message);
2613       g_free (new_str);
2614       g_error_free (error);
2615       return;
2616     }
2617
2618   g_free (new_str);
2619
2620   if (text)
2621     gtk_label_set_text_internal (label, text);
2622
2623   if (attrs)
2624     {
2625       if (priv->effective_attrs)
2626         pango_attr_list_unref (priv->effective_attrs);
2627       priv->effective_attrs = attrs;
2628     }
2629
2630   if (accel_char != 0)
2631     priv->mnemonic_keyval = gdk_keyval_to_lower (gdk_unicode_to_keyval (accel_char));
2632   else
2633     priv->mnemonic_keyval = GDK_KEY_VoidSymbol;
2634 }
2635
2636 /**
2637  * gtk_label_set_markup:
2638  * @label: a #GtkLabel
2639  * @str: a markup string (see <link linkend="PangoMarkupFormat">Pango markup format</link>)
2640  * 
2641  * Parses @str which is marked up with the <link
2642  * linkend="PangoMarkupFormat">Pango text markup language</link>, setting the
2643  * label's text and attribute list based on the parse results. If the @str is
2644  * external data, you may need to escape it with g_markup_escape_text() or
2645  * g_markup_printf_escaped()<!-- -->:
2646  * |[
2647  * char *markup;
2648  *
2649  * markup = g_markup_printf_escaped ("&lt;span style=\"italic\"&gt;&percnt;s&lt;/span&gt;", str);
2650  * gtk_label_set_markup (GTK_LABEL (label), markup);
2651  * g_free (markup);
2652  * ]|
2653  **/
2654 void
2655 gtk_label_set_markup (GtkLabel    *label,
2656                       const gchar *str)
2657 {
2658   g_return_if_fail (GTK_IS_LABEL (label));
2659
2660   g_object_freeze_notify (G_OBJECT (label));
2661
2662   gtk_label_set_label_internal (label, g_strdup (str ? str : ""));
2663   gtk_label_set_use_markup_internal (label, TRUE);
2664   gtk_label_set_use_underline_internal (label, FALSE);
2665
2666   gtk_label_recalculate (label);
2667
2668   g_object_thaw_notify (G_OBJECT (label));
2669 }
2670
2671 /**
2672  * gtk_label_set_markup_with_mnemonic:
2673  * @label: a #GtkLabel
2674  * @str: a markup string (see
2675  *     <link linkend="PangoMarkupFormat">Pango markup format</link>)
2676  *
2677  * Parses @str which is marked up with the
2678  * <link linkend="PangoMarkupFormat">Pango text markup language</link>,
2679  * setting the label's text and attribute list based on the parse results.
2680  * If characters in @str are preceded by an underscore, they are underlined
2681  * indicating that they represent a keyboard accelerator called a mnemonic.
2682  *
2683  * The mnemonic key can be used to activate another widget, chosen
2684  * automatically, or explicitly using gtk_label_set_mnemonic_widget().
2685  */
2686 void
2687 gtk_label_set_markup_with_mnemonic (GtkLabel    *label,
2688                                     const gchar *str)
2689 {
2690   g_return_if_fail (GTK_IS_LABEL (label));
2691
2692   g_object_freeze_notify (G_OBJECT (label));
2693
2694   gtk_label_set_label_internal (label, g_strdup (str ? str : ""));
2695   gtk_label_set_use_markup_internal (label, TRUE);
2696   gtk_label_set_use_underline_internal (label, TRUE);
2697
2698   gtk_label_recalculate (label);
2699
2700   g_object_thaw_notify (G_OBJECT (label));
2701 }
2702
2703 /**
2704  * gtk_label_get_text:
2705  * @label: a #GtkLabel
2706  * 
2707  * Fetches the text from a label widget, as displayed on the
2708  * screen. This does not include any embedded underlines
2709  * indicating mnemonics or Pango markup. (See gtk_label_get_label())
2710  * 
2711  * Return value: the text in the label widget. This is the internal
2712  *   string used by the label, and must not be modified.
2713  **/
2714 const gchar *
2715 gtk_label_get_text (GtkLabel *label)
2716 {
2717   g_return_val_if_fail (GTK_IS_LABEL (label), NULL);
2718
2719   return label->priv->text;
2720 }
2721
2722 static PangoAttrList *
2723 gtk_label_pattern_to_attrs (GtkLabel      *label,
2724                             const gchar   *pattern)
2725 {
2726   GtkLabelPrivate *priv = label->priv;
2727   const char *start;
2728   const char *p = priv->text;
2729   const char *q = pattern;
2730   PangoAttrList *attrs;
2731
2732   attrs = pango_attr_list_new ();
2733
2734   while (1)
2735     {
2736       while (*p && *q && *q != '_')
2737         {
2738           p = g_utf8_next_char (p);
2739           q++;
2740         }
2741       start = p;
2742       while (*p && *q && *q == '_')
2743         {
2744           p = g_utf8_next_char (p);
2745           q++;
2746         }
2747       
2748       if (p > start)
2749         {
2750           PangoAttribute *attr = pango_attr_underline_new (PANGO_UNDERLINE_LOW);
2751           attr->start_index = start - priv->text;
2752           attr->end_index = p - priv->text;
2753           
2754           pango_attr_list_insert (attrs, attr);
2755         }
2756       else
2757         break;
2758     }
2759
2760   return attrs;
2761 }
2762
2763 static void
2764 gtk_label_set_pattern_internal (GtkLabel    *label,
2765                                 const gchar *pattern,
2766                                 gboolean     is_mnemonic)
2767 {
2768   GtkLabelPrivate *priv = label->priv;
2769   PangoAttrList *attrs;
2770   gboolean enable_mnemonics;
2771   gboolean auto_mnemonics;
2772
2773   if (priv->pattern_set)
2774     return;
2775
2776   if (is_mnemonic)
2777     {
2778       g_object_get (gtk_widget_get_settings (GTK_WIDGET (label)),
2779                     "gtk-enable-mnemonics", &enable_mnemonics,
2780                     "gtk-auto-mnemonics", &auto_mnemonics,
2781                     NULL);
2782
2783       if (enable_mnemonics && priv->mnemonics_visible && pattern &&
2784           (!auto_mnemonics ||
2785            (gtk_widget_is_sensitive (GTK_WIDGET (label)) &&
2786             (!priv->mnemonic_widget ||
2787              gtk_widget_is_sensitive (priv->mnemonic_widget)))))
2788         attrs = gtk_label_pattern_to_attrs (label, pattern);
2789       else
2790         attrs = NULL;
2791     }
2792   else
2793     attrs = gtk_label_pattern_to_attrs (label, pattern);
2794
2795   if (priv->effective_attrs)
2796     pango_attr_list_unref (priv->effective_attrs);
2797   priv->effective_attrs = attrs;
2798 }
2799
2800 /**
2801  * gtk_label_set_pattern:
2802  * @label: The #GtkLabel you want to set the pattern to.
2803  * @pattern: The pattern as described above.
2804  *
2805  * The pattern of underlines you want under the existing text within the
2806  * #GtkLabel widget.  For example if the current text of the label says
2807  * "FooBarBaz" passing a pattern of "___   ___" will underline
2808  * "Foo" and "Baz" but not "Bar".
2809  */
2810 void
2811 gtk_label_set_pattern (GtkLabel    *label,
2812                        const gchar *pattern)
2813 {
2814   GtkLabelPrivate *priv;
2815
2816   g_return_if_fail (GTK_IS_LABEL (label));
2817
2818   priv = label->priv;
2819
2820   priv->pattern_set = FALSE;
2821
2822   if (pattern)
2823     {
2824       gtk_label_set_pattern_internal (label, pattern, FALSE);
2825       priv->pattern_set = TRUE;
2826     }
2827   else
2828     gtk_label_recalculate (label);
2829
2830   gtk_label_clear_layout (label);
2831   gtk_widget_queue_resize (GTK_WIDGET (label));
2832 }
2833
2834
2835 /**
2836  * gtk_label_set_justify:
2837  * @label: a #GtkLabel
2838  * @jtype: a #GtkJustification
2839  *
2840  * Sets the alignment of the lines in the text of the label relative to
2841  * each other. %GTK_JUSTIFY_LEFT is the default value when the
2842  * widget is first created with gtk_label_new(). If you instead want
2843  * to set the alignment of the label as a whole, use
2844  * gtk_misc_set_alignment() instead. gtk_label_set_justify() has no
2845  * effect on labels containing only a single line.
2846  **/
2847 void
2848 gtk_label_set_justify (GtkLabel        *label,
2849                        GtkJustification jtype)
2850 {
2851   GtkLabelPrivate *priv;
2852
2853   g_return_if_fail (GTK_IS_LABEL (label));
2854   g_return_if_fail (jtype >= GTK_JUSTIFY_LEFT && jtype <= GTK_JUSTIFY_FILL);
2855
2856   priv = label->priv;
2857
2858   if ((GtkJustification) priv->jtype != jtype)
2859     {
2860       priv->jtype = jtype;
2861
2862       /* No real need to be this drastic, but easier than duplicating the code */
2863       gtk_label_clear_layout (label);
2864       
2865       g_object_notify (G_OBJECT (label), "justify");
2866       gtk_widget_queue_resize (GTK_WIDGET (label));
2867     }
2868 }
2869
2870 /**
2871  * gtk_label_get_justify:
2872  * @label: a #GtkLabel
2873  *
2874  * Returns the justification of the label. See gtk_label_set_justify().
2875  *
2876  * Return value: #GtkJustification
2877  **/
2878 GtkJustification
2879 gtk_label_get_justify (GtkLabel *label)
2880 {
2881   g_return_val_if_fail (GTK_IS_LABEL (label), 0);
2882
2883   return label->priv->jtype;
2884 }
2885
2886 /**
2887  * gtk_label_set_ellipsize:
2888  * @label: a #GtkLabel
2889  * @mode: a #PangoEllipsizeMode
2890  *
2891  * Sets the mode used to ellipsize (add an ellipsis: "...") to the text 
2892  * if there is not enough space to render the entire string.
2893  *
2894  * Since: 2.6
2895  **/
2896 void
2897 gtk_label_set_ellipsize (GtkLabel          *label,
2898                          PangoEllipsizeMode mode)
2899 {
2900   GtkLabelPrivate *priv;
2901
2902   g_return_if_fail (GTK_IS_LABEL (label));
2903   g_return_if_fail (mode >= PANGO_ELLIPSIZE_NONE && mode <= PANGO_ELLIPSIZE_END);
2904
2905   priv = label->priv;
2906
2907   if ((PangoEllipsizeMode) priv->ellipsize != mode)
2908     {
2909       priv->ellipsize = mode;
2910
2911       /* No real need to be this drastic, but easier than duplicating the code */
2912       gtk_label_clear_layout (label);
2913       
2914       g_object_notify (G_OBJECT (label), "ellipsize");
2915       gtk_widget_queue_resize (GTK_WIDGET (label));
2916     }
2917 }
2918
2919 /**
2920  * gtk_label_get_ellipsize:
2921  * @label: a #GtkLabel
2922  *
2923  * Returns the ellipsizing position of the label. See gtk_label_set_ellipsize().
2924  *
2925  * Return value: #PangoEllipsizeMode
2926  *
2927  * Since: 2.6
2928  **/
2929 PangoEllipsizeMode
2930 gtk_label_get_ellipsize (GtkLabel *label)
2931 {
2932   g_return_val_if_fail (GTK_IS_LABEL (label), PANGO_ELLIPSIZE_NONE);
2933
2934   return label->priv->ellipsize;
2935 }
2936
2937 /**
2938  * gtk_label_set_width_chars:
2939  * @label: a #GtkLabel
2940  * @n_chars: the new desired width, in characters.
2941  * 
2942  * Sets the desired width in characters of @label to @n_chars.
2943  * 
2944  * Since: 2.6
2945  **/
2946 void
2947 gtk_label_set_width_chars (GtkLabel *label,
2948                            gint      n_chars)
2949 {
2950   GtkLabelPrivate *priv;
2951
2952   g_return_if_fail (GTK_IS_LABEL (label));
2953
2954   priv = label->priv;
2955
2956   if (priv->width_chars != n_chars)
2957     {
2958       priv->width_chars = n_chars;
2959       g_object_notify (G_OBJECT (label), "width-chars");
2960       gtk_widget_queue_resize (GTK_WIDGET (label));
2961     }
2962 }
2963
2964 /**
2965  * gtk_label_get_width_chars:
2966  * @label: a #GtkLabel
2967  * 
2968  * Retrieves the desired width of @label, in characters. See
2969  * gtk_label_set_width_chars().
2970  * 
2971  * Return value: the width of the label in characters.
2972  * 
2973  * Since: 2.6
2974  **/
2975 gint
2976 gtk_label_get_width_chars (GtkLabel *label)
2977 {
2978   g_return_val_if_fail (GTK_IS_LABEL (label), -1);
2979
2980   return label->priv->width_chars;
2981 }
2982
2983 /**
2984  * gtk_label_set_max_width_chars:
2985  * @label: a #GtkLabel
2986  * @n_chars: the new desired maximum width, in characters.
2987  * 
2988  * Sets the desired maximum width in characters of @label to @n_chars.
2989  * 
2990  * Since: 2.6
2991  **/
2992 void
2993 gtk_label_set_max_width_chars (GtkLabel *label,
2994                                gint      n_chars)
2995 {
2996   GtkLabelPrivate *priv;
2997
2998   g_return_if_fail (GTK_IS_LABEL (label));
2999
3000   priv = label->priv;
3001
3002   if (priv->max_width_chars != n_chars)
3003     {
3004       priv->max_width_chars = n_chars;
3005
3006       g_object_notify (G_OBJECT (label), "max-width-chars");
3007       gtk_widget_queue_resize (GTK_WIDGET (label));
3008     }
3009 }
3010
3011 /**
3012  * gtk_label_get_max_width_chars:
3013  * @label: a #GtkLabel
3014  * 
3015  * Retrieves the desired maximum width of @label, in characters. See
3016  * gtk_label_set_width_chars().
3017  * 
3018  * Return value: the maximum width of the label in characters.
3019  * 
3020  * Since: 2.6
3021  **/
3022 gint
3023 gtk_label_get_max_width_chars (GtkLabel *label)
3024 {
3025   g_return_val_if_fail (GTK_IS_LABEL (label), -1);
3026
3027   return label->priv->max_width_chars;
3028 }
3029
3030 /**
3031  * gtk_label_set_line_wrap:
3032  * @label: a #GtkLabel
3033  * @wrap: the setting
3034  *
3035  * Toggles line wrapping within the #GtkLabel widget. %TRUE makes it break
3036  * lines if text exceeds the widget's size. %FALSE lets the text get cut off
3037  * by the edge of the widget if it exceeds the widget size.
3038  *
3039  * Note that setting line wrapping to %TRUE does not make the label
3040  * wrap at its parent container's width, because GTK+ widgets
3041  * conceptually can't make their requisition depend on the parent
3042  * container's size. For a label that wraps at a specific position,
3043  * set the label's width using gtk_widget_set_size_request().
3044  **/
3045 void
3046 gtk_label_set_line_wrap (GtkLabel *label,
3047                          gboolean  wrap)
3048 {
3049   GtkLabelPrivate *priv;
3050
3051   g_return_if_fail (GTK_IS_LABEL (label));
3052
3053   priv = label->priv;
3054
3055   wrap = wrap != FALSE;
3056
3057   if (priv->wrap != wrap)
3058     {
3059       priv->wrap = wrap;
3060
3061       gtk_label_clear_layout (label);
3062       gtk_widget_queue_resize (GTK_WIDGET (label));
3063       g_object_notify (G_OBJECT (label), "wrap");
3064     }
3065 }
3066
3067 /**
3068  * gtk_label_get_line_wrap:
3069  * @label: a #GtkLabel
3070  *
3071  * Returns whether lines in the label are automatically wrapped. 
3072  * See gtk_label_set_line_wrap().
3073  *
3074  * Return value: %TRUE if the lines of the label are automatically wrapped.
3075  */
3076 gboolean
3077 gtk_label_get_line_wrap (GtkLabel *label)
3078 {
3079   g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
3080
3081   return label->priv->wrap;
3082 }
3083
3084 /**
3085  * gtk_label_set_line_wrap_mode:
3086  * @label: a #GtkLabel
3087  * @wrap_mode: the line wrapping mode
3088  *
3089  * If line wrapping is on (see gtk_label_set_line_wrap()) this controls how
3090  * the line wrapping is done. The default is %PANGO_WRAP_WORD which means
3091  * wrap on word boundaries.
3092  *
3093  * Since: 2.10
3094  **/
3095 void
3096 gtk_label_set_line_wrap_mode (GtkLabel *label,
3097                               PangoWrapMode wrap_mode)
3098 {
3099   GtkLabelPrivate *priv;
3100
3101   g_return_if_fail (GTK_IS_LABEL (label));
3102
3103   priv = label->priv;
3104
3105   if (priv->wrap_mode != wrap_mode)
3106     {
3107       priv->wrap_mode = wrap_mode;
3108       g_object_notify (G_OBJECT (label), "wrap-mode");
3109       
3110       gtk_widget_queue_resize (GTK_WIDGET (label));
3111     }
3112 }
3113
3114 /**
3115  * gtk_label_get_line_wrap_mode:
3116  * @label: a #GtkLabel
3117  *
3118  * Returns line wrap mode used by the label. See gtk_label_set_line_wrap_mode().
3119  *
3120  * Return value: %TRUE if the lines of the label are automatically wrapped.
3121  *
3122  * Since: 2.10
3123  */
3124 PangoWrapMode
3125 gtk_label_get_line_wrap_mode (GtkLabel *label)
3126 {
3127   g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
3128
3129   return label->priv->wrap_mode;
3130 }
3131
3132 static void
3133 gtk_label_destroy (GtkWidget *widget)
3134 {
3135   GtkLabel *label = GTK_LABEL (widget);
3136
3137   gtk_label_set_mnemonic_widget (label, NULL);
3138
3139   GTK_WIDGET_CLASS (gtk_label_parent_class)->destroy (widget);
3140 }
3141
3142 static void
3143 gtk_label_finalize (GObject *object)
3144 {
3145   GtkLabel *label = GTK_LABEL (object);
3146   GtkLabelPrivate *priv = label->priv;
3147
3148   g_free (priv->label);
3149   g_free (priv->text);
3150
3151   if (priv->layout)
3152     g_object_unref (priv->layout);
3153
3154   if (priv->attrs)
3155     pango_attr_list_unref (priv->attrs);
3156
3157   if (priv->effective_attrs)
3158     pango_attr_list_unref (priv->effective_attrs);
3159
3160   gtk_label_clear_links (label);
3161   g_free (priv->select_info);
3162
3163   G_OBJECT_CLASS (gtk_label_parent_class)->finalize (object);
3164 }
3165
3166 static void
3167 gtk_label_clear_layout (GtkLabel *label)
3168 {
3169   GtkLabelPrivate *priv = label->priv;
3170
3171   if (priv->layout)
3172     {
3173       g_object_unref (priv->layout);
3174       priv->layout = NULL;
3175     }
3176 }
3177
3178 static PangoFontMetrics *
3179 get_font_metrics (PangoContext *context, GtkWidget *widget)
3180 {
3181   GtkStyleContext *style_context;
3182   const PangoFontDescription *font;
3183   PangoFontMetrics *retval;
3184
3185   style_context = gtk_widget_get_style_context (widget);
3186   font = gtk_style_context_get_font (style_context, GTK_STATE_FLAG_NORMAL);
3187
3188   retval = pango_context_get_metrics (context,
3189                                       font,
3190                                       pango_context_get_language (context));
3191
3192   return retval;
3193 }
3194
3195 /**
3196  * gtk_label_get_measuring_layout:
3197  * @label: the label
3198  * @existing_layout: %NULL or an existing layout already in use.
3199  * @width: the width to measure with in pango units, or -1 for infinite
3200  * @height: the height to measure with in pango units, or -1 for infinite
3201  *
3202  * Gets a layout that can be used for measuring sizes. The returned
3203  * layout will be identical to the label's layout except for the
3204  * layout's width, which will be set to @width. Do not modify the returned
3205  * layout.
3206  *
3207  * Returns: a new reference to a pango layout
3208  **/
3209 static PangoLayout *
3210 gtk_label_get_measuring_layout (GtkLabel *   label,
3211                                 PangoLayout *existing_layout,
3212                                 int          width,
3213                                 int          height)
3214 {
3215   GtkLabelPrivate *priv = label->priv;
3216   PangoRectangle rect;
3217   PangoLayout *copy;
3218
3219   if (existing_layout != NULL)
3220     {
3221       if (existing_layout != priv->layout)
3222         {
3223           pango_layout_set_width (existing_layout, width);
3224           pango_layout_set_height (existing_layout, height);
3225           return existing_layout;
3226         }
3227
3228       g_object_unref (existing_layout);
3229     }
3230
3231   gtk_label_ensure_layout (label);
3232
3233   if (pango_layout_get_width (priv->layout) == width &&
3234       pango_layout_get_height (priv->layout) == height)
3235     {
3236       g_object_ref (priv->layout);
3237       return priv->layout;
3238     }
3239
3240   /* We can use the label's own layout if we're not allocated a size yet,
3241    * because we don't need it to be properly setup at that point.
3242    * This way we can make use of caching upon the label's creation.
3243    */
3244   if (gtk_widget_get_allocated_width (GTK_WIDGET (label)) <= 1)
3245     {
3246       g_object_ref (priv->layout);
3247       pango_layout_set_width (priv->layout, width);
3248       pango_layout_set_height (priv->layout, height);
3249       return priv->layout;
3250     }
3251
3252   /* oftentimes we want to measure a width that is far wider than the current width,
3253    * even though the layout would not change if we made it wider. In that case, we
3254    * can just return the current layout, because for measuring purposes, it will be
3255    * identical.
3256    */
3257   pango_layout_get_extents (priv->layout, NULL, &rect);
3258   if ((width == -1 || rect.width <= width) &&
3259       (height == -1 || rect.height <= height) &&
3260       !pango_layout_is_wrapped (priv->layout) &&
3261       !pango_layout_is_ellipsized (priv->layout))
3262     {
3263       g_object_ref (priv->layout);
3264       return priv->layout;
3265     }
3266
3267   copy = pango_layout_copy (priv->layout);
3268   pango_layout_set_width (copy, width);
3269   pango_layout_set_height (copy, height);
3270   return copy;
3271 }
3272
3273 static void
3274 gtk_label_update_layout_width (GtkLabel *label)
3275 {
3276   GtkLabelPrivate *priv = label->priv;
3277   GtkWidget *widget = GTK_WIDGET (label);
3278
3279   g_assert (priv->layout);
3280
3281   if (priv->ellipsize || priv->wrap)
3282     {
3283       PangoRectangle logical;
3284       gint xpad, ypad;
3285       gint width, height;
3286
3287       gtk_misc_get_padding (GTK_MISC (label), &xpad, &ypad);
3288
3289       width = gtk_widget_get_allocated_width (GTK_WIDGET (label)) - xpad * 2;
3290       height = gtk_widget_get_allocated_height (GTK_WIDGET (label)) - ypad * 2;
3291
3292       if (priv->have_transform)
3293         {
3294           PangoContext *context = gtk_widget_get_pango_context (widget);
3295           const PangoMatrix *matrix = pango_context_get_matrix (context);
3296           const gdouble dx = matrix->xx; /* cos (M_PI * angle / 180) */
3297           const gdouble dy = matrix->xy; /* sin (M_PI * angle / 180) */
3298
3299           pango_layout_set_width (priv->layout, -1);
3300           pango_layout_set_height (priv->layout, -1);
3301           pango_layout_get_pixel_extents (priv->layout, NULL, &logical);
3302
3303           if (fabs (dy) < 0.01)
3304             {
3305               if (logical.width > width)
3306                 pango_layout_set_width (priv->layout, width * PANGO_SCALE);
3307             }
3308           else if (fabs (dx) < 0.01)
3309             {
3310               if (logical.width > height)
3311                 pango_layout_set_width (priv->layout, height * PANGO_SCALE);
3312             }
3313           else
3314             {
3315               gdouble x0, y0, x1, y1, length;
3316               gboolean vertical;
3317               gint cy;
3318
3319               x0 = width / 2;
3320               y0 = dx ? x0 * dy / dx : G_MAXDOUBLE;
3321               vertical = fabs (y0) > height / 2;
3322
3323               if (vertical)
3324                 {
3325                   y0 = height/2;
3326                   x0 = dy ? y0 * dx / dy : G_MAXDOUBLE;
3327                 }
3328
3329               length = 2 * sqrt (x0 * x0 + y0 * y0);
3330               pango_layout_set_width (priv->layout, rint (length * PANGO_SCALE));
3331               pango_layout_get_pixel_size (priv->layout, NULL, &cy);
3332
3333               x1 = +dy * cy/2;
3334               y1 = -dx * cy/2;
3335
3336               if (vertical)
3337                 {
3338                   y0 = height/2 + y1 - y0;
3339                   x0 = -y0 * dx/dy;
3340                 }
3341               else
3342                 {
3343                   x0 = width/2 + x1 - x0;
3344                   y0 = -x0 * dy/dx;
3345                 }
3346
3347               length = length - sqrt (x0 * x0 + y0 * y0) * 2;
3348               pango_layout_set_width (priv->layout, rint (length * PANGO_SCALE));
3349             }
3350         }
3351       else
3352         {
3353           pango_layout_set_width (priv->layout, width * PANGO_SCALE);
3354           pango_layout_set_height (priv->layout, priv->ellipsize ? height * PANGO_SCALE : -1);
3355         }
3356     }
3357   else
3358     {
3359       pango_layout_set_width (priv->layout, -1);
3360       pango_layout_set_height (priv->layout, -1);
3361     }
3362 }
3363
3364 static void
3365 gtk_label_ensure_layout (GtkLabel *label)
3366 {
3367   GtkLabelPrivate *priv = label->priv;
3368   GtkWidget *widget;
3369   gboolean rtl;
3370
3371   widget = GTK_WIDGET (label);
3372
3373   rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
3374
3375   if (!priv->layout)
3376     {
3377       PangoAlignment align = PANGO_ALIGN_LEFT; /* Quiet gcc */
3378       gdouble angle = gtk_label_get_angle (label);
3379
3380       if (angle != 0.0 && !priv->select_info)
3381         {
3382           PangoMatrix matrix = PANGO_MATRIX_INIT;
3383
3384           /* We rotate the standard singleton PangoContext for the widget,
3385            * depending on the fact that it's meant pretty much exclusively
3386            * for our use.
3387            */
3388           pango_matrix_rotate (&matrix, angle);
3389
3390           pango_context_set_matrix (gtk_widget_get_pango_context (widget), &matrix);
3391
3392           priv->have_transform = TRUE;
3393         }
3394       else
3395         {
3396           if (priv->have_transform)
3397             pango_context_set_matrix (gtk_widget_get_pango_context (widget), NULL);
3398
3399           priv->have_transform = FALSE;
3400         }
3401
3402       priv->layout = gtk_widget_create_pango_layout (widget, priv->text);
3403
3404       if (priv->effective_attrs)
3405         pango_layout_set_attributes (priv->layout, priv->effective_attrs);
3406
3407       switch (priv->jtype)
3408         {
3409         case GTK_JUSTIFY_LEFT:
3410           align = rtl ? PANGO_ALIGN_RIGHT : PANGO_ALIGN_LEFT;
3411           break;
3412         case GTK_JUSTIFY_RIGHT:
3413           align = rtl ? PANGO_ALIGN_LEFT : PANGO_ALIGN_RIGHT;
3414           break;
3415         case GTK_JUSTIFY_CENTER:
3416           align = PANGO_ALIGN_CENTER;
3417           break;
3418         case GTK_JUSTIFY_FILL:
3419           align = rtl ? PANGO_ALIGN_RIGHT : PANGO_ALIGN_LEFT;
3420           pango_layout_set_justify (priv->layout, TRUE);
3421           break;
3422         default:
3423           g_assert_not_reached();
3424         }
3425
3426       pango_layout_set_alignment (priv->layout, align);
3427       pango_layout_set_ellipsize (priv->layout, priv->ellipsize);
3428       pango_layout_set_wrap (priv->layout, priv->wrap_mode);
3429       pango_layout_set_single_paragraph_mode (priv->layout, priv->single_line_mode);
3430
3431       gtk_label_update_layout_width (label);
3432     }
3433 }
3434
3435 static gint
3436 get_single_line_height (GtkWidget   *widget,
3437                         PangoLayout *layout)
3438 {
3439   PangoContext *context;
3440   PangoFontMetrics *metrics;
3441   gint ascent, descent;
3442
3443   context = pango_layout_get_context (layout);
3444   metrics = get_font_metrics (context, widget);
3445   ascent = pango_font_metrics_get_ascent (metrics);
3446   descent = pango_font_metrics_get_descent (metrics);
3447   pango_font_metrics_unref (metrics);
3448
3449   return ascent + descent;
3450 }
3451
3452 static GtkSizeRequestMode
3453 gtk_label_get_request_mode (GtkWidget *widget)
3454 {
3455   GtkLabel *label = GTK_LABEL (widget);
3456   gdouble   angle = gtk_label_get_angle (label);
3457
3458   if (label->priv->wrap)
3459     return (angle == 90 || angle == 270) ?
3460       GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT : 
3461       GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH;
3462
3463     return GTK_SIZE_REQUEST_CONSTANT_SIZE;
3464 }
3465
3466 static void
3467 get_size_for_allocation (GtkLabel        *label,
3468                          GtkOrientation   orientation,
3469                          gint             allocation,
3470                          gint            *minimum_size,
3471                          gint            *natural_size)
3472 {
3473   GtkLabelPrivate *priv = label->priv;
3474   PangoLayout *layout;
3475   gint text_height;
3476
3477   layout = gtk_label_get_measuring_layout (label, NULL, allocation * PANGO_SCALE, -1);
3478
3479   pango_layout_get_pixel_size (layout, NULL, &text_height);
3480
3481   if (minimum_size)
3482     *minimum_size = text_height;
3483
3484   if (natural_size)
3485     {
3486       if (priv->ellipsize && priv->wrap)
3487         {
3488           layout = gtk_label_get_measuring_layout (label, layout, allocation * PANGO_SCALE, G_MAXINT);
3489           pango_layout_get_pixel_size (layout, NULL, &text_height);
3490         }
3491
3492       *natural_size = text_height;
3493     }
3494
3495   g_object_unref (layout);
3496 }
3497
3498 static gint
3499 get_char_pixels (GtkWidget   *label,
3500                  PangoLayout *layout)
3501 {
3502   PangoContext *context;
3503   PangoFontMetrics *metrics;
3504   gint char_width, digit_width;
3505
3506   context = pango_layout_get_context (layout);
3507   metrics = get_font_metrics (context, GTK_WIDGET (label));
3508   char_width = pango_font_metrics_get_approximate_char_width (metrics);
3509   digit_width = pango_font_metrics_get_approximate_digit_width (metrics);
3510   pango_font_metrics_unref (metrics);
3511
3512   return MAX (char_width, digit_width);;
3513 }
3514
3515 static void
3516 gtk_label_get_preferred_layout_size (GtkLabel *label,
3517                                      PangoRectangle *required,
3518                                      PangoRectangle *natural)
3519 {
3520   GtkLabelPrivate *priv = label->priv;
3521   PangoLayout *layout;
3522
3523   /* "width-chars" Hard-coded minimum width:
3524    *    - minimum size should be MAX (width-chars, strlen ("..."));
3525    *    - natural size should be MAX (width-chars, strlen (priv->text));
3526    *
3527    * "max-width-chars" User specified maximum size requisition
3528    *    - minimum size should be MAX (width-chars, 0)
3529    *    - natural size should be MIN (max-width-chars, strlen (priv->text))
3530    *
3531    *    For ellipsizing labels; if max-width-chars is specified: either it is used as 
3532    *    a minimum size or the label text as a minimum size (natural size still overflows).
3533    *
3534    *    For wrapping labels; A reasonable minimum size is useful to naturally layout
3535    *    interfaces automatically. In this case if no "width-chars" is specified, the minimum
3536    *    width will default to the wrap guess that gtk_label_ensure_layout() does.
3537    */
3538
3539   /* Start off with the pixel extents of an as-wide-as-possible layout */
3540   layout = gtk_label_get_measuring_layout (label, NULL, -1, -1);
3541
3542   pango_layout_get_extents (layout, NULL, natural);
3543   natural->x = natural->y = 0;
3544
3545   if (priv->wrap)
3546     natural->height = get_single_line_height (GTK_WIDGET (label), layout);
3547
3548   if (priv->ellipsize || priv->wrap)
3549     {
3550       /* a layout with width 0 will be as small as humanly possible */
3551       layout = gtk_label_get_measuring_layout (label, layout, 0, -1);
3552
3553       pango_layout_get_extents (layout, NULL, required);
3554
3555       /* can happen when Pango decides to ellipsize text */
3556       if (required->width > natural->width)
3557         required->width = natural->width;
3558
3559       required->x = required->y = 0;
3560       required->height = natural->height;
3561     }
3562   else
3563     {
3564       *required = *natural;
3565     }
3566
3567   if (priv->width_chars > -1 || priv->max_width_chars > -1)
3568     {
3569       gint char_pixels;
3570
3571       char_pixels = get_char_pixels (GTK_WIDGET (label), layout);
3572       
3573       if (priv->width_chars > -1)
3574         required->width = MAX (required->width, char_pixels * priv->width_chars);
3575
3576       if (priv->max_width_chars > -1)
3577         natural->width = MIN (natural->width, priv->max_width_chars * char_pixels);
3578       natural->width = MAX (natural->width, required->width);
3579     }
3580
3581   g_object_unref (layout);
3582 }
3583
3584 static void
3585 gtk_label_get_preferred_size (GtkWidget      *widget,
3586                               GtkOrientation  orientation,
3587                               gint           *minimum_size,
3588                               gint           *natural_size)
3589 {
3590   GtkLabel      *label = GTK_LABEL (widget);
3591   GtkLabelPrivate  *priv = label->priv;
3592   PangoRectangle required_rect;
3593   PangoRectangle natural_rect;
3594   gint           xpad, ypad;
3595
3596   gtk_label_get_preferred_layout_size (label, &required_rect, &natural_rect);
3597
3598   /* Now that we have minimum and natural sizes in pango extents, apply a possible transform */
3599   if (priv->have_transform)
3600     {
3601       PangoLayout *copy;
3602       PangoContext *context;
3603       const PangoMatrix *matrix;
3604
3605       copy = pango_layout_copy (priv->layout);
3606       context = pango_layout_get_context (copy);
3607       matrix = pango_context_get_matrix (context);
3608
3609       pango_layout_set_width (copy, -1);
3610       pango_layout_set_ellipsize (copy, PANGO_ELLIPSIZE_NONE);
3611
3612       pango_layout_get_extents (copy, NULL, &natural_rect);
3613       g_object_unref (copy);
3614
3615       pango_matrix_transform_rectangle (matrix, &required_rect);
3616       pango_matrix_transform_rectangle (matrix, &natural_rect);
3617
3618       /* Bump the natural size in case of ellipsize to ensure pango has
3619        * enough space in the angles (note, we could alternatively set the
3620        * layout to not ellipsize when we know we have been allocated our
3621        * full natural size, or it may be that pango needs a fix here).
3622        */
3623       if (priv->ellipsize && priv->angle != 0 && priv->angle != 90 && 
3624           priv->angle != 180 && priv->angle != 270 && priv->angle != 360)
3625         {
3626           /* For some reason we only need this at about 110 degrees, and only
3627            * when gaining in height
3628            */
3629           natural_rect.height += ROTATION_ELLIPSIZE_PADDING * 2 * PANGO_SCALE;
3630           natural_rect.width  += ROTATION_ELLIPSIZE_PADDING * 2 * PANGO_SCALE;
3631         }
3632     }
3633
3634   required_rect.width  = PANGO_PIXELS_CEIL (required_rect.width);
3635   required_rect.height = PANGO_PIXELS_CEIL (required_rect.height);
3636
3637   natural_rect.width  = PANGO_PIXELS_CEIL (natural_rect.width);
3638   natural_rect.height = PANGO_PIXELS_CEIL (natural_rect.height);
3639
3640   gtk_misc_get_padding (GTK_MISC (label), &xpad, &ypad);
3641
3642   if (orientation == GTK_ORIENTATION_HORIZONTAL)
3643     {
3644       /* Note, we cant use get_size_for_allocation() when rotating
3645        * ellipsized labels.
3646        */
3647       if (!(priv->ellipsize && priv->have_transform) &&
3648           (priv->angle == 90 || priv->angle == 270))
3649         {
3650           /* Doing a h4w request on a rotated label here, return the
3651            * required width for the minimum height.
3652            */
3653           get_size_for_allocation (label,
3654                                    GTK_ORIENTATION_VERTICAL,
3655                                    required_rect.height,
3656                                    minimum_size, natural_size);
3657
3658         }
3659       else
3660         {
3661           /* Normal desired width */
3662           *minimum_size = required_rect.width;
3663           *natural_size = natural_rect.width;
3664         }
3665
3666       *minimum_size += xpad * 2;
3667       *natural_size += xpad * 2;
3668     }
3669   else /* GTK_ORIENTATION_VERTICAL */
3670     {
3671       /* Note, we cant use get_size_for_allocation() when rotating
3672        * ellipsized labels.
3673        */
3674       if (!(priv->ellipsize && priv->have_transform) &&
3675           (priv->angle == 0 || priv->angle == 180 || priv->angle == 360))
3676         {
3677           /* Doing a w4h request on a label here, return the required
3678            * height for the minimum width.
3679            */
3680           get_size_for_allocation (label,
3681                                    GTK_ORIENTATION_HORIZONTAL,
3682                                    required_rect.width,
3683                                    minimum_size, natural_size);
3684         }
3685       else
3686         {
3687           /* A vertically rotated label does w4h, so return the base
3688            * desired height (text length)
3689            */
3690           *minimum_size = required_rect.height;
3691           *natural_size = natural_rect.height;
3692         }
3693
3694       *minimum_size += ypad * 2;
3695       *natural_size += ypad * 2;
3696     }
3697 }
3698
3699
3700 static void
3701 gtk_label_get_preferred_width (GtkWidget *widget,
3702                                gint      *minimum_size,
3703                                gint      *natural_size)
3704 {
3705   gtk_label_get_preferred_size (widget, GTK_ORIENTATION_HORIZONTAL, minimum_size, natural_size);
3706 }
3707
3708 static void
3709 gtk_label_get_preferred_height (GtkWidget *widget,
3710                                 gint      *minimum_size,
3711                                 gint      *natural_size)
3712 {
3713   gtk_label_get_preferred_size (widget, GTK_ORIENTATION_VERTICAL, minimum_size, natural_size);
3714 }
3715
3716 static void
3717 gtk_label_get_preferred_width_for_height (GtkWidget *widget,
3718                                           gint       height,
3719                                           gint      *minimum_width,
3720                                           gint      *natural_width)
3721 {
3722   GtkLabel *label = GTK_LABEL (widget);
3723   GtkLabelPrivate *priv = label->priv;
3724
3725   if (priv->wrap && (priv->angle == 90 || priv->angle == 270))
3726     {
3727       gint xpad, ypad;
3728
3729       gtk_misc_get_padding (GTK_MISC (label), &xpad, &ypad);
3730
3731       if (priv->wrap)
3732         gtk_label_clear_layout (label);
3733
3734       get_size_for_allocation (label, GTK_ORIENTATION_VERTICAL,
3735                                MAX (1, height - (ypad * 2)),
3736                                minimum_width, natural_width);
3737
3738       if (minimum_width)
3739         *minimum_width += xpad * 2;
3740
3741       if (natural_width)
3742         *natural_width += xpad * 2;
3743     }
3744   else
3745     GTK_WIDGET_GET_CLASS (widget)->get_preferred_width (widget, minimum_width, natural_width);
3746 }
3747
3748 static void
3749 gtk_label_get_preferred_height_for_width (GtkWidget *widget,
3750                                           gint       width,
3751                                           gint      *minimum_height,
3752                                           gint      *natural_height)
3753 {
3754   GtkLabel *label = GTK_LABEL (widget);
3755   GtkLabelPrivate *priv = label->priv;
3756
3757   if (priv->wrap && (priv->angle == 0 || priv->angle == 180 || priv->angle == 360))
3758     {
3759       gint xpad, ypad;
3760
3761       gtk_misc_get_padding (GTK_MISC (label), &xpad, &ypad);
3762
3763       if (priv->wrap)
3764         gtk_label_clear_layout (label);
3765
3766       get_size_for_allocation (label, GTK_ORIENTATION_HORIZONTAL,
3767                                MAX (1, width - xpad * 2),
3768                                minimum_height, natural_height);
3769
3770       if (minimum_height)
3771         *minimum_height += ypad * 2;
3772
3773       if (natural_height)
3774         *natural_height += ypad * 2;
3775     }
3776   else
3777     GTK_WIDGET_GET_CLASS (widget)->get_preferred_height (widget, minimum_height, natural_height);
3778 }
3779
3780 static void
3781 gtk_label_size_allocate (GtkWidget     *widget,
3782                          GtkAllocation *allocation)
3783 {
3784   GtkLabel *label = GTK_LABEL (widget);
3785   GtkLabelPrivate *priv = label->priv;
3786
3787   GTK_WIDGET_CLASS (gtk_label_parent_class)->size_allocate (widget, allocation);
3788
3789   if (priv->layout)
3790     gtk_label_update_layout_width (label);
3791
3792   if (priv->select_info && priv->select_info->window)
3793     {
3794       gdk_window_move_resize (priv->select_info->window,
3795                               allocation->x,
3796                               allocation->y,
3797                               allocation->width,
3798                               allocation->height);
3799     }
3800 }
3801
3802 static void
3803 gtk_label_update_cursor (GtkLabel *label)
3804 {
3805   GtkLabelPrivate *priv = label->priv;
3806   GtkWidget *widget;
3807
3808   if (!priv->select_info)
3809     return;
3810
3811   widget = GTK_WIDGET (label);
3812
3813   if (gtk_widget_get_realized (widget))
3814     {
3815       GdkDisplay *display;
3816       GdkCursor *cursor;
3817
3818       if (gtk_widget_is_sensitive (widget))
3819         {
3820           display = gtk_widget_get_display (widget);
3821
3822           if (priv->select_info->active_link)
3823             cursor = gdk_cursor_new_for_display (display, GDK_HAND2);
3824           else if (priv->select_info->selectable)
3825             cursor = gdk_cursor_new_for_display (display, GDK_XTERM);
3826           else
3827             cursor = NULL;
3828         }
3829       else
3830         cursor = NULL;
3831
3832       gdk_window_set_cursor (priv->select_info->window, cursor);
3833
3834       if (cursor)
3835         g_object_unref (cursor);
3836     }
3837 }
3838
3839 static void
3840 gtk_label_state_flags_changed (GtkWidget     *widget,
3841                                GtkStateFlags  prev_state)
3842 {
3843   GtkLabel *label = GTK_LABEL (widget);
3844   GtkLabelPrivate *priv = label->priv;
3845
3846   if (priv->select_info)
3847     {
3848       if (!gtk_widget_is_sensitive (widget))
3849         gtk_label_select_region (label, 0, 0);
3850
3851       gtk_label_update_cursor (label);
3852     }
3853
3854   /* We have to clear the layout, fonts etc. may have changed */
3855   gtk_label_clear_layout (label);
3856
3857   if (GTK_WIDGET_CLASS (gtk_label_parent_class)->state_flags_changed)
3858     GTK_WIDGET_CLASS (gtk_label_parent_class)->state_flags_changed (widget, prev_state);
3859 }
3860
3861 static void
3862 gtk_label_style_updated (GtkWidget *widget)
3863 {
3864   GtkLabel *label = GTK_LABEL (widget);
3865
3866   GTK_WIDGET_CLASS (gtk_label_parent_class)->style_updated (widget);
3867
3868   /* We have to clear the layout, fonts etc. may have changed */
3869   gtk_label_clear_layout (label);
3870 }
3871
3872 static void 
3873 gtk_label_direction_changed (GtkWidget        *widget,
3874                              GtkTextDirection previous_dir)
3875 {
3876   GtkLabel *label = GTK_LABEL (widget);
3877   GtkLabelPrivate *priv = label->priv;
3878
3879   if (priv->layout)
3880     pango_layout_context_changed (priv->layout);
3881
3882   GTK_WIDGET_CLASS (gtk_label_parent_class)->direction_changed (widget, previous_dir);
3883 }
3884
3885 static void
3886 get_layout_location (GtkLabel  *label,
3887                      gint      *xp,
3888                      gint      *yp)
3889 {
3890   GtkAllocation allocation;
3891   GtkMisc *misc;
3892   GtkWidget *widget;
3893   GtkLabelPrivate *priv;
3894   gint req_width, x, y;
3895   gint req_height;
3896   gint xpad, ypad;
3897   gfloat xalign, yalign;
3898   PangoRectangle logical;
3899
3900   misc   = GTK_MISC (label);
3901   widget = GTK_WIDGET (label);
3902   priv   = label->priv;
3903
3904   gtk_misc_get_alignment (misc, &xalign, &yalign);
3905   gtk_misc_get_padding (misc, &xpad, &ypad);
3906
3907   if (gtk_widget_get_direction (widget) != GTK_TEXT_DIR_LTR)
3908     xalign = 1.0 - xalign;
3909
3910   pango_layout_get_extents (priv->layout, NULL, &logical);
3911
3912   if (priv->have_transform)
3913     {
3914       PangoContext *context = gtk_widget_get_pango_context (widget);
3915       const PangoMatrix *matrix = pango_context_get_matrix (context);
3916       pango_matrix_transform_rectangle (matrix, &logical);
3917     }
3918
3919   pango_extents_to_pixels (&logical, NULL);
3920
3921   req_width  = logical.width;
3922   req_height = logical.height;
3923
3924   req_width  += 2 * xpad;
3925   req_height += 2 * ypad;
3926
3927   gtk_widget_get_allocation (widget, &allocation);
3928
3929   x = floor (allocation.x + xpad + xalign * (allocation.width - req_width) - logical.x);
3930
3931
3932   /* bgo#315462 - For single-line labels, *do* align the requisition with
3933    * respect to the allocation, even if we are under-allocated.  For multi-line
3934    * labels, always show the top of the text when they are under-allocated.  The
3935    * rationale is this:
3936    *
3937    * - Single-line labels appear in GtkButtons, and it is very easy to get them
3938    *   to be smaller than their requisition.  The button may clip the label, but
3939    *   the label will still be able to show most of itself and the focus
3940    *   rectangle.  Also, it is fairly easy to read a single line of clipped text.
3941    *
3942    * - Multi-line labels should not be clipped to showing "something in the
3943    *   middle".  You want to read the first line, at least, to get some context.
3944    */
3945   if (pango_layout_get_line_count (priv->layout) == 1)
3946     y = floor (allocation.y + ypad + (allocation.height - req_height) * yalign) - logical.y;
3947   else
3948     y = floor (allocation.y + ypad + MAX ((allocation.height - req_height) * yalign, 0)) - logical.y;
3949
3950   if (xp)
3951     *xp = x;
3952
3953   if (yp)
3954     *yp = y;
3955 }
3956
3957 static PangoDirection
3958 get_cursor_direction (GtkLabel *label)
3959 {
3960   GtkLabelPrivate *priv = label->priv;
3961   GSList *l;
3962
3963   g_assert (priv->select_info);
3964
3965   gtk_label_ensure_layout (label);
3966
3967   for (l = pango_layout_get_lines_readonly (priv->layout); l; l = l->next)
3968     {
3969       PangoLayoutLine *line = l->data;
3970
3971       /* If priv->select_info->selection_end is at the very end of
3972        * the line, we don't know if the cursor is on this line or
3973        * the next without looking ahead at the next line. (End
3974        * of paragraph is different from line break.) But it's
3975        * definitely in this paragraph, which is good enough
3976        * to figure out the resolved direction.
3977        */
3978        if (line->start_index + line->length >= priv->select_info->selection_end)
3979         return line->resolved_dir;
3980     }
3981
3982   return PANGO_DIRECTION_LTR;
3983 }
3984
3985 static GtkLabelLink *
3986 gtk_label_get_focus_link (GtkLabel *label)
3987 {
3988   GtkLabelPrivate *priv = label->priv;
3989   GtkLabelSelectionInfo *info = priv->select_info;
3990   GList *l;
3991
3992   if (!info)
3993     return NULL;
3994
3995   if (info->selection_anchor != info->selection_end)
3996     return NULL;
3997
3998   for (l = info->links; l; l = l->next)
3999     {
4000       GtkLabelLink *link = l->data;
4001       if (link->start <= info->selection_anchor &&
4002           info->selection_anchor <= link->end)
4003         return link;
4004     }
4005
4006   return NULL;
4007 }
4008
4009 static gint
4010 gtk_label_draw (GtkWidget *widget,
4011                 cairo_t   *cr)
4012 {
4013   GtkLabel *label = GTK_LABEL (widget);
4014   GtkLabelPrivate *priv = label->priv;
4015   GtkLabelSelectionInfo *info = priv->select_info;
4016   GtkAllocation allocation;
4017   GtkStyleContext *context;
4018   GtkStateFlags state;
4019   gint x, y;
4020
4021   gtk_label_ensure_layout (label);
4022
4023   if (priv->text && (*priv->text != '\0'))
4024     {
4025       get_layout_location (label, &x, &y);
4026
4027       context = gtk_widget_get_style_context (widget);
4028       gtk_widget_get_allocation (widget, &allocation);
4029
4030       cairo_translate (cr, -allocation.x, -allocation.y);
4031
4032       gtk_render_layout (context, cr,
4033                          x, y,
4034                          priv->layout);
4035
4036       state = gtk_widget_get_state_flags (widget);
4037
4038       if (info &&
4039           (info->selection_anchor != info->selection_end))
4040         {
4041           gint range[2];
4042           cairo_region_t *clip;
4043           GdkRGBA bg_color, fg_color;
4044
4045           range[0] = info->selection_anchor;
4046           range[1] = info->selection_end;
4047
4048           if (range[0] > range[1])
4049             {
4050               gint tmp = range[0];
4051               range[0] = range[1];
4052               range[1] = tmp;
4053             }
4054
4055           clip = gdk_pango_layout_get_clip_region (priv->layout,
4056                                                    x, y,
4057                                                    range,
4058                                                    1);
4059
4060          /* FIXME should use gtk_paint, but it can't use a clip region */
4061           cairo_save (cr);
4062
4063           gdk_cairo_region (cr, clip);
4064           cairo_clip (cr);
4065
4066           state |= GTK_STATE_FLAG_SELECTED;
4067
4068           gtk_style_context_get_color (context, state, &fg_color);
4069           gtk_style_context_get_background_color (context, state, &bg_color);
4070
4071           gdk_cairo_set_source_rgba (cr, &bg_color);
4072           cairo_paint (cr);
4073
4074           gdk_cairo_set_source_rgba (cr, &fg_color);
4075           cairo_move_to (cr, x, y);
4076           _gtk_pango_fill_layout (cr, priv->layout);
4077
4078           cairo_restore (cr);
4079           cairo_region_destroy (clip);
4080         }
4081       else if (info)
4082         {
4083           GtkLabelLink *focus_link;
4084           GtkLabelLink *active_link;
4085           gint range[2];
4086           cairo_region_t *clip;
4087           GdkRectangle rect;
4088           GdkColor *text_color;
4089           GdkColor *link_color;
4090           GdkColor *visited_link_color;
4091
4092           if (info->selectable &&
4093               gtk_widget_has_focus (widget) &&
4094               gtk_widget_is_drawable (widget))
4095             {
4096               PangoDirection cursor_direction;
4097
4098               cursor_direction = get_cursor_direction (label);
4099               gtk_render_insertion_cursor (context, cr,
4100                                            x, y,
4101                                            priv->layout, priv->select_info->selection_end,
4102                                            cursor_direction);
4103             }
4104
4105           focus_link = gtk_label_get_focus_link (label);
4106           active_link = info->active_link;
4107
4108           if (active_link)
4109             {
4110               GdkRGBA bg_color;
4111
4112               range[0] = active_link->start;
4113               range[1] = active_link->end;
4114
4115               cairo_save (cr);
4116
4117               clip = gdk_pango_layout_get_clip_region (priv->layout,
4118                                                        x, y,
4119                                                        range,
4120                                                        1);
4121               gdk_cairo_region (cr, clip);
4122               cairo_clip (cr);
4123               cairo_region_destroy (clip);
4124
4125               gtk_label_get_link_colors (widget, &link_color, &visited_link_color);
4126               if (active_link->visited)
4127                 text_color = visited_link_color;
4128               else
4129                 text_color = link_color;
4130
4131               if (info->link_clicked)
4132                 state |= GTK_STATE_FLAG_ACTIVE;
4133               else
4134                 state |= GTK_STATE_FLAG_PRELIGHT;
4135
4136               gtk_style_context_get_background_color (context, state, &bg_color);
4137
4138               gdk_cairo_set_source_rgba (cr, &bg_color);
4139               cairo_paint (cr);
4140
4141               gdk_cairo_set_source_color (cr, text_color);
4142               cairo_move_to (cr, x, y);
4143               _gtk_pango_fill_layout (cr, priv->layout);
4144
4145               gdk_color_free (link_color);
4146               gdk_color_free (visited_link_color);
4147
4148               cairo_restore (cr);
4149             }
4150
4151           if (focus_link && gtk_widget_has_visible_focus (widget))
4152             {
4153               range[0] = focus_link->start;
4154               range[1] = focus_link->end;
4155
4156               clip = gdk_pango_layout_get_clip_region (priv->layout,
4157                                                        x, y,
4158                                                        range,
4159                                                        1);
4160               cairo_region_get_extents (clip, &rect);
4161
4162               gtk_render_focus (context, cr,
4163                                 rect.x, rect.y,
4164                                 rect.width, rect.height);
4165
4166               cairo_region_destroy (clip);
4167             }
4168         }
4169     }
4170
4171   return FALSE;
4172 }
4173
4174 static gboolean
4175 separate_uline_pattern (const gchar  *str,
4176                         guint        *accel_key,
4177                         gchar       **new_str,
4178                         gchar       **pattern)
4179 {
4180   gboolean underscore;
4181   const gchar *src;
4182   gchar *dest;
4183   gchar *pattern_dest;
4184
4185   *accel_key = GDK_KEY_VoidSymbol;
4186   *new_str = g_new (gchar, strlen (str) + 1);
4187   *pattern = g_new (gchar, g_utf8_strlen (str, -1) + 1);
4188
4189   underscore = FALSE;
4190
4191   src = str;
4192   dest = *new_str;
4193   pattern_dest = *pattern;
4194
4195   while (*src)
4196     {
4197       gunichar c;
4198       const gchar *next_src;
4199
4200       c = g_utf8_get_char (src);
4201       if (c == (gunichar)-1)
4202         {
4203           g_warning ("Invalid input string");
4204           g_free (*new_str);
4205           g_free (*pattern);
4206
4207           return FALSE;
4208         }
4209       next_src = g_utf8_next_char (src);
4210
4211       if (underscore)
4212         {
4213           if (c == '_')
4214             *pattern_dest++ = ' ';
4215           else
4216             {
4217               *pattern_dest++ = '_';
4218               if (*accel_key == GDK_KEY_VoidSymbol)
4219                 *accel_key = gdk_keyval_to_lower (gdk_unicode_to_keyval (c));
4220             }
4221
4222           while (src < next_src)
4223             *dest++ = *src++;
4224
4225           underscore = FALSE;
4226         }
4227       else
4228         {
4229           if (c == '_')
4230             {
4231               underscore = TRUE;
4232               src = next_src;
4233             }
4234           else
4235             {
4236               while (src < next_src)
4237                 *dest++ = *src++;
4238
4239               *pattern_dest++ = ' ';
4240             }
4241         }
4242     }
4243
4244   *dest = 0;
4245   *pattern_dest = 0;
4246
4247   return TRUE;
4248 }
4249
4250 static void
4251 gtk_label_set_uline_text_internal (GtkLabel    *label,
4252                                    const gchar *str)
4253 {
4254   GtkLabelPrivate *priv = label->priv;
4255   guint accel_key = GDK_KEY_VoidSymbol;
4256   gchar *new_str;
4257   gchar *pattern;
4258
4259   g_return_if_fail (GTK_IS_LABEL (label));
4260   g_return_if_fail (str != NULL);
4261
4262   /* Split text into the base text and a separate pattern
4263    * of underscores.
4264    */
4265   if (!separate_uline_pattern (str, &accel_key, &new_str, &pattern))
4266     return;
4267
4268   gtk_label_set_text_internal (label, new_str);
4269   gtk_label_set_pattern_internal (label, pattern, TRUE);
4270   priv->mnemonic_keyval = accel_key;
4271
4272   g_free (pattern);
4273 }
4274
4275 /**
4276  * gtk_label_set_text_with_mnemonic:
4277  * @label: a #GtkLabel
4278  * @str: a string
4279  * 
4280  * Sets the label's text from the string @str.
4281  * If characters in @str are preceded by an underscore, they are underlined
4282  * indicating that they represent a keyboard accelerator called a mnemonic.
4283  * The mnemonic key can be used to activate another widget, chosen 
4284  * automatically, or explicitly using gtk_label_set_mnemonic_widget().
4285  **/
4286 void
4287 gtk_label_set_text_with_mnemonic (GtkLabel    *label,
4288                                   const gchar *str)
4289 {
4290   g_return_if_fail (GTK_IS_LABEL (label));
4291   g_return_if_fail (str != NULL);
4292
4293   g_object_freeze_notify (G_OBJECT (label));
4294
4295   gtk_label_set_label_internal (label, g_strdup (str ? str : ""));
4296   gtk_label_set_use_markup_internal (label, FALSE);
4297   gtk_label_set_use_underline_internal (label, TRUE);
4298   
4299   gtk_label_recalculate (label);
4300
4301   g_object_thaw_notify (G_OBJECT (label));
4302 }
4303
4304 static void
4305 gtk_label_realize (GtkWidget *widget)
4306 {
4307   GtkLabel *label = GTK_LABEL (widget);
4308   GtkLabelPrivate *priv = label->priv;
4309
4310   GTK_WIDGET_CLASS (gtk_label_parent_class)->realize (widget);
4311
4312   if (priv->select_info)
4313     gtk_label_create_window (label);
4314 }
4315
4316 static void
4317 gtk_label_unrealize (GtkWidget *widget)
4318 {
4319   GtkLabel *label = GTK_LABEL (widget);
4320   GtkLabelPrivate *priv = label->priv;
4321
4322   if (priv->select_info)
4323     gtk_label_destroy_window (label);
4324
4325   GTK_WIDGET_CLASS (gtk_label_parent_class)->unrealize (widget);
4326 }
4327
4328 static void
4329 gtk_label_map (GtkWidget *widget)
4330 {
4331   GtkLabel *label = GTK_LABEL (widget);
4332   GtkLabelPrivate *priv = label->priv;
4333
4334   GTK_WIDGET_CLASS (gtk_label_parent_class)->map (widget);
4335
4336   if (priv->select_info)
4337     gdk_window_show (priv->select_info->window);
4338 }
4339
4340 static void
4341 gtk_label_unmap (GtkWidget *widget)
4342 {
4343   GtkLabel *label = GTK_LABEL (widget);
4344   GtkLabelPrivate *priv = label->priv;
4345
4346   if (priv->select_info)
4347     gdk_window_hide (priv->select_info->window);
4348
4349   GTK_WIDGET_CLASS (gtk_label_parent_class)->unmap (widget);
4350 }
4351
4352 static void
4353 window_to_layout_coords (GtkLabel *label,
4354                          gint     *x,
4355                          gint     *y)
4356 {
4357   GtkAllocation allocation;
4358   gint lx, ly;
4359   GtkWidget *widget;
4360
4361   widget = GTK_WIDGET (label);
4362   
4363   /* get layout location in widget->window coords */
4364   get_layout_location (label, &lx, &ly);
4365
4366   gtk_widget_get_allocation (widget, &allocation);
4367
4368   if (x)
4369     {
4370       *x += allocation.x; /* go to widget->window */
4371       *x -= lx;                   /* go to layout */
4372     }
4373
4374   if (y)
4375     {
4376       *y += allocation.y; /* go to widget->window */
4377       *y -= ly;                   /* go to layout */
4378     }
4379 }
4380
4381 #if 0
4382 static void
4383 layout_to_window_coords (GtkLabel *label,
4384                          gint     *x,
4385                          gint     *y)
4386 {
4387   gint lx, ly;
4388   GtkWidget *widget;
4389
4390   widget = GTK_WIDGET (label);
4391   
4392   /* get layout location in widget->window coords */
4393   get_layout_location (label, &lx, &ly);
4394   
4395   if (x)
4396     {
4397       *x += lx;                   /* go to widget->window */
4398       *x -= widget->allocation.x; /* go to selection window */
4399     }
4400
4401   if (y)
4402     {
4403       *y += ly;                   /* go to widget->window */
4404       *y -= widget->allocation.y; /* go to selection window */
4405     }
4406 }
4407 #endif
4408
4409 static gboolean
4410 get_layout_index (GtkLabel *label,
4411                   gint      x,
4412                   gint      y,
4413                   gint     *index)
4414 {
4415   GtkLabelPrivate *priv = label->priv;
4416   gint trailing = 0;
4417   const gchar *cluster;
4418   const gchar *cluster_end;
4419   gboolean inside;
4420
4421   *index = 0;
4422
4423   gtk_label_ensure_layout (label);
4424
4425   window_to_layout_coords (label, &x, &y);
4426
4427   x *= PANGO_SCALE;
4428   y *= PANGO_SCALE;
4429
4430   inside = pango_layout_xy_to_index (priv->layout,
4431                                      x, y,
4432                                      index, &trailing);
4433
4434   cluster = priv->text + *index;
4435   cluster_end = cluster;
4436   while (trailing)
4437     {
4438       cluster_end = g_utf8_next_char (cluster_end);
4439       --trailing;
4440     }
4441
4442   *index += (cluster_end - cluster);
4443
4444   return inside;
4445 }
4446
4447 static void
4448 gtk_label_select_word (GtkLabel *label)
4449 {
4450   GtkLabelPrivate *priv = label->priv;
4451   gint min, max;
4452
4453   gint start_index = gtk_label_move_backward_word (label, priv->select_info->selection_end);
4454   gint end_index = gtk_label_move_forward_word (label, priv->select_info->selection_end);
4455
4456   min = MIN (priv->select_info->selection_anchor,
4457              priv->select_info->selection_end);
4458   max = MAX (priv->select_info->selection_anchor,
4459              priv->select_info->selection_end);
4460
4461   min = MIN (min, start_index);
4462   max = MAX (max, end_index);
4463
4464   gtk_label_select_region_index (label, min, max);
4465 }
4466
4467 static void
4468 gtk_label_grab_focus (GtkWidget *widget)
4469 {
4470   GtkLabel *label = GTK_LABEL (widget);
4471   GtkLabelPrivate *priv = label->priv;
4472   gboolean select_on_focus;
4473   GtkLabelLink *link;
4474
4475   if (priv->select_info == NULL)
4476     return;
4477
4478   GTK_WIDGET_CLASS (gtk_label_parent_class)->grab_focus (widget);
4479
4480   if (priv->select_info->selectable)
4481     {
4482       g_object_get (gtk_widget_get_settings (widget),
4483                     "gtk-label-select-on-focus",
4484                     &select_on_focus,
4485                     NULL);
4486
4487       if (select_on_focus && !priv->in_click)
4488         gtk_label_select_region (label, 0, -1);
4489     }
4490   else
4491     {
4492       if (priv->select_info->links && !priv->in_click)
4493         {
4494           link = priv->select_info->links->data;
4495           priv->select_info->selection_anchor = link->start;
4496           priv->select_info->selection_end = link->start;
4497         }
4498     }
4499 }
4500
4501 static gboolean
4502 gtk_label_focus (GtkWidget        *widget,
4503                  GtkDirectionType  direction)
4504 {
4505   GtkLabel *label = GTK_LABEL (widget);
4506   GtkLabelPrivate *priv = label->priv;
4507   GtkLabelSelectionInfo *info = priv->select_info;
4508   GtkLabelLink *focus_link;
4509   GList *l;
4510
4511   if (!gtk_widget_is_focus (widget))
4512     {
4513       gtk_widget_grab_focus (widget);
4514       if (info)
4515         {
4516           focus_link = gtk_label_get_focus_link (label);
4517           if (focus_link && direction == GTK_DIR_TAB_BACKWARD)
4518             {
4519               l = g_list_last (info->links);
4520               focus_link = l->data;
4521               info->selection_anchor = focus_link->start;
4522               info->selection_end = focus_link->start;
4523             }
4524         }
4525
4526       return TRUE;
4527     }
4528
4529   if (!info)
4530     return FALSE;
4531
4532   if (info->selectable)
4533     {
4534       gint index;
4535
4536       if (info->selection_anchor != info->selection_end)
4537         goto out;
4538
4539       index = info->selection_anchor;
4540
4541       if (direction == GTK_DIR_TAB_FORWARD)
4542         for (l = info->links; l; l = l->next)
4543           {
4544             GtkLabelLink *link = l->data;
4545
4546             if (link->start > index)
4547               {
4548                 gtk_label_select_region_index (label, link->start, link->start);
4549                 return TRUE;
4550               }
4551           }
4552       else if (direction == GTK_DIR_TAB_BACKWARD)
4553         for (l = g_list_last (info->links); l; l = l->prev)
4554           {
4555             GtkLabelLink *link = l->data;
4556
4557             if (link->end < index)
4558               {
4559                 gtk_label_select_region_index (label, link->start, link->start);
4560                 return TRUE;
4561               }
4562           }
4563
4564       goto out;
4565     }
4566   else
4567     {
4568       focus_link = gtk_label_get_focus_link (label);
4569       switch (direction)
4570         {
4571         case GTK_DIR_TAB_FORWARD:
4572           if (focus_link)
4573             {
4574               l = g_list_find (info->links, focus_link);
4575               l = l->next;
4576             }
4577           else
4578             l = info->links;
4579           break;
4580
4581         case GTK_DIR_TAB_BACKWARD:
4582           if (focus_link)
4583             {
4584               l = g_list_find (info->links, focus_link);
4585               l = l->prev;
4586             }
4587           else
4588             l = g_list_last (info->links);
4589           break;
4590
4591         default:
4592           goto out;
4593         }
4594
4595       if (l)
4596         {
4597           focus_link = l->data;
4598           info->selection_anchor = focus_link->start;
4599           info->selection_end = focus_link->start;
4600           gtk_widget_queue_draw (widget);
4601
4602           return TRUE;
4603         }
4604     }
4605
4606 out:
4607
4608   return FALSE;
4609 }
4610
4611 static gboolean
4612 gtk_label_button_press (GtkWidget      *widget,
4613                         GdkEventButton *event)
4614 {
4615   GtkLabel *label = GTK_LABEL (widget);
4616   GtkLabelPrivate *priv = label->priv;
4617   GtkLabelSelectionInfo *info = priv->select_info;
4618   gint index = 0;
4619   gint min, max;
4620
4621   if (info == NULL)
4622     return FALSE;
4623
4624   if (info->active_link)
4625     {
4626       if (gdk_event_triggers_context_menu ((GdkEvent *) event))
4627         {
4628           info->link_clicked = 1;
4629           gtk_label_do_popup (label, event);
4630           return TRUE;
4631         }
4632       else if (event->button == 1)
4633         {
4634           info->link_clicked = 1;
4635           gtk_widget_queue_draw (widget);
4636         }
4637     }
4638
4639   if (!info->selectable)
4640     return FALSE;
4641
4642   info->in_drag = FALSE;
4643   info->select_words = FALSE;
4644
4645   if (gdk_event_triggers_context_menu ((GdkEvent *) event))
4646     {
4647       gtk_label_do_popup (label, event);
4648
4649       return TRUE;
4650     }
4651   else if (event->button == 1)
4652     {
4653       if (!gtk_widget_has_focus (widget))
4654         {
4655           priv->in_click = TRUE;
4656           gtk_widget_grab_focus (widget);
4657           priv->in_click = FALSE;
4658         }
4659
4660       if (event->type == GDK_3BUTTON_PRESS)
4661         {
4662           gtk_label_select_region_index (label, 0, strlen (priv->text));
4663           return TRUE;
4664         }
4665
4666       if (event->type == GDK_2BUTTON_PRESS)
4667         {
4668           info->select_words = TRUE;
4669           gtk_label_select_word (label);
4670           return TRUE;
4671         }
4672
4673       get_layout_index (label, event->x, event->y, &index);
4674
4675       min = MIN (info->selection_anchor, info->selection_end);
4676       max = MAX (info->selection_anchor, info->selection_end);
4677
4678       if ((info->selection_anchor != info->selection_end) &&
4679           (event->state & GDK_SHIFT_MASK))
4680         {
4681           if (index > min && index < max)
4682             {
4683               /* truncate selection, but keep it as big as possible */
4684               if (index - min > max - index)
4685                 max = index;
4686               else
4687                 min = index;
4688             }
4689           else
4690             {
4691               /* extend (same as motion) */
4692               min = MIN (min, index);
4693               max = MAX (max, index);
4694             }
4695
4696           /* ensure the anchor is opposite index */
4697           if (index == min)
4698             {
4699               gint tmp = min;
4700               min = max;
4701               max = tmp;
4702             }
4703
4704           gtk_label_select_region_index (label, min, max);
4705         }
4706       else
4707         {
4708           if (event->type == GDK_3BUTTON_PRESS)
4709             gtk_label_select_region_index (label, 0, strlen (priv->text));
4710           else if (event->type == GDK_2BUTTON_PRESS)
4711             gtk_label_select_word (label);
4712           else if (min < max && min <= index && index <= max)
4713             {
4714               info->in_drag = TRUE;
4715               info->drag_start_x = event->x;
4716               info->drag_start_y = event->y;
4717             }
4718           else
4719             /* start a replacement */
4720             gtk_label_select_region_index (label, index, index);
4721         }
4722
4723       return TRUE;
4724     }
4725
4726   return FALSE;
4727 }
4728
4729 static gboolean
4730 gtk_label_button_release (GtkWidget      *widget,
4731                           GdkEventButton *event)
4732
4733 {
4734   GtkLabel *label = GTK_LABEL (widget);
4735   GtkLabelPrivate *priv = label->priv;
4736   GtkLabelSelectionInfo *info = priv->select_info;
4737   gint index;
4738
4739   if (info == NULL)
4740     return FALSE;
4741
4742   if (info->in_drag)
4743     {
4744       info->in_drag = 0;
4745
4746       get_layout_index (label, event->x, event->y, &index);
4747       gtk_label_select_region_index (label, index, index);
4748
4749       return FALSE;
4750     }
4751
4752   if (event->button != 1)
4753     return FALSE;
4754
4755   if (info->active_link &&
4756       info->selection_anchor == info->selection_end &&
4757       info->link_clicked)
4758     {
4759       emit_activate_link (label, info->active_link);
4760       info->link_clicked = 0;
4761
4762       return TRUE;
4763     }
4764
4765   /* The goal here is to return TRUE iff we ate the
4766    * button press to start selecting.
4767    */
4768   return TRUE;
4769 }
4770
4771 static void
4772 connect_mnemonics_visible_notify (GtkLabel *label)
4773 {
4774   GtkLabelPrivate *priv = label->priv;
4775   GtkWidget *toplevel;
4776   gboolean connected;
4777
4778   toplevel = gtk_widget_get_toplevel (GTK_WIDGET (label));
4779
4780   if (!GTK_IS_WINDOW (toplevel))
4781     return;
4782
4783   /* always set up this widgets initial value */
4784   priv->mnemonics_visible =
4785     gtk_window_get_mnemonics_visible (GTK_WINDOW (toplevel));
4786
4787   connected =
4788     GPOINTER_TO_INT (g_object_get_data (G_OBJECT (toplevel),
4789                                         "gtk-label-mnemonics-visible-connected"));
4790
4791   if (!connected)
4792     {
4793       g_signal_connect (toplevel,
4794                         "notify::mnemonics-visible",
4795                         G_CALLBACK (label_mnemonics_visible_changed),
4796                         label);
4797       g_object_set_data (G_OBJECT (toplevel),
4798                          "gtk-label-mnemonics-visible-connected",
4799                          GINT_TO_POINTER (1));
4800     }
4801 }
4802
4803 static void
4804 drag_begin_cb (GtkWidget      *widget,
4805                GdkDragContext *context,
4806                gpointer        data)
4807 {
4808   GtkLabel *label = GTK_LABEL (widget);
4809   GtkLabelPrivate *priv = label->priv;
4810   cairo_surface_t *surface = NULL;
4811
4812   g_signal_handlers_disconnect_by_func (widget, drag_begin_cb, NULL);
4813
4814   if ((priv->select_info->selection_anchor !=
4815        priv->select_info->selection_end) &&
4816       priv->text)
4817     {
4818       gint start, end;
4819       gint len;
4820
4821       start = MIN (priv->select_info->selection_anchor,
4822                    priv->select_info->selection_end);
4823       end = MAX (priv->select_info->selection_anchor,
4824                  priv->select_info->selection_end);
4825
4826       len = strlen (priv->text);
4827
4828       if (end > len)
4829         end = len;
4830
4831       if (start > len)
4832         start = len;
4833
4834       surface = _gtk_text_util_create_drag_icon (widget,
4835                                                  priv->text + start,
4836                                                  end - start);
4837     }
4838
4839   if (surface)
4840     {
4841       gtk_drag_set_icon_surface (context, surface);
4842       cairo_surface_destroy (surface);
4843     }
4844   else
4845     {
4846       gtk_drag_set_icon_default (context);
4847     }
4848 }
4849
4850 static gboolean
4851 gtk_label_motion (GtkWidget      *widget,
4852                   GdkEventMotion *event)
4853 {
4854   GtkLabel *label = GTK_LABEL (widget);
4855   GtkLabelPrivate *priv = label->priv;
4856   GtkLabelSelectionInfo *info = priv->select_info;
4857   gint index;
4858
4859   if (info == NULL)
4860     return FALSE;
4861
4862   if (info->links && !info->in_drag)
4863     {
4864       GList *l;
4865       GtkLabelLink *link;
4866       gboolean found = FALSE;
4867
4868       if (info->selection_anchor == info->selection_end)
4869         {
4870           if (get_layout_index (label, event->x, event->y, &index))
4871             {
4872               for (l = info->links; l != NULL; l = l->next)
4873                 {
4874                   link = l->data;
4875                   if (index >= link->start && index <= link->end)
4876                     {
4877                       found = TRUE;
4878                       break;
4879                     }
4880                 }
4881             }
4882         }
4883
4884       if (found)
4885         {
4886           if (info->active_link != link)
4887             {
4888               info->link_clicked = 0;
4889               info->active_link = link;
4890               gtk_label_update_cursor (label);
4891               gtk_widget_queue_draw (widget);
4892             }
4893         }
4894       else
4895         {
4896           if (info->active_link != NULL)
4897             {
4898               info->link_clicked = 0;
4899               info->active_link = NULL;
4900               gtk_label_update_cursor (label);
4901               gtk_widget_queue_draw (widget);
4902             }
4903         }
4904     }
4905
4906   if (!info->selectable)
4907     return FALSE;
4908
4909   if ((event->state & GDK_BUTTON1_MASK) == 0)
4910     return FALSE;
4911
4912   if (info->in_drag)
4913     {
4914       if (gtk_drag_check_threshold (widget,
4915                                     info->drag_start_x,
4916                                     info->drag_start_y,
4917                                     event->x, event->y))
4918         {
4919           GtkTargetList *target_list = gtk_target_list_new (NULL, 0);
4920
4921           gtk_target_list_add_text_targets (target_list, 0);
4922
4923           g_signal_connect (widget, "drag-begin",
4924                             G_CALLBACK (drag_begin_cb), NULL);
4925           gtk_drag_begin (widget, target_list,
4926                           GDK_ACTION_COPY,
4927                           1, (GdkEvent *)event);
4928
4929           info->in_drag = FALSE;
4930
4931           gtk_target_list_unref (target_list);
4932         }
4933     }
4934   else
4935     {
4936       gint x, y;
4937
4938       gdk_window_get_device_position (info->window, event->device, &x, &y, NULL);
4939       get_layout_index (label, x, y, &index);
4940
4941       if (info->select_words)
4942         {
4943           gint min, max;
4944           gint old_min, old_max;
4945           gint anchor, end;
4946
4947           min = gtk_label_move_backward_word (label, index);
4948           max = gtk_label_move_forward_word (label, index);
4949
4950           anchor = info->selection_anchor;
4951           end = info->selection_end;
4952
4953           old_min = MIN (anchor, end);
4954           old_max = MAX (anchor, end);
4955
4956           if (min < old_min)
4957             {
4958               anchor = min;
4959               end = old_max;
4960             }
4961           else if (old_max < max)
4962             {
4963               anchor = max;
4964               end = old_min;
4965             }
4966           else if (anchor == old_min)
4967             {
4968               if (anchor != min)
4969                 anchor = max;
4970             }
4971           else
4972             {
4973               if (anchor != max)
4974                 anchor = min;
4975             }
4976
4977           gtk_label_select_region_index (label, anchor, end);
4978         }
4979       else
4980         gtk_label_select_region_index (label, info->selection_anchor, index);
4981     }
4982
4983   return TRUE;
4984 }
4985
4986 static gboolean
4987 gtk_label_leave_notify (GtkWidget        *widget,
4988                         GdkEventCrossing *event)
4989 {
4990   GtkLabel *label = GTK_LABEL (widget);
4991   GtkLabelPrivate *priv = label->priv;
4992
4993   if (priv->select_info)
4994     {
4995       priv->select_info->active_link = NULL;
4996       gtk_label_update_cursor (label);
4997       gtk_widget_queue_draw (widget);
4998     }
4999
5000   if (GTK_WIDGET_CLASS (gtk_label_parent_class)->leave_notify_event)
5001     return GTK_WIDGET_CLASS (gtk_label_parent_class)->leave_notify_event (widget, event);
5002
5003  return FALSE;
5004 }
5005
5006 static void
5007 gtk_label_create_window (GtkLabel *label)
5008 {
5009   GtkLabelPrivate *priv = label->priv;
5010   GtkAllocation allocation;
5011   GtkWidget *widget;
5012   GdkWindowAttr attributes;
5013   gint attributes_mask;
5014
5015   g_assert (priv->select_info);
5016   widget = GTK_WIDGET (label);
5017   g_assert (gtk_widget_get_realized (widget));
5018
5019   if (priv->select_info->window)
5020     return;
5021
5022   gtk_widget_get_allocation (widget, &allocation);
5023
5024   attributes.x = allocation.x;
5025   attributes.y = allocation.y;
5026   attributes.width = allocation.width;
5027   attributes.height = allocation.height;
5028   attributes.window_type = GDK_WINDOW_CHILD;
5029   attributes.wclass = GDK_INPUT_ONLY;
5030   attributes.override_redirect = TRUE;
5031   attributes.event_mask = gtk_widget_get_events (widget) |
5032     GDK_BUTTON_PRESS_MASK        |
5033     GDK_BUTTON_RELEASE_MASK      |
5034     GDK_LEAVE_NOTIFY_MASK        |
5035     GDK_BUTTON_MOTION_MASK       |
5036     GDK_POINTER_MOTION_MASK      |
5037     GDK_POINTER_MOTION_HINT_MASK;
5038   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_NOREDIR;
5039   if (gtk_widget_is_sensitive (widget))
5040     {
5041       attributes.cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget),
5042                                                       GDK_XTERM);
5043       attributes_mask |= GDK_WA_CURSOR;
5044     }
5045
5046
5047   priv->select_info->window = gdk_window_new (gtk_widget_get_window (widget),
5048                                                &attributes, attributes_mask);
5049   gdk_window_set_user_data (priv->select_info->window, widget);
5050
5051   if (attributes_mask & GDK_WA_CURSOR)
5052     g_object_unref (attributes.cursor);
5053 }
5054
5055 static void
5056 gtk_label_destroy_window (GtkLabel *label)
5057 {
5058   GtkLabelPrivate *priv = label->priv;
5059
5060   g_assert (priv->select_info);
5061
5062   if (priv->select_info->window == NULL)
5063     return;
5064
5065   gdk_window_set_user_data (priv->select_info->window, NULL);
5066   gdk_window_destroy (priv->select_info->window);
5067   priv->select_info->window = NULL;
5068 }
5069
5070 static void
5071 gtk_label_ensure_select_info (GtkLabel *label)
5072 {
5073   GtkLabelPrivate *priv = label->priv;
5074
5075   if (priv->select_info == NULL)
5076     {
5077       priv->select_info = g_new0 (GtkLabelSelectionInfo, 1);
5078
5079       gtk_widget_set_can_focus (GTK_WIDGET (label), TRUE);
5080
5081       if (gtk_widget_get_realized (GTK_WIDGET (label)))
5082         gtk_label_create_window (label);
5083
5084       if (gtk_widget_get_mapped (GTK_WIDGET (label)))
5085         gdk_window_show (priv->select_info->window);
5086     }
5087 }
5088
5089 static void
5090 gtk_label_clear_select_info (GtkLabel *label)
5091 {
5092   GtkLabelPrivate *priv = label->priv;
5093
5094   if (priv->select_info == NULL)
5095     return;
5096
5097   if (!priv->select_info->selectable && !priv->select_info->links)
5098     {
5099       gtk_label_destroy_window (label);
5100
5101       g_free (priv->select_info);
5102       priv->select_info = NULL;
5103
5104       gtk_widget_set_can_focus (GTK_WIDGET (label), FALSE);
5105     }
5106 }
5107
5108 /**
5109  * gtk_label_set_selectable:
5110  * @label: a #GtkLabel
5111  * @setting: %TRUE to allow selecting text in the label
5112  *
5113  * Selectable labels allow the user to select text from the label, for
5114  * copy-and-paste.
5115  **/
5116 void
5117 gtk_label_set_selectable (GtkLabel *label,
5118                           gboolean  setting)
5119 {
5120   GtkLabelPrivate *priv;
5121   gboolean old_setting;
5122
5123   g_return_if_fail (GTK_IS_LABEL (label));
5124
5125   priv = label->priv;
5126
5127   setting = setting != FALSE;
5128   old_setting = priv->select_info && priv->select_info->selectable;
5129
5130   if (setting)
5131     {
5132       gtk_label_ensure_select_info (label);
5133       priv->select_info->selectable = TRUE;
5134       gtk_label_update_cursor (label);
5135     }
5136   else
5137     {
5138       if (old_setting)
5139         {
5140           /* unselect, to give up the selection */
5141           gtk_label_select_region (label, 0, 0);
5142
5143           priv->select_info->selectable = FALSE;
5144           gtk_label_clear_select_info (label);
5145           gtk_label_update_cursor (label);
5146         }
5147     }
5148   if (setting != old_setting)
5149     {
5150       g_object_freeze_notify (G_OBJECT (label));
5151       g_object_notify (G_OBJECT (label), "selectable");
5152       g_object_notify (G_OBJECT (label), "cursor-position");
5153       g_object_notify (G_OBJECT (label), "selection-bound");
5154       g_object_thaw_notify (G_OBJECT (label));
5155       gtk_widget_queue_draw (GTK_WIDGET (label));
5156     }
5157 }
5158
5159 /**
5160  * gtk_label_get_selectable:
5161  * @label: a #GtkLabel
5162  * 
5163  * Gets the value set by gtk_label_set_selectable().
5164  * 
5165  * Return value: %TRUE if the user can copy text from the label
5166  **/
5167 gboolean
5168 gtk_label_get_selectable (GtkLabel *label)
5169 {
5170   GtkLabelPrivate *priv;
5171
5172   g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
5173
5174   priv = label->priv;
5175
5176   return priv->select_info && priv->select_info->selectable;
5177 }
5178
5179 /**
5180  * gtk_label_set_angle:
5181  * @label: a #GtkLabel
5182  * @angle: the angle that the baseline of the label makes with
5183  *   the horizontal, in degrees, measured counterclockwise
5184  * 
5185  * Sets the angle of rotation for the label. An angle of 90 reads from
5186  * from bottom to top, an angle of 270, from top to bottom. The angle
5187  * setting for the label is ignored if the label is selectable,
5188  * wrapped, or ellipsized.
5189  *
5190  * Since: 2.6
5191  **/
5192 void
5193 gtk_label_set_angle (GtkLabel *label,
5194                      gdouble   angle)
5195 {
5196   GtkLabelPrivate *priv;
5197
5198   g_return_if_fail (GTK_IS_LABEL (label));
5199
5200   priv = label->priv;
5201
5202   /* Canonicalize to [0,360]. We don't canonicalize 360 to 0, because
5203    * double property ranges are inclusive, and changing 360 to 0 would
5204    * make a property editor behave strangely.
5205    */
5206   if (angle < 0 || angle > 360.0)
5207     angle = angle - 360. * floor (angle / 360.);
5208
5209   if (priv->angle != angle)
5210     {
5211       priv->angle = angle;
5212       
5213       gtk_label_clear_layout (label);
5214       gtk_widget_queue_resize (GTK_WIDGET (label));
5215
5216       g_object_notify (G_OBJECT (label), "angle");
5217     }
5218 }
5219
5220 /**
5221  * gtk_label_get_angle:
5222  * @label: a #GtkLabel
5223  * 
5224  * Gets the angle of rotation for the label. See
5225  * gtk_label_set_angle().
5226  * 
5227  * Return value: the angle of rotation for the label
5228  *
5229  * Since: 2.6
5230  **/
5231 gdouble
5232 gtk_label_get_angle  (GtkLabel *label)
5233 {
5234   g_return_val_if_fail (GTK_IS_LABEL (label), 0.0);
5235   
5236   return label->priv->angle;
5237 }
5238
5239 static void
5240 gtk_label_set_selection_text (GtkLabel         *label,
5241                               GtkSelectionData *selection_data)
5242 {
5243   GtkLabelPrivate *priv = label->priv;
5244
5245   if (priv->select_info &&
5246       (priv->select_info->selection_anchor !=
5247        priv->select_info->selection_end) &&
5248       priv->text)
5249     {
5250       gint start, end;
5251       gint len;
5252
5253       start = MIN (priv->select_info->selection_anchor,
5254                    priv->select_info->selection_end);
5255       end = MAX (priv->select_info->selection_anchor,
5256                  priv->select_info->selection_end);
5257
5258       len = strlen (priv->text);
5259
5260       if (end > len)
5261         end = len;
5262
5263       if (start > len)
5264         start = len;
5265
5266       gtk_selection_data_set_text (selection_data,
5267                                    priv->text + start,
5268                                    end - start);
5269     }
5270 }
5271
5272 static void
5273 gtk_label_drag_data_get (GtkWidget        *widget,
5274                          GdkDragContext   *context,
5275                          GtkSelectionData *selection_data,
5276                          guint             info,
5277                          guint             time)
5278 {
5279   gtk_label_set_selection_text (GTK_LABEL (widget), selection_data);
5280 }
5281
5282 static void
5283 get_text_callback (GtkClipboard     *clipboard,
5284                    GtkSelectionData *selection_data,
5285                    guint             info,
5286                    gpointer          user_data_or_owner)
5287 {
5288   gtk_label_set_selection_text (GTK_LABEL (user_data_or_owner), selection_data);
5289 }
5290
5291 static void
5292 clear_text_callback (GtkClipboard     *clipboard,
5293                      gpointer          user_data_or_owner)
5294 {
5295   GtkLabel *label;
5296   GtkLabelPrivate *priv;
5297
5298   label = GTK_LABEL (user_data_or_owner);
5299   priv = label->priv;
5300
5301   if (priv->select_info)
5302     {
5303       priv->select_info->selection_anchor = priv->select_info->selection_end;
5304
5305       gtk_widget_queue_draw (GTK_WIDGET (label));
5306     }
5307 }
5308
5309 static void
5310 gtk_label_select_region_index (GtkLabel *label,
5311                                gint      anchor_index,
5312                                gint      end_index)
5313 {
5314   GtkLabelPrivate *priv;
5315
5316   g_return_if_fail (GTK_IS_LABEL (label));
5317
5318   priv = label->priv;
5319
5320   if (priv->select_info && priv->select_info->selectable)
5321     {
5322       GtkClipboard *clipboard;
5323
5324       if (priv->select_info->selection_anchor == anchor_index &&
5325           priv->select_info->selection_end == end_index)
5326         return;
5327
5328       g_object_freeze_notify (G_OBJECT (label));
5329
5330       if (priv->select_info->selection_anchor != anchor_index)
5331         g_object_notify (G_OBJECT (label), "selection-bound");
5332       if (priv->select_info->selection_end != end_index)
5333         g_object_notify (G_OBJECT (label), "cursor-position");
5334
5335       priv->select_info->selection_anchor = anchor_index;
5336       priv->select_info->selection_end = end_index;
5337
5338       if (gtk_widget_has_screen (GTK_WIDGET (label)))
5339         clipboard = gtk_widget_get_clipboard (GTK_WIDGET (label),
5340                                               GDK_SELECTION_PRIMARY);
5341       else
5342         clipboard = NULL;
5343
5344       if (anchor_index != end_index)
5345         {
5346           GtkTargetList *list;
5347           GtkTargetEntry *targets;
5348           gint n_targets;
5349
5350           list = gtk_target_list_new (NULL, 0);
5351           gtk_target_list_add_text_targets (list, 0);
5352           targets = gtk_target_table_new_from_list (list, &n_targets);
5353
5354           if (clipboard)
5355             gtk_clipboard_set_with_owner (clipboard,
5356                                           targets, n_targets,
5357                                           get_text_callback,
5358                                           clear_text_callback,
5359                                           G_OBJECT (label));
5360
5361           gtk_target_table_free (targets, n_targets);
5362           gtk_target_list_unref (list);
5363         }
5364       else
5365         {
5366           if (clipboard &&
5367               gtk_clipboard_get_owner (clipboard) == G_OBJECT (label))
5368             gtk_clipboard_clear (clipboard);
5369         }
5370
5371       gtk_widget_queue_draw (GTK_WIDGET (label));
5372
5373       g_object_thaw_notify (G_OBJECT (label));
5374     }
5375 }
5376
5377 /**
5378  * gtk_label_select_region:
5379  * @label: a #GtkLabel
5380  * @start_offset: start offset (in characters not bytes)
5381  * @end_offset: end offset (in characters not bytes)
5382  *
5383  * Selects a range of characters in the label, if the label is selectable.
5384  * See gtk_label_set_selectable(). If the label is not selectable,
5385  * this function has no effect. If @start_offset or
5386  * @end_offset are -1, then the end of the label will be substituted.
5387  **/
5388 void
5389 gtk_label_select_region  (GtkLabel *label,
5390                           gint      start_offset,
5391                           gint      end_offset)
5392 {
5393   GtkLabelPrivate *priv;
5394
5395   g_return_if_fail (GTK_IS_LABEL (label));
5396
5397   priv = label->priv;
5398
5399   if (priv->text && priv->select_info)
5400     {
5401       if (start_offset < 0)
5402         start_offset = g_utf8_strlen (priv->text, -1);
5403       
5404       if (end_offset < 0)
5405         end_offset = g_utf8_strlen (priv->text, -1);
5406       
5407       gtk_label_select_region_index (label,
5408                                      g_utf8_offset_to_pointer (priv->text, start_offset) - priv->text,
5409                                      g_utf8_offset_to_pointer (priv->text, end_offset) - priv->text);
5410     }
5411 }
5412
5413 /**
5414  * gtk_label_get_selection_bounds:
5415  * @label: a #GtkLabel
5416  * @start: (out): return location for start of selection, as a character offset
5417  * @end: (out): return location for end of selection, as a character offset
5418  * 
5419  * Gets the selected range of characters in the label, returning %TRUE
5420  * if there's a selection.
5421  * 
5422  * Return value: %TRUE if selection is non-empty
5423  **/
5424 gboolean
5425 gtk_label_get_selection_bounds (GtkLabel  *label,
5426                                 gint      *start,
5427                                 gint      *end)
5428 {
5429   GtkLabelPrivate *priv;
5430
5431   g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
5432
5433   priv = label->priv;
5434
5435   if (priv->select_info == NULL)
5436     {
5437       /* not a selectable label */
5438       if (start)
5439         *start = 0;
5440       if (end)
5441         *end = 0;
5442
5443       return FALSE;
5444     }
5445   else
5446     {
5447       gint start_index, end_index;
5448       gint start_offset, end_offset;
5449       gint len;
5450       
5451       start_index = MIN (priv->select_info->selection_anchor,
5452                    priv->select_info->selection_end);
5453       end_index = MAX (priv->select_info->selection_anchor,
5454                  priv->select_info->selection_end);
5455
5456       len = strlen (priv->text);
5457
5458       if (end_index > len)
5459         end_index = len;
5460
5461       if (start_index > len)
5462         start_index = len;
5463       
5464       start_offset = g_utf8_strlen (priv->text, start_index);
5465       end_offset = g_utf8_strlen (priv->text, end_index);
5466
5467       if (start_offset > end_offset)
5468         {
5469           gint tmp = start_offset;
5470           start_offset = end_offset;
5471           end_offset = tmp;
5472         }
5473       
5474       if (start)
5475         *start = start_offset;
5476
5477       if (end)
5478         *end = end_offset;
5479
5480       return start_offset != end_offset;
5481     }
5482 }
5483
5484
5485 /**
5486  * gtk_label_get_layout:
5487  * @label: a #GtkLabel
5488  * 
5489  * Gets the #PangoLayout used to display the label.
5490  * The layout is useful to e.g. convert text positions to
5491  * pixel positions, in combination with gtk_label_get_layout_offsets().
5492  * The returned layout is owned by the @label so need not be
5493  * freed by the caller. The @label is free to recreate its layout at
5494  * any time, so it should be considered read-only.
5495  *
5496  * Return value: (transfer none): the #PangoLayout for this label
5497  **/
5498 PangoLayout*
5499 gtk_label_get_layout (GtkLabel *label)
5500 {
5501   GtkLabelPrivate *priv;
5502
5503   g_return_val_if_fail (GTK_IS_LABEL (label), NULL);
5504
5505   priv = label->priv;
5506
5507   gtk_label_ensure_layout (label);
5508
5509   return priv->layout;
5510 }
5511
5512 /**
5513  * gtk_label_get_layout_offsets:
5514  * @label: a #GtkLabel
5515  * @x: (out) (allow-none): location to store X offset of layout, or %NULL
5516  * @y: (out) (allow-none): location to store Y offset of layout, or %NULL
5517  *
5518  * Obtains the coordinates where the label will draw the #PangoLayout
5519  * representing the text in the label; useful to convert mouse events
5520  * into coordinates inside the #PangoLayout, e.g. to take some action
5521  * if some part of the label is clicked. Of course you will need to
5522  * create a #GtkEventBox to receive the events, and pack the label
5523  * inside it, since labels are a #GTK_NO_WINDOW widget. Remember
5524  * when using the #PangoLayout functions you need to convert to
5525  * and from pixels using PANGO_PIXELS() or #PANGO_SCALE.
5526  **/
5527 void
5528 gtk_label_get_layout_offsets (GtkLabel *label,
5529                               gint     *x,
5530                               gint     *y)
5531 {
5532   g_return_if_fail (GTK_IS_LABEL (label));
5533
5534   gtk_label_ensure_layout (label);
5535
5536   get_layout_location (label, x, y);
5537 }
5538
5539 /**
5540  * gtk_label_set_use_markup:
5541  * @label: a #GtkLabel
5542  * @setting: %TRUE if the label's text should be parsed for markup.
5543  *
5544  * Sets whether the text of the label contains markup in <link
5545  * linkend="PangoMarkupFormat">Pango's text markup
5546  * language</link>. See gtk_label_set_markup().
5547  **/
5548 void
5549 gtk_label_set_use_markup (GtkLabel *label,
5550                           gboolean  setting)
5551 {
5552   g_return_if_fail (GTK_IS_LABEL (label));
5553
5554   g_object_freeze_notify (G_OBJECT (label));
5555
5556   gtk_label_set_use_markup_internal (label, setting);
5557   gtk_label_recalculate (label);
5558
5559   g_object_thaw_notify (G_OBJECT (label));
5560 }
5561
5562 /**
5563  * gtk_label_get_use_markup:
5564  * @label: a #GtkLabel
5565  *
5566  * Returns whether the label's text is interpreted as marked up with
5567  * the <link linkend="PangoMarkupFormat">Pango text markup
5568  * language</link>. See gtk_label_set_use_markup ().
5569  *
5570  * Return value: %TRUE if the label's text will be parsed for markup.
5571  **/
5572 gboolean
5573 gtk_label_get_use_markup (GtkLabel *label)
5574 {
5575   g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
5576
5577   return label->priv->use_markup;
5578 }
5579
5580 /**
5581  * gtk_label_set_use_underline:
5582  * @label: a #GtkLabel
5583  * @setting: %TRUE if underlines in the text indicate mnemonics
5584  *
5585  * If true, an underline in the text indicates the next character should be
5586  * used for the mnemonic accelerator key.
5587  */
5588 void
5589 gtk_label_set_use_underline (GtkLabel *label,
5590                              gboolean  setting)
5591 {
5592   g_return_if_fail (GTK_IS_LABEL (label));
5593
5594   g_object_freeze_notify (G_OBJECT (label));
5595
5596   gtk_label_set_use_underline_internal (label, setting);
5597   gtk_label_recalculate (label);
5598
5599   g_object_thaw_notify (G_OBJECT (label));
5600 }
5601
5602 /**
5603  * gtk_label_get_use_underline:
5604  * @label: a #GtkLabel
5605  *
5606  * Returns whether an embedded underline in the label indicates a
5607  * mnemonic. See gtk_label_set_use_underline().
5608  *
5609  * Return value: %TRUE whether an embedded underline in the label indicates
5610  *               the mnemonic accelerator keys.
5611  **/
5612 gboolean
5613 gtk_label_get_use_underline (GtkLabel *label)
5614 {
5615   g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
5616
5617   return label->priv->use_underline;
5618 }
5619
5620 /**
5621  * gtk_label_set_single_line_mode:
5622  * @label: a #GtkLabel
5623  * @single_line_mode: %TRUE if the label should be in single line mode
5624  *
5625  * Sets whether the label is in single line mode.
5626  *
5627  * Since: 2.6
5628  */
5629 void
5630 gtk_label_set_single_line_mode (GtkLabel *label,
5631                                 gboolean single_line_mode)
5632 {
5633   GtkLabelPrivate *priv;
5634
5635   g_return_if_fail (GTK_IS_LABEL (label));
5636
5637   priv = label->priv;
5638
5639   single_line_mode = single_line_mode != FALSE;
5640
5641   if (priv->single_line_mode != single_line_mode)
5642     {
5643       priv->single_line_mode = single_line_mode;
5644
5645       gtk_label_clear_layout (label);
5646       gtk_widget_queue_resize (GTK_WIDGET (label));
5647
5648       g_object_notify (G_OBJECT (label), "single-line-mode");
5649     }
5650 }
5651
5652 /**
5653  * gtk_label_get_single_line_mode:
5654  * @label: a #GtkLabel
5655  *
5656  * Returns whether the label is in single line mode.
5657  *
5658  * Return value: %TRUE when the label is in single line mode.
5659  *
5660  * Since: 2.6
5661  **/
5662 gboolean
5663 gtk_label_get_single_line_mode  (GtkLabel *label)
5664 {
5665   g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
5666
5667   return label->priv->single_line_mode;
5668 }
5669
5670 /* Compute the X position for an offset that corresponds to the "more important
5671  * cursor position for that offset. We use this when trying to guess to which
5672  * end of the selection we should go to when the user hits the left or
5673  * right arrow key.
5674  */
5675 static void
5676 get_better_cursor (GtkLabel *label,
5677                    gint      index,
5678                    gint      *x,
5679                    gint      *y)
5680 {
5681   GtkLabelPrivate *priv = label->priv;
5682   GdkKeymap *keymap = gdk_keymap_get_for_display (gtk_widget_get_display (GTK_WIDGET (label)));
5683   PangoDirection keymap_direction = gdk_keymap_get_direction (keymap);
5684   PangoDirection cursor_direction = get_cursor_direction (label);
5685   gboolean split_cursor;
5686   PangoRectangle strong_pos, weak_pos;
5687   
5688   g_object_get (gtk_widget_get_settings (GTK_WIDGET (label)),
5689                 "gtk-split-cursor", &split_cursor,
5690                 NULL);
5691
5692   gtk_label_ensure_layout (label);
5693   
5694   pango_layout_get_cursor_pos (priv->layout, index,
5695                                &strong_pos, &weak_pos);
5696
5697   if (split_cursor)
5698     {
5699       *x = strong_pos.x / PANGO_SCALE;
5700       *y = strong_pos.y / PANGO_SCALE;
5701     }
5702   else
5703     {
5704       if (keymap_direction == cursor_direction)
5705         {
5706           *x = strong_pos.x / PANGO_SCALE;
5707           *y = strong_pos.y / PANGO_SCALE;
5708         }
5709       else
5710         {
5711           *x = weak_pos.x / PANGO_SCALE;
5712           *y = weak_pos.y / PANGO_SCALE;
5713         }
5714     }
5715 }
5716
5717
5718 static gint
5719 gtk_label_move_logically (GtkLabel *label,
5720                           gint      start,
5721                           gint      count)
5722 {
5723   GtkLabelPrivate *priv = label->priv;
5724   gint offset = g_utf8_pointer_to_offset (priv->text,
5725                                           priv->text + start);
5726
5727   if (priv->text)
5728     {
5729       PangoLogAttr *log_attrs;
5730       gint n_attrs;
5731       gint length;
5732
5733       gtk_label_ensure_layout (label);
5734       
5735       length = g_utf8_strlen (priv->text, -1);
5736
5737       pango_layout_get_log_attrs (priv->layout, &log_attrs, &n_attrs);
5738
5739       while (count > 0 && offset < length)
5740         {
5741           do
5742             offset++;
5743           while (offset < length && !log_attrs[offset].is_cursor_position);
5744           
5745           count--;
5746         }
5747       while (count < 0 && offset > 0)
5748         {
5749           do
5750             offset--;
5751           while (offset > 0 && !log_attrs[offset].is_cursor_position);
5752           
5753           count++;
5754         }
5755       
5756       g_free (log_attrs);
5757     }
5758
5759   return g_utf8_offset_to_pointer (priv->text, offset) - priv->text;
5760 }
5761
5762 static gint
5763 gtk_label_move_visually (GtkLabel *label,
5764                          gint      start,
5765                          gint      count)
5766 {
5767   GtkLabelPrivate *priv = label->priv;
5768   gint index;
5769
5770   index = start;
5771   
5772   while (count != 0)
5773     {
5774       int new_index, new_trailing;
5775       gboolean split_cursor;
5776       gboolean strong;
5777
5778       gtk_label_ensure_layout (label);
5779
5780       g_object_get (gtk_widget_get_settings (GTK_WIDGET (label)),
5781                     "gtk-split-cursor", &split_cursor,
5782                     NULL);
5783
5784       if (split_cursor)
5785         strong = TRUE;
5786       else
5787         {
5788           GdkKeymap *keymap = gdk_keymap_get_for_display (gtk_widget_get_display (GTK_WIDGET (label)));
5789           PangoDirection keymap_direction = gdk_keymap_get_direction (keymap);
5790
5791           strong = keymap_direction == get_cursor_direction (label);
5792         }
5793       
5794       if (count > 0)
5795         {
5796           pango_layout_move_cursor_visually (priv->layout, strong, index, 0, 1, &new_index, &new_trailing);
5797           count--;
5798         }
5799       else
5800         {
5801           pango_layout_move_cursor_visually (priv->layout, strong, index, 0, -1, &new_index, &new_trailing);
5802           count++;
5803         }
5804
5805       if (new_index < 0 || new_index == G_MAXINT)
5806         break;
5807
5808       index = new_index;
5809       
5810       while (new_trailing--)
5811         index = g_utf8_next_char (priv->text + new_index) - priv->text;
5812     }
5813   
5814   return index;
5815 }
5816
5817 static gint
5818 gtk_label_move_forward_word (GtkLabel *label,
5819                              gint      start)
5820 {
5821   GtkLabelPrivate *priv = label->priv;
5822   gint new_pos = g_utf8_pointer_to_offset (priv->text,
5823                                            priv->text + start);
5824   gint length;
5825
5826   length = g_utf8_strlen (priv->text, -1);
5827   if (new_pos < length)
5828     {
5829       PangoLogAttr *log_attrs;
5830       gint n_attrs;
5831
5832       gtk_label_ensure_layout (label);
5833
5834       pango_layout_get_log_attrs (priv->layout, &log_attrs, &n_attrs);
5835
5836       /* Find the next word end */
5837       new_pos++;
5838       while (new_pos < n_attrs && !log_attrs[new_pos].is_word_end)
5839         new_pos++;
5840
5841       g_free (log_attrs);
5842     }
5843
5844   return g_utf8_offset_to_pointer (priv->text, new_pos) - priv->text;
5845 }
5846
5847
5848 static gint
5849 gtk_label_move_backward_word (GtkLabel *label,
5850                               gint      start)
5851 {
5852   GtkLabelPrivate *priv = label->priv;
5853   gint new_pos = g_utf8_pointer_to_offset (priv->text,
5854                                            priv->text + start);
5855
5856   if (new_pos > 0)
5857     {
5858       PangoLogAttr *log_attrs;
5859       gint n_attrs;
5860
5861       gtk_label_ensure_layout (label);
5862
5863       pango_layout_get_log_attrs (priv->layout, &log_attrs, &n_attrs);
5864
5865       new_pos -= 1;
5866
5867       /* Find the previous word beginning */
5868       while (new_pos > 0 && !log_attrs[new_pos].is_word_start)
5869         new_pos--;
5870
5871       g_free (log_attrs);
5872     }
5873
5874   return g_utf8_offset_to_pointer (priv->text, new_pos) - priv->text;
5875 }
5876
5877 static void
5878 gtk_label_move_cursor (GtkLabel       *label,
5879                        GtkMovementStep step,
5880                        gint            count,
5881                        gboolean        extend_selection)
5882 {
5883   GtkLabelPrivate *priv = label->priv;
5884   gint old_pos;
5885   gint new_pos;
5886
5887   if (priv->select_info == NULL)
5888     return;
5889
5890   old_pos = new_pos = priv->select_info->selection_end;
5891
5892   if (priv->select_info->selection_end != priv->select_info->selection_anchor &&
5893       !extend_selection)
5894     {
5895       /* If we have a current selection and aren't extending it, move to the
5896        * start/or end of the selection as appropriate
5897        */
5898       switch (step)
5899         {
5900         case GTK_MOVEMENT_VISUAL_POSITIONS:
5901           {
5902             gint end_x, end_y;
5903             gint anchor_x, anchor_y;
5904             gboolean end_is_left;
5905
5906             get_better_cursor (label, priv->select_info->selection_end, &end_x, &end_y);
5907             get_better_cursor (label, priv->select_info->selection_anchor, &anchor_x, &anchor_y);
5908
5909             end_is_left = (end_y < anchor_y) || (end_y == anchor_y && end_x < anchor_x);
5910
5911             if (count < 0)
5912               new_pos = end_is_left ? priv->select_info->selection_end : priv->select_info->selection_anchor;
5913             else
5914               new_pos = !end_is_left ? priv->select_info->selection_end : priv->select_info->selection_anchor;
5915             break;
5916           }
5917         case GTK_MOVEMENT_LOGICAL_POSITIONS:
5918         case GTK_MOVEMENT_WORDS:
5919           if (count < 0)
5920             new_pos = MIN (priv->select_info->selection_end, priv->select_info->selection_anchor);
5921           else
5922             new_pos = MAX (priv->select_info->selection_end, priv->select_info->selection_anchor);
5923           break;
5924         case GTK_MOVEMENT_DISPLAY_LINE_ENDS:
5925         case GTK_MOVEMENT_PARAGRAPH_ENDS:
5926         case GTK_MOVEMENT_BUFFER_ENDS:
5927           /* FIXME: Can do better here */
5928           new_pos = count < 0 ? 0 : strlen (priv->text);
5929           break;
5930         case GTK_MOVEMENT_DISPLAY_LINES:
5931         case GTK_MOVEMENT_PARAGRAPHS:
5932         case GTK_MOVEMENT_PAGES:
5933         case GTK_MOVEMENT_HORIZONTAL_PAGES:
5934           break;
5935         }
5936     }
5937   else
5938     {
5939       switch (step)
5940         {
5941         case GTK_MOVEMENT_LOGICAL_POSITIONS:
5942           new_pos = gtk_label_move_logically (label, new_pos, count);
5943           break;
5944         case GTK_MOVEMENT_VISUAL_POSITIONS:
5945           new_pos = gtk_label_move_visually (label, new_pos, count);
5946           if (new_pos == old_pos)
5947             {
5948               if (!extend_selection)
5949                 {
5950                   if (!gtk_widget_keynav_failed (GTK_WIDGET (label),
5951                                                  count > 0 ?
5952                                                  GTK_DIR_RIGHT : GTK_DIR_LEFT))
5953                     {
5954                       GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (label));
5955
5956                       if (toplevel)
5957                         gtk_widget_child_focus (toplevel,
5958                                                 count > 0 ?
5959                                                 GTK_DIR_RIGHT : GTK_DIR_LEFT);
5960                     }
5961                 }
5962               else
5963                 {
5964                   gtk_widget_error_bell (GTK_WIDGET (label));
5965                 }
5966             }
5967           break;
5968         case GTK_MOVEMENT_WORDS:
5969           while (count > 0)
5970             {
5971               new_pos = gtk_label_move_forward_word (label, new_pos);
5972               count--;
5973             }
5974           while (count < 0)
5975             {
5976               new_pos = gtk_label_move_backward_word (label, new_pos);
5977               count++;
5978             }
5979           if (new_pos == old_pos)
5980             gtk_widget_error_bell (GTK_WIDGET (label));
5981           break;
5982         case GTK_MOVEMENT_DISPLAY_LINE_ENDS:
5983         case GTK_MOVEMENT_PARAGRAPH_ENDS:
5984         case GTK_MOVEMENT_BUFFER_ENDS:
5985           /* FIXME: Can do better here */
5986           new_pos = count < 0 ? 0 : strlen (priv->text);
5987           if (new_pos == old_pos)
5988             gtk_widget_error_bell (GTK_WIDGET (label));
5989           break;
5990         case GTK_MOVEMENT_DISPLAY_LINES:
5991         case GTK_MOVEMENT_PARAGRAPHS:
5992         case GTK_MOVEMENT_PAGES:
5993         case GTK_MOVEMENT_HORIZONTAL_PAGES:
5994           break;
5995         }
5996     }
5997
5998   if (extend_selection)
5999     gtk_label_select_region_index (label,
6000                                    priv->select_info->selection_anchor,
6001                                    new_pos);
6002   else
6003     gtk_label_select_region_index (label, new_pos, new_pos);
6004 }
6005
6006 static void
6007 gtk_label_copy_clipboard (GtkLabel *label)
6008 {
6009   GtkLabelPrivate *priv = label->priv;
6010
6011   if (priv->text && priv->select_info)
6012     {
6013       gint start, end;
6014       gint len;
6015       GtkClipboard *clipboard;
6016
6017       start = MIN (priv->select_info->selection_anchor,
6018                    priv->select_info->selection_end);
6019       end = MAX (priv->select_info->selection_anchor,
6020                  priv->select_info->selection_end);
6021
6022       len = strlen (priv->text);
6023
6024       if (end > len)
6025         end = len;
6026
6027       if (start > len)
6028         start = len;
6029
6030       clipboard = gtk_widget_get_clipboard (GTK_WIDGET (label), GDK_SELECTION_CLIPBOARD);
6031
6032       if (start != end)
6033         gtk_clipboard_set_text (clipboard, priv->text + start, end - start);
6034       else
6035         {
6036           GtkLabelLink *link;
6037
6038           link = gtk_label_get_focus_link (label);
6039           if (link)
6040             gtk_clipboard_set_text (clipboard, link->uri, -1);
6041         }
6042     }
6043 }
6044
6045 static void
6046 gtk_label_select_all (GtkLabel *label)
6047 {
6048   GtkLabelPrivate *priv = label->priv;
6049
6050   gtk_label_select_region_index (label, 0, strlen (priv->text));
6051 }
6052
6053 /* Quick hack of a popup menu
6054  */
6055 static void
6056 activate_cb (GtkWidget *menuitem,
6057              GtkLabel  *label)
6058 {
6059   const gchar *signal = g_object_get_data (G_OBJECT (menuitem), "gtk-signal");
6060   g_signal_emit_by_name (label, signal);
6061 }
6062
6063 static void
6064 append_action_signal (GtkLabel     *label,
6065                       GtkWidget    *menu,
6066                       const gchar  *stock_id,
6067                       const gchar  *signal,
6068                       gboolean      sensitive)
6069 {
6070   GtkWidget *menuitem = gtk_image_menu_item_new_from_stock (stock_id, NULL);
6071
6072   g_object_set_data (G_OBJECT (menuitem), I_("gtk-signal"), (char *)signal);
6073   g_signal_connect (menuitem, "activate",
6074                     G_CALLBACK (activate_cb), label);
6075
6076   gtk_widget_set_sensitive (menuitem, sensitive);
6077   
6078   gtk_widget_show (menuitem);
6079   gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
6080 }
6081
6082 static void
6083 popup_menu_detach (GtkWidget *attach_widget,
6084                    GtkMenu   *menu)
6085 {
6086   GtkLabel *label = GTK_LABEL (attach_widget);
6087   GtkLabelPrivate *priv = label->priv;
6088
6089   if (priv->select_info)
6090     priv->select_info->popup_menu = NULL;
6091 }
6092
6093 static void
6094 popup_position_func (GtkMenu   *menu,
6095                      gint      *x,
6096                      gint      *y,
6097                      gboolean  *push_in,
6098                      gpointer   user_data)
6099 {
6100   GtkLabel *label;
6101   GtkWidget *widget;
6102   GtkAllocation allocation;
6103   GtkRequisition req;
6104   GdkScreen *screen;
6105
6106   label = GTK_LABEL (user_data);
6107   widget = GTK_WIDGET (label);
6108
6109   g_return_if_fail (gtk_widget_get_realized (widget));
6110
6111   screen = gtk_widget_get_screen (widget);
6112   gdk_window_get_origin (gtk_widget_get_window (widget), x, y);
6113
6114   gtk_widget_get_allocation (widget, &allocation);
6115
6116   *x += allocation.x;
6117   *y += allocation.y;
6118
6119   gtk_widget_get_preferred_size (GTK_WIDGET (menu),
6120                                  &req, NULL);
6121
6122   gtk_widget_get_allocation (widget, &allocation);
6123
6124   *x += allocation.width / 2;
6125   *y += allocation.height;
6126
6127   *x = CLAMP (*x, 0, MAX (0, gdk_screen_get_width (screen) - req.width));
6128   *y = CLAMP (*y, 0, MAX (0, gdk_screen_get_height (screen) - req.height));
6129 }
6130
6131 static void
6132 open_link_activate_cb (GtkMenuItem *menu_item,
6133                        GtkLabel    *label)
6134 {
6135   GtkLabelLink *link;
6136
6137   link = gtk_label_get_current_link (label);
6138
6139   if (link)
6140     emit_activate_link (label, link);
6141 }
6142
6143 static void
6144 copy_link_activate_cb (GtkMenuItem *menu_item,
6145                        GtkLabel    *label)
6146 {
6147   GtkClipboard *clipboard;
6148   const gchar *uri;
6149
6150   uri = gtk_label_get_current_uri (label);
6151   if (uri)
6152     {
6153       clipboard = gtk_widget_get_clipboard (GTK_WIDGET (label), GDK_SELECTION_CLIPBOARD);
6154       gtk_clipboard_set_text (clipboard, uri, -1);
6155     }
6156 }
6157
6158 static gboolean
6159 gtk_label_popup_menu (GtkWidget *widget)
6160 {
6161   gtk_label_do_popup (GTK_LABEL (widget), NULL);
6162
6163   return TRUE;
6164 }
6165
6166 static void
6167 gtk_label_do_popup (GtkLabel       *label,
6168                     GdkEventButton *event)
6169 {
6170   GtkLabelPrivate *priv = label->priv;
6171   GtkWidget *menuitem;
6172   GtkWidget *menu;
6173   GtkWidget *image;
6174   gboolean have_selection;
6175   GtkLabelLink *link;
6176
6177   if (!priv->select_info)
6178     return;
6179
6180   if (priv->select_info->popup_menu)
6181     gtk_widget_destroy (priv->select_info->popup_menu);
6182
6183   priv->select_info->popup_menu = menu = gtk_menu_new ();
6184
6185   gtk_menu_attach_to_widget (GTK_MENU (menu), GTK_WIDGET (label), popup_menu_detach);
6186
6187   have_selection =
6188     priv->select_info->selection_anchor != priv->select_info->selection_end;
6189
6190   if (event)
6191     {
6192       if (priv->select_info->link_clicked)
6193         link = priv->select_info->active_link;
6194       else
6195         link = NULL;
6196     }
6197   else
6198     link = gtk_label_get_focus_link (label);
6199
6200   if (!have_selection && link)
6201     {
6202       /* Open Link */
6203       menuitem = gtk_image_menu_item_new_with_mnemonic (_("_Open Link"));
6204       gtk_widget_show (menuitem);
6205       gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
6206
6207       g_signal_connect (G_OBJECT (menuitem), "activate",
6208                         G_CALLBACK (open_link_activate_cb), label);
6209
6210       image = gtk_image_new_from_stock (GTK_STOCK_JUMP_TO, GTK_ICON_SIZE_MENU);
6211       gtk_widget_show (image);
6212       gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem), image);
6213
6214       /* Copy Link Address */
6215       menuitem = gtk_image_menu_item_new_with_mnemonic (_("Copy _Link Address"));
6216       gtk_widget_show (menuitem);
6217       gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
6218
6219       g_signal_connect (G_OBJECT (menuitem), "activate",
6220                         G_CALLBACK (copy_link_activate_cb), label);
6221
6222       image = gtk_image_new_from_stock (GTK_STOCK_COPY, GTK_ICON_SIZE_MENU);
6223       gtk_widget_show (image);
6224       gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem), image);
6225     }
6226   else
6227     {
6228       append_action_signal (label, menu, GTK_STOCK_CUT, "cut-clipboard", FALSE);
6229       append_action_signal (label, menu, GTK_STOCK_COPY, "copy-clipboard", have_selection);
6230       append_action_signal (label, menu, GTK_STOCK_PASTE, "paste-clipboard", FALSE);
6231   
6232       menuitem = gtk_image_menu_item_new_from_stock (GTK_STOCK_DELETE, NULL);
6233       gtk_widget_set_sensitive (menuitem, FALSE);
6234       gtk_widget_show (menuitem);
6235       gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
6236
6237       menuitem = gtk_separator_menu_item_new ();
6238       gtk_widget_show (menuitem);
6239       gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
6240
6241       menuitem = gtk_image_menu_item_new_from_stock (GTK_STOCK_SELECT_ALL, NULL);
6242       g_signal_connect_swapped (menuitem, "activate",
6243                                 G_CALLBACK (gtk_label_select_all), label);
6244       gtk_widget_show (menuitem);
6245       gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
6246     }
6247
6248   g_signal_emit (label, signals[POPULATE_POPUP], 0, menu);
6249
6250   if (event)
6251     gtk_menu_popup (GTK_MENU (menu), NULL, NULL,
6252                     NULL, NULL,
6253                     event->button, event->time);
6254   else
6255     {
6256       gtk_menu_popup (GTK_MENU (menu), NULL, NULL,
6257                       popup_position_func, label,
6258                       0, gtk_get_current_event_time ());
6259       gtk_menu_shell_select_first (GTK_MENU_SHELL (menu), FALSE);
6260     }
6261 }
6262
6263 static void
6264 gtk_label_clear_links (GtkLabel *label)
6265 {
6266   GtkLabelPrivate *priv = label->priv;
6267
6268   if (!priv->select_info)
6269     return;
6270
6271   g_list_free_full (priv->select_info->links, (GDestroyNotify) link_free);
6272   priv->select_info->links = NULL;
6273   priv->select_info->active_link = NULL;
6274 }
6275
6276 static gboolean
6277 gtk_label_activate_link (GtkLabel    *label,
6278                          const gchar *uri)
6279 {
6280   GtkWidget *widget = GTK_WIDGET (label);
6281   GError *error = NULL;
6282
6283   if (!gtk_show_uri (gtk_widget_get_screen (widget),
6284                      uri, gtk_get_current_event_time (), &error))
6285     {
6286       g_warning ("Unable to show '%s': %s", uri, error->message);
6287       g_error_free (error);
6288     }
6289
6290   return TRUE;
6291 }
6292
6293 static void
6294 emit_activate_link (GtkLabel     *label,
6295                     GtkLabelLink *link)
6296 {
6297   GtkLabelPrivate *priv = label->priv;
6298   gboolean handled;
6299
6300   g_signal_emit (label, signals[ACTIVATE_LINK], 0, link->uri, &handled);
6301   if (handled && priv->track_links && !link->visited)
6302     {
6303       link->visited = TRUE;
6304       /* FIXME: shouldn't have to redo everything here */
6305       gtk_label_recalculate (label);
6306     }
6307 }
6308
6309 static void
6310 gtk_label_activate_current_link (GtkLabel *label)
6311 {
6312   GtkLabelLink *link;
6313   GtkWidget *widget = GTK_WIDGET (label);
6314
6315   link = gtk_label_get_focus_link (label);
6316
6317   if (link)
6318     {
6319       emit_activate_link (label, link);
6320     }
6321   else
6322     {
6323       GtkWidget *toplevel;
6324       GtkWindow *window;
6325       GtkWidget *default_widget, *focus_widget;
6326
6327       toplevel = gtk_widget_get_toplevel (widget);
6328       if (GTK_IS_WINDOW (toplevel))
6329         {
6330           window = GTK_WINDOW (toplevel);
6331
6332           if (window)
6333             {
6334               default_widget = gtk_window_get_default_widget (window);
6335               focus_widget = gtk_window_get_focus (window);
6336
6337               if (default_widget != widget &&
6338                   !(widget == focus_widget && (!default_widget || !gtk_widget_is_sensitive (default_widget))))
6339                 gtk_window_activate_default (window);
6340             }
6341         }
6342     }
6343 }
6344
6345 static GtkLabelLink *
6346 gtk_label_get_current_link (GtkLabel *label)
6347 {
6348   GtkLabelPrivate *priv = label->priv;
6349   GtkLabelLink *link;
6350
6351   if (!priv->select_info)
6352     return NULL;
6353
6354   if (priv->select_info->link_clicked)
6355     link = priv->select_info->active_link;
6356   else
6357     link = gtk_label_get_focus_link (label);
6358
6359   return link;
6360 }
6361
6362 /**
6363  * gtk_label_get_current_uri:
6364  * @label: a #GtkLabel
6365  *
6366  * Returns the URI for the currently active link in the label.
6367  * The active link is the one under the mouse pointer or, in a
6368  * selectable label, the link in which the text cursor is currently
6369  * positioned.
6370  *
6371  * This function is intended for use in a #GtkLabel::activate-link handler
6372  * or for use in a #GtkWidget::query-tooltip handler.
6373  *
6374  * Returns: the currently active URI. The string is owned by GTK+ and must
6375  *   not be freed or modified.
6376  *
6377  * Since: 2.18
6378  */
6379 const gchar *
6380 gtk_label_get_current_uri (GtkLabel *label)
6381 {
6382   GtkLabelLink *link;
6383
6384   g_return_val_if_fail (GTK_IS_LABEL (label), NULL);
6385
6386   link = gtk_label_get_current_link (label);
6387
6388   if (link)
6389     return link->uri;
6390
6391   return NULL;
6392 }
6393
6394 /**
6395  * gtk_label_set_track_visited_links:
6396  * @label: a #GtkLabel
6397  * @track_links: %TRUE to track visited links
6398  *
6399  * Sets whether the label should keep track of clicked
6400  * links (and use a different color for them).
6401  *
6402  * Since: 2.18
6403  */
6404 void
6405 gtk_label_set_track_visited_links (GtkLabel *label,
6406                                    gboolean  track_links)
6407 {
6408   GtkLabelPrivate *priv;
6409
6410   g_return_if_fail (GTK_IS_LABEL (label));
6411
6412   priv = label->priv;
6413
6414   track_links = track_links != FALSE;
6415
6416   if (priv->track_links != track_links)
6417     {
6418       priv->track_links = track_links;
6419
6420       /* FIXME: shouldn't have to redo everything here */
6421       gtk_label_recalculate (label);
6422
6423       g_object_notify (G_OBJECT (label), "track-visited-links");
6424     }
6425 }
6426
6427 /**
6428  * gtk_label_get_track_visited_links:
6429  * @label: a #GtkLabel
6430  *
6431  * Returns whether the label is currently keeping track
6432  * of clicked links.
6433  *
6434  * Returns: %TRUE if clicked links are remembered
6435  *
6436  * Since: 2.18
6437  */
6438 gboolean
6439 gtk_label_get_track_visited_links (GtkLabel *label)
6440 {
6441   g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
6442
6443   return label->priv->track_links;
6444 }
6445
6446 static gboolean
6447 gtk_label_query_tooltip (GtkWidget  *widget,
6448                          gint        x,
6449                          gint        y,
6450                          gboolean    keyboard_tip,
6451                          GtkTooltip *tooltip)
6452 {
6453   GtkLabel *label = GTK_LABEL (widget);
6454   GtkLabelPrivate *priv = label->priv;
6455   GtkLabelSelectionInfo *info = priv->select_info;
6456   gint index = -1;
6457   GList *l;
6458
6459   if (info && info->links)
6460     {
6461       if (keyboard_tip)
6462         {
6463           if (info->selection_anchor == info->selection_end)
6464             index = info->selection_anchor;
6465         }
6466       else
6467         {
6468           if (!get_layout_index (label, x, y, &index))
6469             index = -1;
6470         }
6471
6472       if (index != -1)
6473         {
6474           for (l = info->links; l != NULL; l = l->next)
6475             {
6476               GtkLabelLink *link = l->data;
6477               if (index >= link->start && index <= link->end)
6478                 {
6479                   if (link->title)
6480                     {
6481                       gtk_tooltip_set_markup (tooltip, link->title);
6482                       return TRUE;
6483                     }
6484                   break;
6485                 }
6486             }
6487         }
6488     }
6489
6490   return GTK_WIDGET_CLASS (gtk_label_parent_class)->query_tooltip (widget,
6491                                                                    x, y,
6492                                                                    keyboard_tip,
6493                                                                    tooltip);
6494 }
6495
6496 gint
6497 _gtk_label_get_cursor_position (GtkLabel *label)
6498 {
6499   GtkLabelPrivate *priv = label->priv;
6500
6501   if (priv->select_info && priv->select_info->selectable)
6502     return g_utf8_pointer_to_offset (priv->text,
6503                                      priv->text + priv->select_info->selection_end);
6504
6505   return 0;
6506 }
6507
6508 gint
6509 _gtk_label_get_selection_bound (GtkLabel *label)
6510 {
6511   GtkLabelPrivate *priv = label->priv;
6512
6513   if (priv->select_info && priv->select_info->selectable)
6514     return g_utf8_pointer_to_offset (priv->text,
6515                                      priv->text + priv->select_info->selection_anchor);
6516
6517   return 0;
6518 }