]> Pileus Git - ~andy/gtk/blob - gtk/gtklabel.c
label: Redo attribute application
[~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 (from);
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 (into, 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 /* Calculates text, attrs and mnemonic_keyval from
2065  * label, use_underline and use_markup
2066  */
2067 static void
2068 gtk_label_recalculate (GtkLabel *label)
2069 {
2070   GtkLabelPrivate *priv = label->priv;
2071   guint keyval = priv->mnemonic_keyval;
2072
2073   gtk_label_clear_links (label);
2074
2075   if (priv->use_markup)
2076     gtk_label_set_markup_internal (label, priv->label, priv->use_underline);
2077   else if (priv->use_underline)
2078     gtk_label_set_uline_text_internal (label, priv->label);
2079   else
2080     {
2081       if (!priv->pattern_set)
2082         {
2083           if (priv->effective_attrs)
2084             pango_attr_list_unref (priv->effective_attrs);
2085           priv->effective_attrs = NULL;
2086         }
2087       gtk_label_set_text_internal (label, g_strdup (priv->label));
2088     }
2089
2090   if (!priv->use_underline)
2091     priv->mnemonic_keyval = GDK_KEY_VoidSymbol;
2092
2093   if (keyval != priv->mnemonic_keyval)
2094     {
2095       gtk_label_setup_mnemonic (label, keyval);
2096       g_object_notify (G_OBJECT (label), "mnemonic-keyval");
2097     }
2098
2099   gtk_label_clear_layout (label);
2100   gtk_label_clear_select_info (label);
2101   gtk_widget_queue_resize (GTK_WIDGET (label));
2102 }
2103
2104 /**
2105  * gtk_label_set_text:
2106  * @label: a #GtkLabel
2107  * @str: The text you want to set
2108  *
2109  * Sets the text within the #GtkLabel widget. It overwrites any text that
2110  * was there before.  
2111  *
2112  * This will also clear any previously set mnemonic accelerators.
2113  **/
2114 void
2115 gtk_label_set_text (GtkLabel    *label,
2116                     const gchar *str)
2117 {
2118   g_return_if_fail (GTK_IS_LABEL (label));
2119   
2120   g_object_freeze_notify (G_OBJECT (label));
2121
2122   gtk_label_set_label_internal (label, g_strdup (str ? str : ""));
2123   gtk_label_set_use_markup_internal (label, FALSE);
2124   gtk_label_set_use_underline_internal (label, FALSE);
2125   
2126   gtk_label_recalculate (label);
2127
2128   g_object_thaw_notify (G_OBJECT (label));
2129 }
2130
2131 /**
2132  * gtk_label_set_attributes:
2133  * @label: a #GtkLabel
2134  * @attrs: a #PangoAttrList
2135  * 
2136  * Sets a #PangoAttrList; the attributes in the list are applied to the
2137  * label text. 
2138  *
2139  * <note><para>The attributes set with this function will be applied
2140  * and merged with any other attributes previously effected by way
2141  * of the #GtkLabel:use-underline or #GtkLabel:use-markup properties.
2142  * While it is not recommended to mix markup strings with manually set
2143  * attributes, if you must; know that the attributes will be applied
2144  * to the label after the markup string is parsed.</para></note>
2145  **/
2146 void
2147 gtk_label_set_attributes (GtkLabel         *label,
2148                           PangoAttrList    *attrs)
2149 {
2150   GtkLabelPrivate *priv = label->priv;
2151
2152   g_return_if_fail (GTK_IS_LABEL (label));
2153
2154   if (attrs)
2155     pango_attr_list_ref (attrs);
2156
2157   if (priv->attrs)
2158     pango_attr_list_unref (priv->attrs);
2159   priv->attrs = attrs;
2160
2161   g_object_notify (G_OBJECT (label), "attributes");
2162
2163   gtk_label_recalculate (label);
2164
2165   gtk_label_clear_layout (label);
2166   gtk_widget_queue_resize (GTK_WIDGET (label));
2167 }
2168
2169 /**
2170  * gtk_label_get_attributes:
2171  * @label: a #GtkLabel
2172  *
2173  * Gets the attribute list that was set on the label using
2174  * gtk_label_set_attributes(), if any. This function does
2175  * not reflect attributes that come from the labels markup
2176  * (see gtk_label_set_markup()). If you want to get the
2177  * effective attributes for the label, use
2178  * pango_layout_get_attribute (gtk_label_get_layout (label)).
2179  *
2180  * Return value: (transfer none): the attribute list, or %NULL
2181  *     if none was set.
2182  **/
2183 PangoAttrList *
2184 gtk_label_get_attributes (GtkLabel *label)
2185 {
2186   g_return_val_if_fail (GTK_IS_LABEL (label), NULL);
2187
2188   return label->priv->attrs;
2189 }
2190
2191 /**
2192  * gtk_label_set_label:
2193  * @label: a #GtkLabel
2194  * @str: the new text to set for the label
2195  *
2196  * Sets the text of the label. The label is interpreted as
2197  * including embedded underlines and/or Pango markup depending
2198  * on the values of the #GtkLabel:use-underline" and
2199  * #GtkLabel:use-markup properties.
2200  **/
2201 void
2202 gtk_label_set_label (GtkLabel    *label,
2203                      const gchar *str)
2204 {
2205   g_return_if_fail (GTK_IS_LABEL (label));
2206
2207   g_object_freeze_notify (G_OBJECT (label));
2208
2209   gtk_label_set_label_internal (label, g_strdup (str ? str : ""));
2210   gtk_label_recalculate (label);
2211
2212   g_object_thaw_notify (G_OBJECT (label));
2213 }
2214
2215 /**
2216  * gtk_label_get_label:
2217  * @label: a #GtkLabel
2218  *
2219  * Fetches the text from a label widget including any embedded
2220  * underlines indicating mnemonics and Pango markup. (See
2221  * gtk_label_get_text()).
2222  *
2223  * Return value: the text of the label widget. This string is
2224  *   owned by the widget and must not be modified or freed.
2225  **/
2226 const gchar *
2227 gtk_label_get_label (GtkLabel *label)
2228 {
2229   g_return_val_if_fail (GTK_IS_LABEL (label), NULL);
2230
2231   return label->priv->label;
2232 }
2233
2234 typedef struct
2235 {
2236   GtkLabel *label;
2237   GList *links;
2238   GString *new_str;
2239   gsize text_len;
2240 } UriParserData;
2241
2242 static void
2243 start_element_handler (GMarkupParseContext  *context,
2244                        const gchar          *element_name,
2245                        const gchar         **attribute_names,
2246                        const gchar         **attribute_values,
2247                        gpointer              user_data,
2248                        GError              **error)
2249 {
2250   GtkLabelPrivate *priv;
2251   UriParserData *pdata = user_data;
2252
2253   if (strcmp (element_name, "a") == 0)
2254     {
2255       GtkLabelLink *link;
2256       const gchar *uri = NULL;
2257       const gchar *title = NULL;
2258       gboolean visited = FALSE;
2259       gint line_number;
2260       gint char_number;
2261       gint i;
2262
2263       g_markup_parse_context_get_position (context, &line_number, &char_number);
2264
2265       for (i = 0; attribute_names[i] != NULL; i++)
2266         {
2267           const gchar *attr = attribute_names[i];
2268
2269           if (strcmp (attr, "href") == 0)
2270             uri = attribute_values[i];
2271           else if (strcmp (attr, "title") == 0)
2272             title = attribute_values[i];
2273           else
2274             {
2275               g_set_error (error,
2276                            G_MARKUP_ERROR,
2277                            G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE,
2278                            "Attribute '%s' is not allowed on the <a> tag "
2279                            "on line %d char %d",
2280                             attr, line_number, char_number);
2281               return;
2282             }
2283         }
2284
2285       if (uri == NULL)
2286         {
2287           g_set_error (error,
2288                        G_MARKUP_ERROR,
2289                        G_MARKUP_ERROR_INVALID_CONTENT,
2290                        "Attribute 'href' was missing on the <a> tag "
2291                        "on line %d char %d",
2292                        line_number, char_number);
2293           return;
2294         }
2295
2296       visited = FALSE;
2297       priv = pdata->label->priv;
2298       if (priv->track_links && priv->select_info)
2299         {
2300           GList *l;
2301           for (l = priv->select_info->links; l; l = l->next)
2302             {
2303               link = l->data;
2304               if (strcmp (uri, link->uri) == 0)
2305                 {
2306                   visited = link->visited;
2307                   break;
2308                 }
2309             }
2310         }
2311
2312       link = g_new0 (GtkLabelLink, 1);
2313       link->uri = g_strdup (uri);
2314       link->title = g_strdup (title);
2315       link->visited = visited;
2316       link->start = pdata->text_len;
2317       pdata->links = g_list_prepend (pdata->links, link);
2318     }
2319   else
2320     {
2321       gint i;
2322
2323       g_string_append_c (pdata->new_str, '<');
2324       g_string_append (pdata->new_str, element_name);
2325
2326       for (i = 0; attribute_names[i] != NULL; i++)
2327         {
2328           const gchar *attr  = attribute_names[i];
2329           const gchar *value = attribute_values[i];
2330           gchar *newvalue;
2331
2332           newvalue = g_markup_escape_text (value, -1);
2333
2334           g_string_append_c (pdata->new_str, ' ');
2335           g_string_append (pdata->new_str, attr);
2336           g_string_append (pdata->new_str, "=\"");
2337           g_string_append (pdata->new_str, newvalue);
2338           g_string_append_c (pdata->new_str, '\"');
2339
2340           g_free (newvalue);
2341         }
2342       g_string_append_c (pdata->new_str, '>');
2343     }
2344 }
2345
2346 static void
2347 end_element_handler (GMarkupParseContext  *context,
2348                      const gchar          *element_name,
2349                      gpointer              user_data,
2350                      GError              **error)
2351 {
2352   UriParserData *pdata = user_data;
2353
2354   if (!strcmp (element_name, "a"))
2355     {
2356       GtkLabelLink *link = pdata->links->data;
2357       link->end = pdata->text_len;
2358     }
2359   else
2360     {
2361       g_string_append (pdata->new_str, "</");
2362       g_string_append (pdata->new_str, element_name);
2363       g_string_append_c (pdata->new_str, '>');
2364     }
2365 }
2366
2367 static void
2368 text_handler (GMarkupParseContext  *context,
2369               const gchar          *text,
2370               gsize                 text_len,
2371               gpointer              user_data,
2372               GError              **error)
2373 {
2374   UriParserData *pdata = user_data;
2375   gchar *newtext;
2376
2377   newtext = g_markup_escape_text (text, text_len);
2378   g_string_append (pdata->new_str, newtext);
2379   pdata->text_len += text_len;
2380   g_free (newtext);
2381 }
2382
2383 static const GMarkupParser markup_parser =
2384 {
2385   start_element_handler,
2386   end_element_handler,
2387   text_handler,
2388   NULL,
2389   NULL
2390 };
2391
2392 static gboolean
2393 xml_isspace (gchar c)
2394 {
2395   return (c == ' ' || c == '\t' || c == '\n' || c == '\r');
2396 }
2397
2398 static void
2399 link_free (GtkLabelLink *link)
2400 {
2401   g_free (link->uri);
2402   g_free (link->title);
2403   g_free (link);
2404 }
2405
2406 static void
2407 gtk_label_get_link_colors (GtkWidget *widget,
2408                            GdkColor  *link_color,
2409                            GdkColor  *visited_link_color)
2410 {
2411   GtkStyleContext *context;
2412   GdkColor *link, *visited;
2413
2414   context = gtk_widget_get_style_context (widget);
2415   gtk_style_context_get_style (context,
2416                                "link-color", &link,
2417                                "visited-link-color", &visited,
2418                                 NULL);
2419   if (link)
2420     {
2421       *link_color = *link;
2422       gdk_color_free (link);
2423     }
2424   else
2425     *link_color = default_link_color;
2426
2427   if (visited)
2428     {
2429       *visited_link_color = *visited;
2430       gdk_color_free (visited);
2431     }
2432   else
2433     *visited_link_color = default_visited_link_color;
2434 }
2435
2436 static gboolean
2437 parse_uri_markup (GtkLabel     *label,
2438                   const gchar  *str,
2439                   gchar       **new_str,
2440                   GList       **links,
2441                   GError      **error)
2442 {
2443   GMarkupParseContext *context = NULL;
2444   const gchar *p, *end;
2445   gboolean needs_root = TRUE;
2446   gsize length;
2447   UriParserData pdata;
2448
2449   length = strlen (str);
2450   p = str;
2451   end = str + length;
2452
2453   pdata.label = label;
2454   pdata.links = NULL;
2455   pdata.new_str = g_string_sized_new (length);
2456   pdata.text_len = 0;
2457
2458   while (p != end && xml_isspace (*p))
2459     p++;
2460
2461   if (end - p >= 8 && strncmp (p, "<markup>", 8) == 0)
2462     needs_root = FALSE;
2463
2464   context = g_markup_parse_context_new (&markup_parser, 0, &pdata, NULL);
2465
2466   if (needs_root)
2467     {
2468       if (!g_markup_parse_context_parse (context, "<markup>", -1, error))
2469         goto failed;
2470     }
2471
2472   if (!g_markup_parse_context_parse (context, str, length, error))
2473     goto failed;
2474
2475   if (needs_root)
2476     {
2477       if (!g_markup_parse_context_parse (context, "</markup>", -1, error))
2478         goto failed;
2479     }
2480
2481   if (!g_markup_parse_context_end_parse (context, error))
2482     goto failed;
2483
2484   g_markup_parse_context_free (context);
2485
2486   *new_str = g_string_free (pdata.new_str, FALSE);
2487   *links = pdata.links;
2488
2489   return TRUE;
2490
2491 failed:
2492   g_markup_parse_context_free (context);
2493   g_string_free (pdata.new_str, TRUE);
2494   g_list_free_full (pdata.links, (GDestroyNotify) link_free);
2495
2496   return FALSE;
2497 }
2498
2499 static void
2500 gtk_label_ensure_has_tooltip (GtkLabel *label)
2501 {
2502   GtkLabelPrivate *priv = label->priv;
2503   GList *l;
2504   gboolean has_tooltip = FALSE;
2505
2506   for (l = priv->select_info->links; l; l = l->next)
2507     {
2508       GtkLabelLink *link = l->data;
2509       if (link->title)
2510         {
2511           has_tooltip = TRUE;
2512           break;
2513         }
2514     }
2515
2516   gtk_widget_set_has_tooltip (GTK_WIDGET (label), has_tooltip);
2517 }
2518
2519 static void
2520 gtk_label_set_markup_internal (GtkLabel    *label,
2521                                const gchar *str,
2522                                gboolean     with_uline)
2523 {
2524   GtkLabelPrivate *priv = label->priv;
2525   gchar *text = NULL;
2526   GError *error = NULL;
2527   PangoAttrList *attrs = NULL;
2528   gunichar accel_char = 0;
2529   gchar *new_str;
2530   GList *links = NULL;
2531
2532   if (!parse_uri_markup (label, str, &new_str, &links, &error))
2533     {
2534       g_warning ("Failed to set text from markup due to error parsing markup: %s",
2535                  error->message);
2536       g_error_free (error);
2537       return;
2538     }
2539
2540   if (links)
2541     {
2542       gtk_label_ensure_select_info (label);
2543       priv->select_info->links = g_list_reverse (links);
2544       gtk_label_ensure_has_tooltip (label);
2545     }
2546
2547   if (with_uline)
2548     {
2549       gboolean enable_mnemonics;
2550       gboolean auto_mnemonics;
2551
2552       g_object_get (gtk_widget_get_settings (GTK_WIDGET (label)),
2553                     "gtk-enable-mnemonics", &enable_mnemonics,
2554                     "gtk-auto-mnemonics", &auto_mnemonics,
2555                     NULL);
2556
2557       if (!(enable_mnemonics && priv->mnemonics_visible &&
2558             (!auto_mnemonics ||
2559              (gtk_widget_is_sensitive (GTK_WIDGET (label)) &&
2560               (!priv->mnemonic_widget ||
2561                gtk_widget_is_sensitive (priv->mnemonic_widget))))))
2562         {
2563           gchar *tmp;
2564           gchar *pattern;
2565           guint key;
2566
2567           if (separate_uline_pattern (new_str, &key, &tmp, &pattern))
2568             {
2569               g_free (new_str);
2570               new_str = tmp;
2571               g_free (pattern);
2572             }
2573         }
2574     }
2575
2576   if (!pango_parse_markup (new_str,
2577                            -1,
2578                            with_uline ? '_' : 0,
2579                            &attrs,
2580                            &text,
2581                            with_uline ? &accel_char : NULL,
2582                            &error))
2583     {
2584       g_warning ("Failed to set text from markup due to error parsing markup: %s",
2585                  error->message);
2586       g_free (new_str);
2587       g_error_free (error);
2588       return;
2589     }
2590
2591   g_free (new_str);
2592
2593   if (text)
2594     gtk_label_set_text_internal (label, text);
2595
2596   if (attrs)
2597     {
2598       if (priv->effective_attrs)
2599         pango_attr_list_unref (priv->effective_attrs);
2600       priv->effective_attrs = attrs;
2601     }
2602
2603   if (accel_char != 0)
2604     priv->mnemonic_keyval = gdk_keyval_to_lower (gdk_unicode_to_keyval (accel_char));
2605   else
2606     priv->mnemonic_keyval = GDK_KEY_VoidSymbol;
2607 }
2608
2609 /**
2610  * gtk_label_set_markup:
2611  * @label: a #GtkLabel
2612  * @str: a markup string (see <link linkend="PangoMarkupFormat">Pango markup format</link>)
2613  * 
2614  * Parses @str which is marked up with the <link
2615  * linkend="PangoMarkupFormat">Pango text markup language</link>, setting the
2616  * label's text and attribute list based on the parse results. If the @str is
2617  * external data, you may need to escape it with g_markup_escape_text() or
2618  * g_markup_printf_escaped()<!-- -->:
2619  * |[
2620  * char *markup;
2621  *
2622  * markup = g_markup_printf_escaped ("&lt;span style=\"italic\"&gt;&percnt;s&lt;/span&gt;", str);
2623  * gtk_label_set_markup (GTK_LABEL (label), markup);
2624  * g_free (markup);
2625  * ]|
2626  **/
2627 void
2628 gtk_label_set_markup (GtkLabel    *label,
2629                       const gchar *str)
2630 {
2631   g_return_if_fail (GTK_IS_LABEL (label));
2632
2633   g_object_freeze_notify (G_OBJECT (label));
2634
2635   gtk_label_set_label_internal (label, g_strdup (str ? str : ""));
2636   gtk_label_set_use_markup_internal (label, TRUE);
2637   gtk_label_set_use_underline_internal (label, FALSE);
2638
2639   gtk_label_recalculate (label);
2640
2641   g_object_thaw_notify (G_OBJECT (label));
2642 }
2643
2644 /**
2645  * gtk_label_set_markup_with_mnemonic:
2646  * @label: a #GtkLabel
2647  * @str: a markup string (see
2648  *     <link linkend="PangoMarkupFormat">Pango markup format</link>)
2649  *
2650  * Parses @str which is marked up with the
2651  * <link linkend="PangoMarkupFormat">Pango text markup language</link>,
2652  * setting the label's text and attribute list based on the parse results.
2653  * If characters in @str are preceded by an underscore, they are underlined
2654  * indicating that they represent a keyboard accelerator called a mnemonic.
2655  *
2656  * The mnemonic key can be used to activate another widget, chosen
2657  * automatically, or explicitly using gtk_label_set_mnemonic_widget().
2658  */
2659 void
2660 gtk_label_set_markup_with_mnemonic (GtkLabel    *label,
2661                                     const gchar *str)
2662 {
2663   g_return_if_fail (GTK_IS_LABEL (label));
2664
2665   g_object_freeze_notify (G_OBJECT (label));
2666
2667   gtk_label_set_label_internal (label, g_strdup (str ? str : ""));
2668   gtk_label_set_use_markup_internal (label, TRUE);
2669   gtk_label_set_use_underline_internal (label, TRUE);
2670
2671   gtk_label_recalculate (label);
2672
2673   g_object_thaw_notify (G_OBJECT (label));
2674 }
2675
2676 /**
2677  * gtk_label_get_text:
2678  * @label: a #GtkLabel
2679  * 
2680  * Fetches the text from a label widget, as displayed on the
2681  * screen. This does not include any embedded underlines
2682  * indicating mnemonics or Pango markup. (See gtk_label_get_label())
2683  * 
2684  * Return value: the text in the label widget. This is the internal
2685  *   string used by the label, and must not be modified.
2686  **/
2687 const gchar *
2688 gtk_label_get_text (GtkLabel *label)
2689 {
2690   g_return_val_if_fail (GTK_IS_LABEL (label), NULL);
2691
2692   return label->priv->text;
2693 }
2694
2695 static PangoAttrList *
2696 gtk_label_pattern_to_attrs (GtkLabel      *label,
2697                             const gchar   *pattern)
2698 {
2699   GtkLabelPrivate *priv = label->priv;
2700   const char *start;
2701   const char *p = priv->text;
2702   const char *q = pattern;
2703   PangoAttrList *attrs;
2704
2705   attrs = pango_attr_list_new ();
2706
2707   while (1)
2708     {
2709       while (*p && *q && *q != '_')
2710         {
2711           p = g_utf8_next_char (p);
2712           q++;
2713         }
2714       start = p;
2715       while (*p && *q && *q == '_')
2716         {
2717           p = g_utf8_next_char (p);
2718           q++;
2719         }
2720       
2721       if (p > start)
2722         {
2723           PangoAttribute *attr = pango_attr_underline_new (PANGO_UNDERLINE_LOW);
2724           attr->start_index = start - priv->text;
2725           attr->end_index = p - priv->text;
2726           
2727           pango_attr_list_insert (attrs, attr);
2728         }
2729       else
2730         break;
2731     }
2732
2733   return attrs;
2734 }
2735
2736 static void
2737 gtk_label_set_pattern_internal (GtkLabel    *label,
2738                                 const gchar *pattern,
2739                                 gboolean     is_mnemonic)
2740 {
2741   GtkLabelPrivate *priv = label->priv;
2742   PangoAttrList *attrs;
2743   gboolean enable_mnemonics;
2744   gboolean auto_mnemonics;
2745
2746   if (priv->pattern_set)
2747     return;
2748
2749   if (is_mnemonic)
2750     {
2751       g_object_get (gtk_widget_get_settings (GTK_WIDGET (label)),
2752                     "gtk-enable-mnemonics", &enable_mnemonics,
2753                     "gtk-auto-mnemonics", &auto_mnemonics,
2754                     NULL);
2755
2756       if (enable_mnemonics && priv->mnemonics_visible && pattern &&
2757           (!auto_mnemonics ||
2758            (gtk_widget_is_sensitive (GTK_WIDGET (label)) &&
2759             (!priv->mnemonic_widget ||
2760              gtk_widget_is_sensitive (priv->mnemonic_widget)))))
2761         attrs = gtk_label_pattern_to_attrs (label, pattern);
2762       else
2763         attrs = NULL;
2764     }
2765   else
2766     attrs = gtk_label_pattern_to_attrs (label, pattern);
2767
2768   if (priv->effective_attrs)
2769     pango_attr_list_unref (priv->effective_attrs);
2770   priv->effective_attrs = attrs;
2771 }
2772
2773 /**
2774  * gtk_label_set_pattern:
2775  * @label: The #GtkLabel you want to set the pattern to.
2776  * @pattern: The pattern as described above.
2777  *
2778  * The pattern of underlines you want under the existing text within the
2779  * #GtkLabel widget.  For example if the current text of the label says
2780  * "FooBarBaz" passing a pattern of "___   ___" will underline
2781  * "Foo" and "Baz" but not "Bar".
2782  */
2783 void
2784 gtk_label_set_pattern (GtkLabel    *label,
2785                        const gchar *pattern)
2786 {
2787   GtkLabelPrivate *priv;
2788
2789   g_return_if_fail (GTK_IS_LABEL (label));
2790
2791   priv = label->priv;
2792
2793   priv->pattern_set = FALSE;
2794
2795   if (pattern)
2796     {
2797       gtk_label_set_pattern_internal (label, pattern, FALSE);
2798       priv->pattern_set = TRUE;
2799     }
2800   else
2801     gtk_label_recalculate (label);
2802
2803   gtk_label_clear_layout (label);
2804   gtk_widget_queue_resize (GTK_WIDGET (label));
2805 }
2806
2807
2808 /**
2809  * gtk_label_set_justify:
2810  * @label: a #GtkLabel
2811  * @jtype: a #GtkJustification
2812  *
2813  * Sets the alignment of the lines in the text of the label relative to
2814  * each other. %GTK_JUSTIFY_LEFT is the default value when the
2815  * widget is first created with gtk_label_new(). If you instead want
2816  * to set the alignment of the label as a whole, use
2817  * gtk_misc_set_alignment() instead. gtk_label_set_justify() has no
2818  * effect on labels containing only a single line.
2819  **/
2820 void
2821 gtk_label_set_justify (GtkLabel        *label,
2822                        GtkJustification jtype)
2823 {
2824   GtkLabelPrivate *priv;
2825
2826   g_return_if_fail (GTK_IS_LABEL (label));
2827   g_return_if_fail (jtype >= GTK_JUSTIFY_LEFT && jtype <= GTK_JUSTIFY_FILL);
2828
2829   priv = label->priv;
2830
2831   if ((GtkJustification) priv->jtype != jtype)
2832     {
2833       priv->jtype = jtype;
2834
2835       /* No real need to be this drastic, but easier than duplicating the code */
2836       gtk_label_clear_layout (label);
2837       
2838       g_object_notify (G_OBJECT (label), "justify");
2839       gtk_widget_queue_resize (GTK_WIDGET (label));
2840     }
2841 }
2842
2843 /**
2844  * gtk_label_get_justify:
2845  * @label: a #GtkLabel
2846  *
2847  * Returns the justification of the label. See gtk_label_set_justify().
2848  *
2849  * Return value: #GtkJustification
2850  **/
2851 GtkJustification
2852 gtk_label_get_justify (GtkLabel *label)
2853 {
2854   g_return_val_if_fail (GTK_IS_LABEL (label), 0);
2855
2856   return label->priv->jtype;
2857 }
2858
2859 /**
2860  * gtk_label_set_ellipsize:
2861  * @label: a #GtkLabel
2862  * @mode: a #PangoEllipsizeMode
2863  *
2864  * Sets the mode used to ellipsize (add an ellipsis: "...") to the text 
2865  * if there is not enough space to render the entire string.
2866  *
2867  * Since: 2.6
2868  **/
2869 void
2870 gtk_label_set_ellipsize (GtkLabel          *label,
2871                          PangoEllipsizeMode mode)
2872 {
2873   GtkLabelPrivate *priv;
2874
2875   g_return_if_fail (GTK_IS_LABEL (label));
2876   g_return_if_fail (mode >= PANGO_ELLIPSIZE_NONE && mode <= PANGO_ELLIPSIZE_END);
2877
2878   priv = label->priv;
2879
2880   if ((PangoEllipsizeMode) priv->ellipsize != mode)
2881     {
2882       priv->ellipsize = mode;
2883
2884       /* No real need to be this drastic, but easier than duplicating the code */
2885       gtk_label_clear_layout (label);
2886       
2887       g_object_notify (G_OBJECT (label), "ellipsize");
2888       gtk_widget_queue_resize (GTK_WIDGET (label));
2889     }
2890 }
2891
2892 /**
2893  * gtk_label_get_ellipsize:
2894  * @label: a #GtkLabel
2895  *
2896  * Returns the ellipsizing position of the label. See gtk_label_set_ellipsize().
2897  *
2898  * Return value: #PangoEllipsizeMode
2899  *
2900  * Since: 2.6
2901  **/
2902 PangoEllipsizeMode
2903 gtk_label_get_ellipsize (GtkLabel *label)
2904 {
2905   g_return_val_if_fail (GTK_IS_LABEL (label), PANGO_ELLIPSIZE_NONE);
2906
2907   return label->priv->ellipsize;
2908 }
2909
2910 /**
2911  * gtk_label_set_width_chars:
2912  * @label: a #GtkLabel
2913  * @n_chars: the new desired width, in characters.
2914  * 
2915  * Sets the desired width in characters of @label to @n_chars.
2916  * 
2917  * Since: 2.6
2918  **/
2919 void
2920 gtk_label_set_width_chars (GtkLabel *label,
2921                            gint      n_chars)
2922 {
2923   GtkLabelPrivate *priv;
2924
2925   g_return_if_fail (GTK_IS_LABEL (label));
2926
2927   priv = label->priv;
2928
2929   if (priv->width_chars != n_chars)
2930     {
2931       priv->width_chars = n_chars;
2932       g_object_notify (G_OBJECT (label), "width-chars");
2933       gtk_widget_queue_resize (GTK_WIDGET (label));
2934     }
2935 }
2936
2937 /**
2938  * gtk_label_get_width_chars:
2939  * @label: a #GtkLabel
2940  * 
2941  * Retrieves the desired width of @label, in characters. See
2942  * gtk_label_set_width_chars().
2943  * 
2944  * Return value: the width of the label in characters.
2945  * 
2946  * Since: 2.6
2947  **/
2948 gint
2949 gtk_label_get_width_chars (GtkLabel *label)
2950 {
2951   g_return_val_if_fail (GTK_IS_LABEL (label), -1);
2952
2953   return label->priv->width_chars;
2954 }
2955
2956 /**
2957  * gtk_label_set_max_width_chars:
2958  * @label: a #GtkLabel
2959  * @n_chars: the new desired maximum width, in characters.
2960  * 
2961  * Sets the desired maximum width in characters of @label to @n_chars.
2962  * 
2963  * Since: 2.6
2964  **/
2965 void
2966 gtk_label_set_max_width_chars (GtkLabel *label,
2967                                gint      n_chars)
2968 {
2969   GtkLabelPrivate *priv;
2970
2971   g_return_if_fail (GTK_IS_LABEL (label));
2972
2973   priv = label->priv;
2974
2975   if (priv->max_width_chars != n_chars)
2976     {
2977       priv->max_width_chars = n_chars;
2978
2979       g_object_notify (G_OBJECT (label), "max-width-chars");
2980       gtk_widget_queue_resize (GTK_WIDGET (label));
2981     }
2982 }
2983
2984 /**
2985  * gtk_label_get_max_width_chars:
2986  * @label: a #GtkLabel
2987  * 
2988  * Retrieves the desired maximum width of @label, in characters. See
2989  * gtk_label_set_width_chars().
2990  * 
2991  * Return value: the maximum width of the label in characters.
2992  * 
2993  * Since: 2.6
2994  **/
2995 gint
2996 gtk_label_get_max_width_chars (GtkLabel *label)
2997 {
2998   g_return_val_if_fail (GTK_IS_LABEL (label), -1);
2999
3000   return label->priv->max_width_chars;
3001 }
3002
3003 /**
3004  * gtk_label_set_line_wrap:
3005  * @label: a #GtkLabel
3006  * @wrap: the setting
3007  *
3008  * Toggles line wrapping within the #GtkLabel widget. %TRUE makes it break
3009  * lines if text exceeds the widget's size. %FALSE lets the text get cut off
3010  * by the edge of the widget if it exceeds the widget size.
3011  *
3012  * Note that setting line wrapping to %TRUE does not make the label
3013  * wrap at its parent container's width, because GTK+ widgets
3014  * conceptually can't make their requisition depend on the parent
3015  * container's size. For a label that wraps at a specific position,
3016  * set the label's width using gtk_widget_set_size_request().
3017  **/
3018 void
3019 gtk_label_set_line_wrap (GtkLabel *label,
3020                          gboolean  wrap)
3021 {
3022   GtkLabelPrivate *priv;
3023
3024   g_return_if_fail (GTK_IS_LABEL (label));
3025
3026   priv = label->priv;
3027
3028   wrap = wrap != FALSE;
3029
3030   if (priv->wrap != wrap)
3031     {
3032       priv->wrap = wrap;
3033
3034       gtk_label_clear_layout (label);
3035       gtk_widget_queue_resize (GTK_WIDGET (label));
3036       g_object_notify (G_OBJECT (label), "wrap");
3037     }
3038 }
3039
3040 /**
3041  * gtk_label_get_line_wrap:
3042  * @label: a #GtkLabel
3043  *
3044  * Returns whether lines in the label are automatically wrapped. 
3045  * See gtk_label_set_line_wrap().
3046  *
3047  * Return value: %TRUE if the lines of the label are automatically wrapped.
3048  */
3049 gboolean
3050 gtk_label_get_line_wrap (GtkLabel *label)
3051 {
3052   g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
3053
3054   return label->priv->wrap;
3055 }
3056
3057 /**
3058  * gtk_label_set_line_wrap_mode:
3059  * @label: a #GtkLabel
3060  * @wrap_mode: the line wrapping mode
3061  *
3062  * If line wrapping is on (see gtk_label_set_line_wrap()) this controls how
3063  * the line wrapping is done. The default is %PANGO_WRAP_WORD which means
3064  * wrap on word boundaries.
3065  *
3066  * Since: 2.10
3067  **/
3068 void
3069 gtk_label_set_line_wrap_mode (GtkLabel *label,
3070                               PangoWrapMode wrap_mode)
3071 {
3072   GtkLabelPrivate *priv;
3073
3074   g_return_if_fail (GTK_IS_LABEL (label));
3075
3076   priv = label->priv;
3077
3078   if (priv->wrap_mode != wrap_mode)
3079     {
3080       priv->wrap_mode = wrap_mode;
3081       g_object_notify (G_OBJECT (label), "wrap-mode");
3082       
3083       gtk_widget_queue_resize (GTK_WIDGET (label));
3084     }
3085 }
3086
3087 /**
3088  * gtk_label_get_line_wrap_mode:
3089  * @label: a #GtkLabel
3090  *
3091  * Returns line wrap mode used by the label. See gtk_label_set_line_wrap_mode().
3092  *
3093  * Return value: %TRUE if the lines of the label are automatically wrapped.
3094  *
3095  * Since: 2.10
3096  */
3097 PangoWrapMode
3098 gtk_label_get_line_wrap_mode (GtkLabel *label)
3099 {
3100   g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
3101
3102   return label->priv->wrap_mode;
3103 }
3104
3105 static void
3106 gtk_label_destroy (GtkWidget *widget)
3107 {
3108   GtkLabel *label = GTK_LABEL (widget);
3109
3110   gtk_label_set_mnemonic_widget (label, NULL);
3111
3112   GTK_WIDGET_CLASS (gtk_label_parent_class)->destroy (widget);
3113 }
3114
3115 static void
3116 gtk_label_finalize (GObject *object)
3117 {
3118   GtkLabel *label = GTK_LABEL (object);
3119   GtkLabelPrivate *priv = label->priv;
3120
3121   g_free (priv->label);
3122   g_free (priv->text);
3123
3124   if (priv->layout)
3125     g_object_unref (priv->layout);
3126
3127   if (priv->attrs)
3128     pango_attr_list_unref (priv->attrs);
3129
3130   if (priv->effective_attrs)
3131     pango_attr_list_unref (priv->effective_attrs);
3132
3133   gtk_label_clear_links (label);
3134   g_free (priv->select_info);
3135
3136   G_OBJECT_CLASS (gtk_label_parent_class)->finalize (object);
3137 }
3138
3139 static void
3140 gtk_label_clear_layout (GtkLabel *label)
3141 {
3142   GtkLabelPrivate *priv = label->priv;
3143
3144   if (priv->layout)
3145     {
3146       g_object_unref (priv->layout);
3147       priv->layout = NULL;
3148     }
3149 }
3150
3151 static PangoFontMetrics *
3152 get_font_metrics (PangoContext *context, GtkWidget *widget)
3153 {
3154   GtkStyleContext *style_context;
3155   const PangoFontDescription *font;
3156   PangoFontMetrics *retval;
3157
3158   style_context = gtk_widget_get_style_context (widget);
3159   font = gtk_style_context_get_font (style_context, GTK_STATE_FLAG_NORMAL);
3160
3161   retval = pango_context_get_metrics (context,
3162                                       font,
3163                                       pango_context_get_language (context));
3164
3165   return retval;
3166 }
3167
3168 /**
3169  * gtk_label_get_measuring_layout:
3170  * @label: the label
3171  * @existing_layout: %NULL or an existing layout already in use.
3172  * @width: the width to measure with in pango units, or -1 for infinite
3173  * @height: the height to measure with in pango units, or -1 for infinite
3174  *
3175  * Gets a layout that can be used for measuring sizes. The returned
3176  * layout will be identical to the label's layout except for the
3177  * layout's width, which will be set to @width. Do not modify the returned
3178  * layout.
3179  *
3180  * Returns: a new reference to a pango layout
3181  **/
3182 static PangoLayout *
3183 gtk_label_get_measuring_layout (GtkLabel *   label,
3184                                 PangoLayout *existing_layout,
3185                                 int          width,
3186                                 int          height)
3187 {
3188   GtkLabelPrivate *priv = label->priv;
3189   PangoRectangle rect;
3190   PangoLayout *copy;
3191
3192   if (existing_layout != NULL)
3193     {
3194       if (existing_layout != priv->layout)
3195         {
3196           pango_layout_set_width (existing_layout, width);
3197           pango_layout_set_height (existing_layout, height);
3198           return existing_layout;
3199         }
3200
3201       g_object_unref (existing_layout);
3202     }
3203
3204   gtk_label_ensure_layout (label);
3205
3206   if (pango_layout_get_width (priv->layout) == width &&
3207       pango_layout_get_height (priv->layout) == height)
3208     {
3209       g_object_ref (priv->layout);
3210       return priv->layout;
3211     }
3212
3213   /* We can use the label's own layout if we're not allocated a size yet,
3214    * because we don't need it to be properly setup at that point.
3215    * This way we can make use of caching upon the label's creation.
3216    */
3217   if (gtk_widget_get_allocated_width (GTK_WIDGET (label)) <= 1)
3218     {
3219       g_object_ref (priv->layout);
3220       pango_layout_set_width (priv->layout, width);
3221       pango_layout_set_height (priv->layout, height);
3222       return priv->layout;
3223     }
3224
3225   /* oftentimes we want to measure a width that is far wider than the current width,
3226    * even though the layout would not change if we made it wider. In that case, we
3227    * can just return the current layout, because for measuring purposes, it will be
3228    * identical.
3229    */
3230   pango_layout_get_extents (priv->layout, NULL, &rect);
3231   if ((width == -1 || rect.width <= width) &&
3232       (height == -1 || rect.height <= height) &&
3233       !pango_layout_is_wrapped (priv->layout) &&
3234       !pango_layout_is_ellipsized (priv->layout))
3235     {
3236       g_object_ref (priv->layout);
3237       return priv->layout;
3238     }
3239
3240   copy = pango_layout_copy (priv->layout);
3241   pango_layout_set_width (copy, width);
3242   pango_layout_set_height (copy, height);
3243   return copy;
3244 }
3245
3246 static void
3247 gtk_label_update_layout_width (GtkLabel *label)
3248 {
3249   GtkLabelPrivate *priv = label->priv;
3250   GtkWidget *widget = GTK_WIDGET (label);
3251
3252   g_assert (priv->layout);
3253
3254   if (priv->ellipsize || priv->wrap)
3255     {
3256       PangoRectangle logical;
3257       gint xpad, ypad;
3258       gint width, height;
3259
3260       gtk_misc_get_padding (GTK_MISC (label), &xpad, &ypad);
3261
3262       width = gtk_widget_get_allocated_width (GTK_WIDGET (label)) - xpad * 2;
3263       height = gtk_widget_get_allocated_height (GTK_WIDGET (label)) - ypad * 2;
3264
3265       if (priv->have_transform)
3266         {
3267           PangoContext *context = gtk_widget_get_pango_context (widget);
3268           const PangoMatrix *matrix = pango_context_get_matrix (context);
3269           const gdouble dx = matrix->xx; /* cos (M_PI * angle / 180) */
3270           const gdouble dy = matrix->xy; /* sin (M_PI * angle / 180) */
3271
3272           pango_layout_set_width (priv->layout, -1);
3273           pango_layout_set_height (priv->layout, -1);
3274           pango_layout_get_pixel_extents (priv->layout, NULL, &logical);
3275
3276           if (fabs (dy) < 0.01)
3277             {
3278               if (logical.width > width)
3279                 pango_layout_set_width (priv->layout, width * PANGO_SCALE);
3280             }
3281           else if (fabs (dx) < 0.01)
3282             {
3283               if (logical.width > height)
3284                 pango_layout_set_width (priv->layout, height * PANGO_SCALE);
3285             }
3286           else
3287             {
3288               gdouble x0, y0, x1, y1, length;
3289               gboolean vertical;
3290               gint cy;
3291
3292               x0 = width / 2;
3293               y0 = dx ? x0 * dy / dx : G_MAXDOUBLE;
3294               vertical = fabs (y0) > height / 2;
3295
3296               if (vertical)
3297                 {
3298                   y0 = height/2;
3299                   x0 = dy ? y0 * dx / dy : G_MAXDOUBLE;
3300                 }
3301
3302               length = 2 * sqrt (x0 * x0 + y0 * y0);
3303               pango_layout_set_width (priv->layout, rint (length * PANGO_SCALE));
3304               pango_layout_get_pixel_size (priv->layout, NULL, &cy);
3305
3306               x1 = +dy * cy/2;
3307               y1 = -dx * cy/2;
3308
3309               if (vertical)
3310                 {
3311                   y0 = height/2 + y1 - y0;
3312                   x0 = -y0 * dx/dy;
3313                 }
3314               else
3315                 {
3316                   x0 = width/2 + x1 - x0;
3317                   y0 = -x0 * dy/dx;
3318                 }
3319
3320               length = length - sqrt (x0 * x0 + y0 * y0) * 2;
3321               pango_layout_set_width (priv->layout, rint (length * PANGO_SCALE));
3322             }
3323         }
3324       else
3325         {
3326           pango_layout_set_width (priv->layout, width * PANGO_SCALE);
3327           pango_layout_set_height (priv->layout, priv->ellipsize ? height * PANGO_SCALE : -1);
3328         }
3329     }
3330   else
3331     {
3332       pango_layout_set_width (priv->layout, -1);
3333       pango_layout_set_height (priv->layout, -1);
3334     }
3335 }
3336
3337 static void
3338 gtk_label_ensure_layout (GtkLabel *label)
3339 {
3340   GtkLabelPrivate *priv = label->priv;
3341   GtkWidget *widget;
3342   gboolean rtl;
3343
3344   widget = GTK_WIDGET (label);
3345
3346   rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
3347
3348   if (!priv->layout)
3349     {
3350       PangoAlignment align = PANGO_ALIGN_LEFT; /* Quiet gcc */
3351       PangoAttrList *attrs;
3352       gdouble angle = gtk_label_get_angle (label);
3353
3354       if (angle != 0.0 && !priv->select_info)
3355         {
3356           PangoMatrix matrix = PANGO_MATRIX_INIT;
3357
3358           /* We rotate the standard singleton PangoContext for the widget,
3359            * depending on the fact that it's meant pretty much exclusively
3360            * for our use.
3361            */
3362           pango_matrix_rotate (&matrix, angle);
3363
3364           pango_context_set_matrix (gtk_widget_get_pango_context (widget), &matrix);
3365
3366           priv->have_transform = TRUE;
3367         }
3368       else
3369         {
3370           if (priv->have_transform)
3371             pango_context_set_matrix (gtk_widget_get_pango_context (widget), NULL);
3372
3373           priv->have_transform = FALSE;
3374         }
3375
3376       priv->layout = gtk_widget_create_pango_layout (widget, priv->text);
3377
3378       if (priv->select_info && priv->select_info->links)
3379         {
3380           GdkColor link_color, visited_color;
3381           PangoAttribute *attribute;
3382           GList *list;
3383           
3384           gtk_label_get_link_colors (widget, &link_color, &visited_color);
3385           attrs = pango_attr_list_new ();
3386
3387           for (list = priv->select_info->links; list; list = list->next)
3388             {
3389               GtkLabelLink *link = list->data;
3390
3391               attribute = pango_attr_underline_new (TRUE);
3392               attribute->start_index = link->start;
3393               attribute->end_index = link->end;
3394               pango_attr_list_insert (attrs, attribute);
3395
3396               if (link->visited)
3397                 attribute = pango_attr_foreground_new (visited_color.red,
3398                                                        visited_color.green,
3399                                                        visited_color.blue);
3400               else
3401                 attribute = pango_attr_foreground_new (link_color.red,
3402                                                        link_color.green,
3403                                                        link_color.blue);
3404               attribute->start_index = link->start;
3405               attribute->end_index = link->end;
3406               pango_attr_list_insert (attrs, attribute);
3407             }
3408         }
3409       else if (priv->effective_attrs && priv->effective_attrs)
3410         attrs = pango_attr_list_new ();
3411       else
3412         attrs = NULL;
3413
3414       if (priv->effective_attrs)
3415         {
3416           if (attrs)
3417             my_pango_attr_list_merge (attrs, priv->effective_attrs);
3418           else
3419             attrs = pango_attr_list_ref (priv->effective_attrs);
3420         }
3421           
3422       if (priv->attrs)
3423         {
3424           if (attrs)
3425             my_pango_attr_list_merge (attrs, priv->attrs);
3426           else
3427             attrs = pango_attr_list_ref (priv->attrs);
3428         }
3429           
3430       if (attrs)
3431         {
3432           pango_layout_set_attributes (priv->layout, attrs);
3433           pango_attr_list_unref (attrs);
3434         }
3435
3436       switch (priv->jtype)
3437         {
3438         case GTK_JUSTIFY_LEFT:
3439           align = rtl ? PANGO_ALIGN_RIGHT : PANGO_ALIGN_LEFT;
3440           break;
3441         case GTK_JUSTIFY_RIGHT:
3442           align = rtl ? PANGO_ALIGN_LEFT : PANGO_ALIGN_RIGHT;
3443           break;
3444         case GTK_JUSTIFY_CENTER:
3445           align = PANGO_ALIGN_CENTER;
3446           break;
3447         case GTK_JUSTIFY_FILL:
3448           align = rtl ? PANGO_ALIGN_RIGHT : PANGO_ALIGN_LEFT;
3449           pango_layout_set_justify (priv->layout, TRUE);
3450           break;
3451         default:
3452           g_assert_not_reached();
3453         }
3454
3455       pango_layout_set_alignment (priv->layout, align);
3456       pango_layout_set_ellipsize (priv->layout, priv->ellipsize);
3457       pango_layout_set_wrap (priv->layout, priv->wrap_mode);
3458       pango_layout_set_single_paragraph_mode (priv->layout, priv->single_line_mode);
3459
3460       gtk_label_update_layout_width (label);
3461     }
3462 }
3463
3464 static gint
3465 get_single_line_height (GtkWidget   *widget,
3466                         PangoLayout *layout)
3467 {
3468   PangoContext *context;
3469   PangoFontMetrics *metrics;
3470   gint ascent, descent;
3471
3472   context = pango_layout_get_context (layout);
3473   metrics = get_font_metrics (context, widget);
3474   ascent = pango_font_metrics_get_ascent (metrics);
3475   descent = pango_font_metrics_get_descent (metrics);
3476   pango_font_metrics_unref (metrics);
3477
3478   return ascent + descent;
3479 }
3480
3481 static GtkSizeRequestMode
3482 gtk_label_get_request_mode (GtkWidget *widget)
3483 {
3484   GtkLabel *label = GTK_LABEL (widget);
3485   gdouble   angle = gtk_label_get_angle (label);
3486
3487   if (label->priv->wrap)
3488     return (angle == 90 || angle == 270) ?
3489       GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT : 
3490       GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH;
3491
3492     return GTK_SIZE_REQUEST_CONSTANT_SIZE;
3493 }
3494
3495 static void
3496 get_size_for_allocation (GtkLabel        *label,
3497                          GtkOrientation   orientation,
3498                          gint             allocation,
3499                          gint            *minimum_size,
3500                          gint            *natural_size)
3501 {
3502   GtkLabelPrivate *priv = label->priv;
3503   PangoLayout *layout;
3504   gint text_height;
3505
3506   layout = gtk_label_get_measuring_layout (label, NULL, allocation * PANGO_SCALE, -1);
3507
3508   pango_layout_get_pixel_size (layout, NULL, &text_height);
3509
3510   if (minimum_size)
3511     *minimum_size = text_height;
3512
3513   if (natural_size)
3514     {
3515       if (priv->ellipsize && priv->wrap)
3516         {
3517           layout = gtk_label_get_measuring_layout (label, layout, allocation * PANGO_SCALE, G_MAXINT);
3518           pango_layout_get_pixel_size (layout, NULL, &text_height);
3519         }
3520
3521       *natural_size = text_height;
3522     }
3523
3524   g_object_unref (layout);
3525 }
3526
3527 static gint
3528 get_char_pixels (GtkWidget   *label,
3529                  PangoLayout *layout)
3530 {
3531   PangoContext *context;
3532   PangoFontMetrics *metrics;
3533   gint char_width, digit_width;
3534
3535   context = pango_layout_get_context (layout);
3536   metrics = get_font_metrics (context, GTK_WIDGET (label));
3537   char_width = pango_font_metrics_get_approximate_char_width (metrics);
3538   digit_width = pango_font_metrics_get_approximate_digit_width (metrics);
3539   pango_font_metrics_unref (metrics);
3540
3541   return MAX (char_width, digit_width);;
3542 }
3543
3544 static void
3545 gtk_label_get_preferred_layout_size (GtkLabel *label,
3546                                      PangoRectangle *required,
3547                                      PangoRectangle *natural)
3548 {
3549   GtkLabelPrivate *priv = label->priv;
3550   PangoLayout *layout;
3551
3552   /* "width-chars" Hard-coded minimum width:
3553    *    - minimum size should be MAX (width-chars, strlen ("..."));
3554    *    - natural size should be MAX (width-chars, strlen (priv->text));
3555    *
3556    * "max-width-chars" User specified maximum size requisition
3557    *    - minimum size should be MAX (width-chars, 0)
3558    *    - natural size should be MIN (max-width-chars, strlen (priv->text))
3559    *
3560    *    For ellipsizing labels; if max-width-chars is specified: either it is used as 
3561    *    a minimum size or the label text as a minimum size (natural size still overflows).
3562    *
3563    *    For wrapping labels; A reasonable minimum size is useful to naturally layout
3564    *    interfaces automatically. In this case if no "width-chars" is specified, the minimum
3565    *    width will default to the wrap guess that gtk_label_ensure_layout() does.
3566    */
3567
3568   /* Start off with the pixel extents of an as-wide-as-possible layout */
3569   layout = gtk_label_get_measuring_layout (label, NULL, -1, -1);
3570
3571   pango_layout_get_extents (layout, NULL, natural);
3572   natural->x = natural->y = 0;
3573
3574   if (priv->wrap)
3575     natural->height = get_single_line_height (GTK_WIDGET (label), layout);
3576
3577   if (priv->ellipsize || priv->wrap)
3578     {
3579       /* a layout with width 0 will be as small as humanly possible */
3580       layout = gtk_label_get_measuring_layout (label, layout, 0, -1);
3581
3582       pango_layout_get_extents (layout, NULL, required);
3583
3584       /* can happen when Pango decides to ellipsize text */
3585       if (required->width > natural->width)
3586         required->width = natural->width;
3587
3588       required->x = required->y = 0;
3589       required->height = natural->height;
3590     }
3591   else
3592     {
3593       *required = *natural;
3594     }
3595
3596   if (priv->width_chars > -1 || priv->max_width_chars > -1)
3597     {
3598       gint char_pixels;
3599
3600       char_pixels = get_char_pixels (GTK_WIDGET (label), layout);
3601       
3602       if (priv->width_chars > -1)
3603         required->width = MAX (required->width, char_pixels * priv->width_chars);
3604
3605       if (priv->max_width_chars > -1)
3606         natural->width = MIN (natural->width, priv->max_width_chars * char_pixels);
3607       natural->width = MAX (natural->width, required->width);
3608     }
3609
3610   g_object_unref (layout);
3611 }
3612
3613 static void
3614 gtk_label_get_preferred_size (GtkWidget      *widget,
3615                               GtkOrientation  orientation,
3616                               gint           *minimum_size,
3617                               gint           *natural_size)
3618 {
3619   GtkLabel      *label = GTK_LABEL (widget);
3620   GtkLabelPrivate  *priv = label->priv;
3621   PangoRectangle required_rect;
3622   PangoRectangle natural_rect;
3623   gint           xpad, ypad;
3624
3625   gtk_label_get_preferred_layout_size (label, &required_rect, &natural_rect);
3626
3627   /* Now that we have minimum and natural sizes in pango extents, apply a possible transform */
3628   if (priv->have_transform)
3629     {
3630       PangoLayout *copy;
3631       PangoContext *context;
3632       const PangoMatrix *matrix;
3633
3634       copy = pango_layout_copy (priv->layout);
3635       context = pango_layout_get_context (copy);
3636       matrix = pango_context_get_matrix (context);
3637
3638       pango_layout_set_width (copy, -1);
3639       pango_layout_set_ellipsize (copy, PANGO_ELLIPSIZE_NONE);
3640
3641       pango_layout_get_extents (copy, NULL, &natural_rect);
3642       g_object_unref (copy);
3643
3644       pango_matrix_transform_rectangle (matrix, &required_rect);
3645       pango_matrix_transform_rectangle (matrix, &natural_rect);
3646
3647       /* Bump the natural size in case of ellipsize to ensure pango has
3648        * enough space in the angles (note, we could alternatively set the
3649        * layout to not ellipsize when we know we have been allocated our
3650        * full natural size, or it may be that pango needs a fix here).
3651        */
3652       if (priv->ellipsize && priv->angle != 0 && priv->angle != 90 && 
3653           priv->angle != 180 && priv->angle != 270 && priv->angle != 360)
3654         {
3655           /* For some reason we only need this at about 110 degrees, and only
3656            * when gaining in height
3657            */
3658           natural_rect.height += ROTATION_ELLIPSIZE_PADDING * 2 * PANGO_SCALE;
3659           natural_rect.width  += ROTATION_ELLIPSIZE_PADDING * 2 * PANGO_SCALE;
3660         }
3661     }
3662
3663   required_rect.width  = PANGO_PIXELS_CEIL (required_rect.width);
3664   required_rect.height = PANGO_PIXELS_CEIL (required_rect.height);
3665
3666   natural_rect.width  = PANGO_PIXELS_CEIL (natural_rect.width);
3667   natural_rect.height = PANGO_PIXELS_CEIL (natural_rect.height);
3668
3669   gtk_misc_get_padding (GTK_MISC (label), &xpad, &ypad);
3670
3671   if (orientation == GTK_ORIENTATION_HORIZONTAL)
3672     {
3673       /* Note, we cant use get_size_for_allocation() when rotating
3674        * ellipsized labels.
3675        */
3676       if (!(priv->ellipsize && priv->have_transform) &&
3677           (priv->angle == 90 || priv->angle == 270))
3678         {
3679           /* Doing a h4w request on a rotated label here, return the
3680            * required width for the minimum height.
3681            */
3682           get_size_for_allocation (label,
3683                                    GTK_ORIENTATION_VERTICAL,
3684                                    required_rect.height,
3685                                    minimum_size, natural_size);
3686
3687         }
3688       else
3689         {
3690           /* Normal desired width */
3691           *minimum_size = required_rect.width;
3692           *natural_size = natural_rect.width;
3693         }
3694
3695       *minimum_size += xpad * 2;
3696       *natural_size += xpad * 2;
3697     }
3698   else /* GTK_ORIENTATION_VERTICAL */
3699     {
3700       /* Note, we cant use get_size_for_allocation() when rotating
3701        * ellipsized labels.
3702        */
3703       if (!(priv->ellipsize && priv->have_transform) &&
3704           (priv->angle == 0 || priv->angle == 180 || priv->angle == 360))
3705         {
3706           /* Doing a w4h request on a label here, return the required
3707            * height for the minimum width.
3708            */
3709           get_size_for_allocation (label,
3710                                    GTK_ORIENTATION_HORIZONTAL,
3711                                    required_rect.width,
3712                                    minimum_size, natural_size);
3713         }
3714       else
3715         {
3716           /* A vertically rotated label does w4h, so return the base
3717            * desired height (text length)
3718            */
3719           *minimum_size = required_rect.height;
3720           *natural_size = natural_rect.height;
3721         }
3722
3723       *minimum_size += ypad * 2;
3724       *natural_size += ypad * 2;
3725     }
3726 }
3727
3728
3729 static void
3730 gtk_label_get_preferred_width (GtkWidget *widget,
3731                                gint      *minimum_size,
3732                                gint      *natural_size)
3733 {
3734   gtk_label_get_preferred_size (widget, GTK_ORIENTATION_HORIZONTAL, minimum_size, natural_size);
3735 }
3736
3737 static void
3738 gtk_label_get_preferred_height (GtkWidget *widget,
3739                                 gint      *minimum_size,
3740                                 gint      *natural_size)
3741 {
3742   gtk_label_get_preferred_size (widget, GTK_ORIENTATION_VERTICAL, minimum_size, natural_size);
3743 }
3744
3745 static void
3746 gtk_label_get_preferred_width_for_height (GtkWidget *widget,
3747                                           gint       height,
3748                                           gint      *minimum_width,
3749                                           gint      *natural_width)
3750 {
3751   GtkLabel *label = GTK_LABEL (widget);
3752   GtkLabelPrivate *priv = label->priv;
3753
3754   if (priv->wrap && (priv->angle == 90 || priv->angle == 270))
3755     {
3756       gint xpad, ypad;
3757
3758       gtk_misc_get_padding (GTK_MISC (label), &xpad, &ypad);
3759
3760       if (priv->wrap)
3761         gtk_label_clear_layout (label);
3762
3763       get_size_for_allocation (label, GTK_ORIENTATION_VERTICAL,
3764                                MAX (1, height - (ypad * 2)),
3765                                minimum_width, natural_width);
3766
3767       if (minimum_width)
3768         *minimum_width += xpad * 2;
3769
3770       if (natural_width)
3771         *natural_width += xpad * 2;
3772     }
3773   else
3774     GTK_WIDGET_GET_CLASS (widget)->get_preferred_width (widget, minimum_width, natural_width);
3775 }
3776
3777 static void
3778 gtk_label_get_preferred_height_for_width (GtkWidget *widget,
3779                                           gint       width,
3780                                           gint      *minimum_height,
3781                                           gint      *natural_height)
3782 {
3783   GtkLabel *label = GTK_LABEL (widget);
3784   GtkLabelPrivate *priv = label->priv;
3785
3786   if (priv->wrap && (priv->angle == 0 || priv->angle == 180 || priv->angle == 360))
3787     {
3788       gint xpad, ypad;
3789
3790       gtk_misc_get_padding (GTK_MISC (label), &xpad, &ypad);
3791
3792       if (priv->wrap)
3793         gtk_label_clear_layout (label);
3794
3795       get_size_for_allocation (label, GTK_ORIENTATION_HORIZONTAL,
3796                                MAX (1, width - xpad * 2),
3797                                minimum_height, natural_height);
3798
3799       if (minimum_height)
3800         *minimum_height += ypad * 2;
3801
3802       if (natural_height)
3803         *natural_height += ypad * 2;
3804     }
3805   else
3806     GTK_WIDGET_GET_CLASS (widget)->get_preferred_height (widget, minimum_height, natural_height);
3807 }
3808
3809 static void
3810 gtk_label_size_allocate (GtkWidget     *widget,
3811                          GtkAllocation *allocation)
3812 {
3813   GtkLabel *label = GTK_LABEL (widget);
3814   GtkLabelPrivate *priv = label->priv;
3815
3816   GTK_WIDGET_CLASS (gtk_label_parent_class)->size_allocate (widget, allocation);
3817
3818   if (priv->layout)
3819     gtk_label_update_layout_width (label);
3820
3821   if (priv->select_info && priv->select_info->window)
3822     {
3823       gdk_window_move_resize (priv->select_info->window,
3824                               allocation->x,
3825                               allocation->y,
3826                               allocation->width,
3827                               allocation->height);
3828     }
3829 }
3830
3831 static void
3832 gtk_label_update_cursor (GtkLabel *label)
3833 {
3834   GtkLabelPrivate *priv = label->priv;
3835   GtkWidget *widget;
3836
3837   if (!priv->select_info)
3838     return;
3839
3840   widget = GTK_WIDGET (label);
3841
3842   if (gtk_widget_get_realized (widget))
3843     {
3844       GdkDisplay *display;
3845       GdkCursor *cursor;
3846
3847       if (gtk_widget_is_sensitive (widget))
3848         {
3849           display = gtk_widget_get_display (widget);
3850
3851           if (priv->select_info->active_link)
3852             cursor = gdk_cursor_new_for_display (display, GDK_HAND2);
3853           else if (priv->select_info->selectable)
3854             cursor = gdk_cursor_new_for_display (display, GDK_XTERM);
3855           else
3856             cursor = NULL;
3857         }
3858       else
3859         cursor = NULL;
3860
3861       gdk_window_set_cursor (priv->select_info->window, cursor);
3862
3863       if (cursor)
3864         g_object_unref (cursor);
3865     }
3866 }
3867
3868 static void
3869 gtk_label_state_flags_changed (GtkWidget     *widget,
3870                                GtkStateFlags  prev_state)
3871 {
3872   GtkLabel *label = GTK_LABEL (widget);
3873   GtkLabelPrivate *priv = label->priv;
3874
3875   if (priv->select_info)
3876     {
3877       if (!gtk_widget_is_sensitive (widget))
3878         gtk_label_select_region (label, 0, 0);
3879
3880       gtk_label_update_cursor (label);
3881     }
3882
3883   /* We have to clear the layout, fonts etc. may have changed */
3884   gtk_label_clear_layout (label);
3885
3886   if (GTK_WIDGET_CLASS (gtk_label_parent_class)->state_flags_changed)
3887     GTK_WIDGET_CLASS (gtk_label_parent_class)->state_flags_changed (widget, prev_state);
3888 }
3889
3890 static void
3891 gtk_label_style_updated (GtkWidget *widget)
3892 {
3893   GtkLabel *label = GTK_LABEL (widget);
3894
3895   GTK_WIDGET_CLASS (gtk_label_parent_class)->style_updated (widget);
3896
3897   /* We have to clear the layout, fonts etc. may have changed */
3898   gtk_label_clear_layout (label);
3899 }
3900
3901 static void 
3902 gtk_label_direction_changed (GtkWidget        *widget,
3903                              GtkTextDirection previous_dir)
3904 {
3905   GtkLabel *label = GTK_LABEL (widget);
3906   GtkLabelPrivate *priv = label->priv;
3907
3908   if (priv->layout)
3909     pango_layout_context_changed (priv->layout);
3910
3911   GTK_WIDGET_CLASS (gtk_label_parent_class)->direction_changed (widget, previous_dir);
3912 }
3913
3914 static void
3915 get_layout_location (GtkLabel  *label,
3916                      gint      *xp,
3917                      gint      *yp)
3918 {
3919   GtkAllocation allocation;
3920   GtkMisc *misc;
3921   GtkWidget *widget;
3922   GtkLabelPrivate *priv;
3923   gint req_width, x, y;
3924   gint req_height;
3925   gint xpad, ypad;
3926   gfloat xalign, yalign;
3927   PangoRectangle logical;
3928
3929   misc   = GTK_MISC (label);
3930   widget = GTK_WIDGET (label);
3931   priv   = label->priv;
3932
3933   gtk_misc_get_alignment (misc, &xalign, &yalign);
3934   gtk_misc_get_padding (misc, &xpad, &ypad);
3935
3936   if (gtk_widget_get_direction (widget) != GTK_TEXT_DIR_LTR)
3937     xalign = 1.0 - xalign;
3938
3939   pango_layout_get_extents (priv->layout, NULL, &logical);
3940
3941   if (priv->have_transform)
3942     {
3943       PangoContext *context = gtk_widget_get_pango_context (widget);
3944       const PangoMatrix *matrix = pango_context_get_matrix (context);
3945       pango_matrix_transform_rectangle (matrix, &logical);
3946     }
3947
3948   pango_extents_to_pixels (&logical, NULL);
3949
3950   req_width  = logical.width;
3951   req_height = logical.height;
3952
3953   req_width  += 2 * xpad;
3954   req_height += 2 * ypad;
3955
3956   gtk_widget_get_allocation (widget, &allocation);
3957
3958   x = floor (allocation.x + xpad + xalign * (allocation.width - req_width) - logical.x);
3959
3960
3961   /* bgo#315462 - For single-line labels, *do* align the requisition with
3962    * respect to the allocation, even if we are under-allocated.  For multi-line
3963    * labels, always show the top of the text when they are under-allocated.  The
3964    * rationale is this:
3965    *
3966    * - Single-line labels appear in GtkButtons, and it is very easy to get them
3967    *   to be smaller than their requisition.  The button may clip the label, but
3968    *   the label will still be able to show most of itself and the focus
3969    *   rectangle.  Also, it is fairly easy to read a single line of clipped text.
3970    *
3971    * - Multi-line labels should not be clipped to showing "something in the
3972    *   middle".  You want to read the first line, at least, to get some context.
3973    */
3974   if (pango_layout_get_line_count (priv->layout) == 1)
3975     y = floor (allocation.y + ypad + (allocation.height - req_height) * yalign) - logical.y;
3976   else
3977     y = floor (allocation.y + ypad + MAX ((allocation.height - req_height) * yalign, 0)) - logical.y;
3978
3979   if (xp)
3980     *xp = x;
3981
3982   if (yp)
3983     *yp = y;
3984 }
3985
3986 static PangoDirection
3987 get_cursor_direction (GtkLabel *label)
3988 {
3989   GtkLabelPrivate *priv = label->priv;
3990   GSList *l;
3991
3992   g_assert (priv->select_info);
3993
3994   gtk_label_ensure_layout (label);
3995
3996   for (l = pango_layout_get_lines_readonly (priv->layout); l; l = l->next)
3997     {
3998       PangoLayoutLine *line = l->data;
3999
4000       /* If priv->select_info->selection_end is at the very end of
4001        * the line, we don't know if the cursor is on this line or
4002        * the next without looking ahead at the next line. (End
4003        * of paragraph is different from line break.) But it's
4004        * definitely in this paragraph, which is good enough
4005        * to figure out the resolved direction.
4006        */
4007        if (line->start_index + line->length >= priv->select_info->selection_end)
4008         return line->resolved_dir;
4009     }
4010
4011   return PANGO_DIRECTION_LTR;
4012 }
4013
4014 static GtkLabelLink *
4015 gtk_label_get_focus_link (GtkLabel *label)
4016 {
4017   GtkLabelPrivate *priv = label->priv;
4018   GtkLabelSelectionInfo *info = priv->select_info;
4019   GList *l;
4020
4021   if (!info)
4022     return NULL;
4023
4024   if (info->selection_anchor != info->selection_end)
4025     return NULL;
4026
4027   for (l = info->links; l; l = l->next)
4028     {
4029       GtkLabelLink *link = l->data;
4030       if (link->start <= info->selection_anchor &&
4031           info->selection_anchor <= link->end)
4032         return link;
4033     }
4034
4035   return NULL;
4036 }
4037
4038 static gint
4039 gtk_label_draw (GtkWidget *widget,
4040                 cairo_t   *cr)
4041 {
4042   GtkLabel *label = GTK_LABEL (widget);
4043   GtkLabelPrivate *priv = label->priv;
4044   GtkLabelSelectionInfo *info = priv->select_info;
4045   GtkAllocation allocation;
4046   GtkStyleContext *context;
4047   GtkStateFlags state;
4048   gint x, y;
4049
4050   gtk_label_ensure_layout (label);
4051
4052   if (priv->text && (*priv->text != '\0'))
4053     {
4054       get_layout_location (label, &x, &y);
4055
4056       context = gtk_widget_get_style_context (widget);
4057       gtk_widget_get_allocation (widget, &allocation);
4058
4059       cairo_translate (cr, -allocation.x, -allocation.y);
4060
4061       gtk_render_layout (context, cr,
4062                          x, y,
4063                          priv->layout);
4064
4065       state = gtk_widget_get_state_flags (widget);
4066
4067       if (info &&
4068           (info->selection_anchor != info->selection_end))
4069         {
4070           gint range[2];
4071           cairo_region_t *clip;
4072           GdkRGBA bg_color, fg_color;
4073
4074           range[0] = info->selection_anchor;
4075           range[1] = info->selection_end;
4076
4077           if (range[0] > range[1])
4078             {
4079               gint tmp = range[0];
4080               range[0] = range[1];
4081               range[1] = tmp;
4082             }
4083
4084           clip = gdk_pango_layout_get_clip_region (priv->layout,
4085                                                    x, y,
4086                                                    range,
4087                                                    1);
4088
4089          /* FIXME should use gtk_paint, but it can't use a clip region */
4090           cairo_save (cr);
4091
4092           gdk_cairo_region (cr, clip);
4093           cairo_clip (cr);
4094
4095           state |= GTK_STATE_FLAG_SELECTED;
4096
4097           gtk_style_context_get_color (context, state, &fg_color);
4098           gtk_style_context_get_background_color (context, state, &bg_color);
4099
4100           gdk_cairo_set_source_rgba (cr, &bg_color);
4101           cairo_paint (cr);
4102
4103           gdk_cairo_set_source_rgba (cr, &fg_color);
4104           cairo_move_to (cr, x, y);
4105           _gtk_pango_fill_layout (cr, priv->layout);
4106
4107           cairo_restore (cr);
4108           cairo_region_destroy (clip);
4109         }
4110       else if (info)
4111         {
4112           GtkLabelLink *focus_link;
4113           GtkLabelLink *active_link;
4114           gint range[2];
4115           cairo_region_t *clip;
4116           GdkRectangle rect;
4117           GdkColor *text_color;
4118           GdkColor link_color;
4119           GdkColor visited_link_color;
4120
4121           if (info->selectable &&
4122               gtk_widget_has_focus (widget) &&
4123               gtk_widget_is_drawable (widget))
4124             {
4125               PangoDirection cursor_direction;
4126
4127               cursor_direction = get_cursor_direction (label);
4128               gtk_render_insertion_cursor (context, cr,
4129                                            x, y,
4130                                            priv->layout, priv->select_info->selection_end,
4131                                            cursor_direction);
4132             }
4133
4134           focus_link = gtk_label_get_focus_link (label);
4135           active_link = info->active_link;
4136
4137           if (active_link)
4138             {
4139               GdkRGBA bg_color;
4140
4141               range[0] = active_link->start;
4142               range[1] = active_link->end;
4143
4144               cairo_save (cr);
4145
4146               clip = gdk_pango_layout_get_clip_region (priv->layout,
4147                                                        x, y,
4148                                                        range,
4149                                                        1);
4150               gdk_cairo_region (cr, clip);
4151               cairo_clip (cr);
4152               cairo_region_destroy (clip);
4153
4154               gtk_label_get_link_colors (widget, &link_color, &visited_link_color);
4155               if (active_link->visited)
4156                 text_color = &visited_link_color;
4157               else
4158                 text_color = &link_color;
4159
4160               if (info->link_clicked)
4161                 state |= GTK_STATE_FLAG_ACTIVE;
4162               else
4163                 state |= GTK_STATE_FLAG_PRELIGHT;
4164
4165               gtk_style_context_get_background_color (context, state, &bg_color);
4166
4167               gdk_cairo_set_source_rgba (cr, &bg_color);
4168               cairo_paint (cr);
4169
4170               gdk_cairo_set_source_color (cr, text_color);
4171               cairo_move_to (cr, x, y);
4172               _gtk_pango_fill_layout (cr, priv->layout);
4173
4174               cairo_restore (cr);
4175             }
4176
4177           if (focus_link && gtk_widget_has_visible_focus (widget))
4178             {
4179               range[0] = focus_link->start;
4180               range[1] = focus_link->end;
4181
4182               clip = gdk_pango_layout_get_clip_region (priv->layout,
4183                                                        x, y,
4184                                                        range,
4185                                                        1);
4186               cairo_region_get_extents (clip, &rect);
4187
4188               gtk_render_focus (context, cr,
4189                                 rect.x, rect.y,
4190                                 rect.width, rect.height);
4191
4192               cairo_region_destroy (clip);
4193             }
4194         }
4195     }
4196
4197   return FALSE;
4198 }
4199
4200 static gboolean
4201 separate_uline_pattern (const gchar  *str,
4202                         guint        *accel_key,
4203                         gchar       **new_str,
4204                         gchar       **pattern)
4205 {
4206   gboolean underscore;
4207   const gchar *src;
4208   gchar *dest;
4209   gchar *pattern_dest;
4210
4211   *accel_key = GDK_KEY_VoidSymbol;
4212   *new_str = g_new (gchar, strlen (str) + 1);
4213   *pattern = g_new (gchar, g_utf8_strlen (str, -1) + 1);
4214
4215   underscore = FALSE;
4216
4217   src = str;
4218   dest = *new_str;
4219   pattern_dest = *pattern;
4220
4221   while (*src)
4222     {
4223       gunichar c;
4224       const gchar *next_src;
4225
4226       c = g_utf8_get_char (src);
4227       if (c == (gunichar)-1)
4228         {
4229           g_warning ("Invalid input string");
4230           g_free (*new_str);
4231           g_free (*pattern);
4232
4233           return FALSE;
4234         }
4235       next_src = g_utf8_next_char (src);
4236
4237       if (underscore)
4238         {
4239           if (c == '_')
4240             *pattern_dest++ = ' ';
4241           else
4242             {
4243               *pattern_dest++ = '_';
4244               if (*accel_key == GDK_KEY_VoidSymbol)
4245                 *accel_key = gdk_keyval_to_lower (gdk_unicode_to_keyval (c));
4246             }
4247
4248           while (src < next_src)
4249             *dest++ = *src++;
4250
4251           underscore = FALSE;
4252         }
4253       else
4254         {
4255           if (c == '_')
4256             {
4257               underscore = TRUE;
4258               src = next_src;
4259             }
4260           else
4261             {
4262               while (src < next_src)
4263                 *dest++ = *src++;
4264
4265               *pattern_dest++ = ' ';
4266             }
4267         }
4268     }
4269
4270   *dest = 0;
4271   *pattern_dest = 0;
4272
4273   return TRUE;
4274 }
4275
4276 static void
4277 gtk_label_set_uline_text_internal (GtkLabel    *label,
4278                                    const gchar *str)
4279 {
4280   GtkLabelPrivate *priv = label->priv;
4281   guint accel_key = GDK_KEY_VoidSymbol;
4282   gchar *new_str;
4283   gchar *pattern;
4284
4285   g_return_if_fail (GTK_IS_LABEL (label));
4286   g_return_if_fail (str != NULL);
4287
4288   /* Split text into the base text and a separate pattern
4289    * of underscores.
4290    */
4291   if (!separate_uline_pattern (str, &accel_key, &new_str, &pattern))
4292     return;
4293
4294   gtk_label_set_text_internal (label, new_str);
4295   gtk_label_set_pattern_internal (label, pattern, TRUE);
4296   priv->mnemonic_keyval = accel_key;
4297
4298   g_free (pattern);
4299 }
4300
4301 /**
4302  * gtk_label_set_text_with_mnemonic:
4303  * @label: a #GtkLabel
4304  * @str: a string
4305  * 
4306  * Sets the label's text from the string @str.
4307  * If characters in @str are preceded by an underscore, they are underlined
4308  * indicating that they represent a keyboard accelerator called a mnemonic.
4309  * The mnemonic key can be used to activate another widget, chosen 
4310  * automatically, or explicitly using gtk_label_set_mnemonic_widget().
4311  **/
4312 void
4313 gtk_label_set_text_with_mnemonic (GtkLabel    *label,
4314                                   const gchar *str)
4315 {
4316   g_return_if_fail (GTK_IS_LABEL (label));
4317   g_return_if_fail (str != NULL);
4318
4319   g_object_freeze_notify (G_OBJECT (label));
4320
4321   gtk_label_set_label_internal (label, g_strdup (str ? str : ""));
4322   gtk_label_set_use_markup_internal (label, FALSE);
4323   gtk_label_set_use_underline_internal (label, TRUE);
4324   
4325   gtk_label_recalculate (label);
4326
4327   g_object_thaw_notify (G_OBJECT (label));
4328 }
4329
4330 static void
4331 gtk_label_realize (GtkWidget *widget)
4332 {
4333   GtkLabel *label = GTK_LABEL (widget);
4334   GtkLabelPrivate *priv = label->priv;
4335
4336   GTK_WIDGET_CLASS (gtk_label_parent_class)->realize (widget);
4337
4338   if (priv->select_info)
4339     gtk_label_create_window (label);
4340 }
4341
4342 static void
4343 gtk_label_unrealize (GtkWidget *widget)
4344 {
4345   GtkLabel *label = GTK_LABEL (widget);
4346   GtkLabelPrivate *priv = label->priv;
4347
4348   if (priv->select_info)
4349     gtk_label_destroy_window (label);
4350
4351   GTK_WIDGET_CLASS (gtk_label_parent_class)->unrealize (widget);
4352 }
4353
4354 static void
4355 gtk_label_map (GtkWidget *widget)
4356 {
4357   GtkLabel *label = GTK_LABEL (widget);
4358   GtkLabelPrivate *priv = label->priv;
4359
4360   GTK_WIDGET_CLASS (gtk_label_parent_class)->map (widget);
4361
4362   if (priv->select_info)
4363     gdk_window_show (priv->select_info->window);
4364 }
4365
4366 static void
4367 gtk_label_unmap (GtkWidget *widget)
4368 {
4369   GtkLabel *label = GTK_LABEL (widget);
4370   GtkLabelPrivate *priv = label->priv;
4371
4372   if (priv->select_info)
4373     gdk_window_hide (priv->select_info->window);
4374
4375   GTK_WIDGET_CLASS (gtk_label_parent_class)->unmap (widget);
4376 }
4377
4378 static void
4379 window_to_layout_coords (GtkLabel *label,
4380                          gint     *x,
4381                          gint     *y)
4382 {
4383   GtkAllocation allocation;
4384   gint lx, ly;
4385   GtkWidget *widget;
4386
4387   widget = GTK_WIDGET (label);
4388   
4389   /* get layout location in widget->window coords */
4390   get_layout_location (label, &lx, &ly);
4391
4392   gtk_widget_get_allocation (widget, &allocation);
4393
4394   if (x)
4395     {
4396       *x += allocation.x; /* go to widget->window */
4397       *x -= lx;                   /* go to layout */
4398     }
4399
4400   if (y)
4401     {
4402       *y += allocation.y; /* go to widget->window */
4403       *y -= ly;                   /* go to layout */
4404     }
4405 }
4406
4407 #if 0
4408 static void
4409 layout_to_window_coords (GtkLabel *label,
4410                          gint     *x,
4411                          gint     *y)
4412 {
4413   gint lx, ly;
4414   GtkWidget *widget;
4415
4416   widget = GTK_WIDGET (label);
4417   
4418   /* get layout location in widget->window coords */
4419   get_layout_location (label, &lx, &ly);
4420   
4421   if (x)
4422     {
4423       *x += lx;                   /* go to widget->window */
4424       *x -= widget->allocation.x; /* go to selection window */
4425     }
4426
4427   if (y)
4428     {
4429       *y += ly;                   /* go to widget->window */
4430       *y -= widget->allocation.y; /* go to selection window */
4431     }
4432 }
4433 #endif
4434
4435 static gboolean
4436 get_layout_index (GtkLabel *label,
4437                   gint      x,
4438                   gint      y,
4439                   gint     *index)
4440 {
4441   GtkLabelPrivate *priv = label->priv;
4442   gint trailing = 0;
4443   const gchar *cluster;
4444   const gchar *cluster_end;
4445   gboolean inside;
4446
4447   *index = 0;
4448
4449   gtk_label_ensure_layout (label);
4450
4451   window_to_layout_coords (label, &x, &y);
4452
4453   x *= PANGO_SCALE;
4454   y *= PANGO_SCALE;
4455
4456   inside = pango_layout_xy_to_index (priv->layout,
4457                                      x, y,
4458                                      index, &trailing);
4459
4460   cluster = priv->text + *index;
4461   cluster_end = cluster;
4462   while (trailing)
4463     {
4464       cluster_end = g_utf8_next_char (cluster_end);
4465       --trailing;
4466     }
4467
4468   *index += (cluster_end - cluster);
4469
4470   return inside;
4471 }
4472
4473 static void
4474 gtk_label_select_word (GtkLabel *label)
4475 {
4476   GtkLabelPrivate *priv = label->priv;
4477   gint min, max;
4478
4479   gint start_index = gtk_label_move_backward_word (label, priv->select_info->selection_end);
4480   gint end_index = gtk_label_move_forward_word (label, priv->select_info->selection_end);
4481
4482   min = MIN (priv->select_info->selection_anchor,
4483              priv->select_info->selection_end);
4484   max = MAX (priv->select_info->selection_anchor,
4485              priv->select_info->selection_end);
4486
4487   min = MIN (min, start_index);
4488   max = MAX (max, end_index);
4489
4490   gtk_label_select_region_index (label, min, max);
4491 }
4492
4493 static void
4494 gtk_label_grab_focus (GtkWidget *widget)
4495 {
4496   GtkLabel *label = GTK_LABEL (widget);
4497   GtkLabelPrivate *priv = label->priv;
4498   gboolean select_on_focus;
4499   GtkLabelLink *link;
4500
4501   if (priv->select_info == NULL)
4502     return;
4503
4504   GTK_WIDGET_CLASS (gtk_label_parent_class)->grab_focus (widget);
4505
4506   if (priv->select_info->selectable)
4507     {
4508       g_object_get (gtk_widget_get_settings (widget),
4509                     "gtk-label-select-on-focus",
4510                     &select_on_focus,
4511                     NULL);
4512
4513       if (select_on_focus && !priv->in_click)
4514         gtk_label_select_region (label, 0, -1);
4515     }
4516   else
4517     {
4518       if (priv->select_info->links && !priv->in_click)
4519         {
4520           link = priv->select_info->links->data;
4521           priv->select_info->selection_anchor = link->start;
4522           priv->select_info->selection_end = link->start;
4523         }
4524     }
4525 }
4526
4527 static gboolean
4528 gtk_label_focus (GtkWidget        *widget,
4529                  GtkDirectionType  direction)
4530 {
4531   GtkLabel *label = GTK_LABEL (widget);
4532   GtkLabelPrivate *priv = label->priv;
4533   GtkLabelSelectionInfo *info = priv->select_info;
4534   GtkLabelLink *focus_link;
4535   GList *l;
4536
4537   if (!gtk_widget_is_focus (widget))
4538     {
4539       gtk_widget_grab_focus (widget);
4540       if (info)
4541         {
4542           focus_link = gtk_label_get_focus_link (label);
4543           if (focus_link && direction == GTK_DIR_TAB_BACKWARD)
4544             {
4545               l = g_list_last (info->links);
4546               focus_link = l->data;
4547               info->selection_anchor = focus_link->start;
4548               info->selection_end = focus_link->start;
4549             }
4550         }
4551
4552       return TRUE;
4553     }
4554
4555   if (!info)
4556     return FALSE;
4557
4558   if (info->selectable)
4559     {
4560       gint index;
4561
4562       if (info->selection_anchor != info->selection_end)
4563         goto out;
4564
4565       index = info->selection_anchor;
4566
4567       if (direction == GTK_DIR_TAB_FORWARD)
4568         for (l = info->links; l; l = l->next)
4569           {
4570             GtkLabelLink *link = l->data;
4571
4572             if (link->start > index)
4573               {
4574                 gtk_label_select_region_index (label, link->start, link->start);
4575                 return TRUE;
4576               }
4577           }
4578       else if (direction == GTK_DIR_TAB_BACKWARD)
4579         for (l = g_list_last (info->links); l; l = l->prev)
4580           {
4581             GtkLabelLink *link = l->data;
4582
4583             if (link->end < index)
4584               {
4585                 gtk_label_select_region_index (label, link->start, link->start);
4586                 return TRUE;
4587               }
4588           }
4589
4590       goto out;
4591     }
4592   else
4593     {
4594       focus_link = gtk_label_get_focus_link (label);
4595       switch (direction)
4596         {
4597         case GTK_DIR_TAB_FORWARD:
4598           if (focus_link)
4599             {
4600               l = g_list_find (info->links, focus_link);
4601               l = l->next;
4602             }
4603           else
4604             l = info->links;
4605           break;
4606
4607         case GTK_DIR_TAB_BACKWARD:
4608           if (focus_link)
4609             {
4610               l = g_list_find (info->links, focus_link);
4611               l = l->prev;
4612             }
4613           else
4614             l = g_list_last (info->links);
4615           break;
4616
4617         default:
4618           goto out;
4619         }
4620
4621       if (l)
4622         {
4623           focus_link = l->data;
4624           info->selection_anchor = focus_link->start;
4625           info->selection_end = focus_link->start;
4626           gtk_widget_queue_draw (widget);
4627
4628           return TRUE;
4629         }
4630     }
4631
4632 out:
4633
4634   return FALSE;
4635 }
4636
4637 static gboolean
4638 gtk_label_button_press (GtkWidget      *widget,
4639                         GdkEventButton *event)
4640 {
4641   GtkLabel *label = GTK_LABEL (widget);
4642   GtkLabelPrivate *priv = label->priv;
4643   GtkLabelSelectionInfo *info = priv->select_info;
4644   gint index = 0;
4645   gint min, max;
4646
4647   if (info == NULL)
4648     return FALSE;
4649
4650   if (info->active_link)
4651     {
4652       if (gdk_event_triggers_context_menu ((GdkEvent *) event))
4653         {
4654           info->link_clicked = 1;
4655           gtk_label_do_popup (label, event);
4656           return TRUE;
4657         }
4658       else if (event->button == 1)
4659         {
4660           info->link_clicked = 1;
4661           gtk_widget_queue_draw (widget);
4662         }
4663     }
4664
4665   if (!info->selectable)
4666     return FALSE;
4667
4668   info->in_drag = FALSE;
4669   info->select_words = FALSE;
4670
4671   if (gdk_event_triggers_context_menu ((GdkEvent *) event))
4672     {
4673       gtk_label_do_popup (label, event);
4674
4675       return TRUE;
4676     }
4677   else if (event->button == 1)
4678     {
4679       if (!gtk_widget_has_focus (widget))
4680         {
4681           priv->in_click = TRUE;
4682           gtk_widget_grab_focus (widget);
4683           priv->in_click = FALSE;
4684         }
4685
4686       if (event->type == GDK_3BUTTON_PRESS)
4687         {
4688           gtk_label_select_region_index (label, 0, strlen (priv->text));
4689           return TRUE;
4690         }
4691
4692       if (event->type == GDK_2BUTTON_PRESS)
4693         {
4694           info->select_words = TRUE;
4695           gtk_label_select_word (label);
4696           return TRUE;
4697         }
4698
4699       get_layout_index (label, event->x, event->y, &index);
4700
4701       min = MIN (info->selection_anchor, info->selection_end);
4702       max = MAX (info->selection_anchor, info->selection_end);
4703
4704       if ((info->selection_anchor != info->selection_end) &&
4705           (event->state & GDK_SHIFT_MASK))
4706         {
4707           if (index > min && index < max)
4708             {
4709               /* truncate selection, but keep it as big as possible */
4710               if (index - min > max - index)
4711                 max = index;
4712               else
4713                 min = index;
4714             }
4715           else
4716             {
4717               /* extend (same as motion) */
4718               min = MIN (min, index);
4719               max = MAX (max, index);
4720             }
4721
4722           /* ensure the anchor is opposite index */
4723           if (index == min)
4724             {
4725               gint tmp = min;
4726               min = max;
4727               max = tmp;
4728             }
4729
4730           gtk_label_select_region_index (label, min, max);
4731         }
4732       else
4733         {
4734           if (event->type == GDK_3BUTTON_PRESS)
4735             gtk_label_select_region_index (label, 0, strlen (priv->text));
4736           else if (event->type == GDK_2BUTTON_PRESS)
4737             gtk_label_select_word (label);
4738           else if (min < max && min <= index && index <= max)
4739             {
4740               info->in_drag = TRUE;
4741               info->drag_start_x = event->x;
4742               info->drag_start_y = event->y;
4743             }
4744           else
4745             /* start a replacement */
4746             gtk_label_select_region_index (label, index, index);
4747         }
4748
4749       return TRUE;
4750     }
4751
4752   return FALSE;
4753 }
4754
4755 static gboolean
4756 gtk_label_button_release (GtkWidget      *widget,
4757                           GdkEventButton *event)
4758
4759 {
4760   GtkLabel *label = GTK_LABEL (widget);
4761   GtkLabelPrivate *priv = label->priv;
4762   GtkLabelSelectionInfo *info = priv->select_info;
4763   gint index;
4764
4765   if (info == NULL)
4766     return FALSE;
4767
4768   if (info->in_drag)
4769     {
4770       info->in_drag = 0;
4771
4772       get_layout_index (label, event->x, event->y, &index);
4773       gtk_label_select_region_index (label, index, index);
4774
4775       return FALSE;
4776     }
4777
4778   if (event->button != 1)
4779     return FALSE;
4780
4781   if (info->active_link &&
4782       info->selection_anchor == info->selection_end &&
4783       info->link_clicked)
4784     {
4785       emit_activate_link (label, info->active_link);
4786       info->link_clicked = 0;
4787
4788       return TRUE;
4789     }
4790
4791   /* The goal here is to return TRUE iff we ate the
4792    * button press to start selecting.
4793    */
4794   return TRUE;
4795 }
4796
4797 static void
4798 connect_mnemonics_visible_notify (GtkLabel *label)
4799 {
4800   GtkLabelPrivate *priv = label->priv;
4801   GtkWidget *toplevel;
4802   gboolean connected;
4803
4804   toplevel = gtk_widget_get_toplevel (GTK_WIDGET (label));
4805
4806   if (!GTK_IS_WINDOW (toplevel))
4807     return;
4808
4809   /* always set up this widgets initial value */
4810   priv->mnemonics_visible =
4811     gtk_window_get_mnemonics_visible (GTK_WINDOW (toplevel));
4812
4813   connected =
4814     GPOINTER_TO_INT (g_object_get_data (G_OBJECT (toplevel),
4815                                         "gtk-label-mnemonics-visible-connected"));
4816
4817   if (!connected)
4818     {
4819       g_signal_connect (toplevel,
4820                         "notify::mnemonics-visible",
4821                         G_CALLBACK (label_mnemonics_visible_changed),
4822                         label);
4823       g_object_set_data (G_OBJECT (toplevel),
4824                          "gtk-label-mnemonics-visible-connected",
4825                          GINT_TO_POINTER (1));
4826     }
4827 }
4828
4829 static void
4830 drag_begin_cb (GtkWidget      *widget,
4831                GdkDragContext *context,
4832                gpointer        data)
4833 {
4834   GtkLabel *label = GTK_LABEL (widget);
4835   GtkLabelPrivate *priv = label->priv;
4836   cairo_surface_t *surface = NULL;
4837
4838   g_signal_handlers_disconnect_by_func (widget, drag_begin_cb, NULL);
4839
4840   if ((priv->select_info->selection_anchor !=
4841        priv->select_info->selection_end) &&
4842       priv->text)
4843     {
4844       gint start, end;
4845       gint len;
4846
4847       start = MIN (priv->select_info->selection_anchor,
4848                    priv->select_info->selection_end);
4849       end = MAX (priv->select_info->selection_anchor,
4850                  priv->select_info->selection_end);
4851
4852       len = strlen (priv->text);
4853
4854       if (end > len)
4855         end = len;
4856
4857       if (start > len)
4858         start = len;
4859
4860       surface = _gtk_text_util_create_drag_icon (widget,
4861                                                  priv->text + start,
4862                                                  end - start);
4863     }
4864
4865   if (surface)
4866     {
4867       gtk_drag_set_icon_surface (context, surface);
4868       cairo_surface_destroy (surface);
4869     }
4870   else
4871     {
4872       gtk_drag_set_icon_default (context);
4873     }
4874 }
4875
4876 static gboolean
4877 gtk_label_motion (GtkWidget      *widget,
4878                   GdkEventMotion *event)
4879 {
4880   GtkLabel *label = GTK_LABEL (widget);
4881   GtkLabelPrivate *priv = label->priv;
4882   GtkLabelSelectionInfo *info = priv->select_info;
4883   gint index;
4884
4885   if (info == NULL)
4886     return FALSE;
4887
4888   if (info->links && !info->in_drag)
4889     {
4890       GList *l;
4891       GtkLabelLink *link;
4892       gboolean found = FALSE;
4893
4894       if (info->selection_anchor == info->selection_end)
4895         {
4896           if (get_layout_index (label, event->x, event->y, &index))
4897             {
4898               for (l = info->links; l != NULL; l = l->next)
4899                 {
4900                   link = l->data;
4901                   if (index >= link->start && index <= link->end)
4902                     {
4903                       found = TRUE;
4904                       break;
4905                     }
4906                 }
4907             }
4908         }
4909
4910       if (found)
4911         {
4912           if (info->active_link != link)
4913             {
4914               info->link_clicked = 0;
4915               info->active_link = link;
4916               gtk_label_update_cursor (label);
4917               gtk_widget_queue_draw (widget);
4918             }
4919         }
4920       else
4921         {
4922           if (info->active_link != NULL)
4923             {
4924               info->link_clicked = 0;
4925               info->active_link = NULL;
4926               gtk_label_update_cursor (label);
4927               gtk_widget_queue_draw (widget);
4928             }
4929         }
4930     }
4931
4932   if (!info->selectable)
4933     return FALSE;
4934
4935   if ((event->state & GDK_BUTTON1_MASK) == 0)
4936     return FALSE;
4937
4938   if (info->in_drag)
4939     {
4940       if (gtk_drag_check_threshold (widget,
4941                                     info->drag_start_x,
4942                                     info->drag_start_y,
4943                                     event->x, event->y))
4944         {
4945           GtkTargetList *target_list = gtk_target_list_new (NULL, 0);
4946
4947           gtk_target_list_add_text_targets (target_list, 0);
4948
4949           g_signal_connect (widget, "drag-begin",
4950                             G_CALLBACK (drag_begin_cb), NULL);
4951           gtk_drag_begin (widget, target_list,
4952                           GDK_ACTION_COPY,
4953                           1, (GdkEvent *)event);
4954
4955           info->in_drag = FALSE;
4956
4957           gtk_target_list_unref (target_list);
4958         }
4959     }
4960   else
4961     {
4962       gint x, y;
4963
4964       gdk_window_get_device_position (info->window, event->device, &x, &y, NULL);
4965       get_layout_index (label, x, y, &index);
4966
4967       if (info->select_words)
4968         {
4969           gint min, max;
4970           gint old_min, old_max;
4971           gint anchor, end;
4972
4973           min = gtk_label_move_backward_word (label, index);
4974           max = gtk_label_move_forward_word (label, index);
4975
4976           anchor = info->selection_anchor;
4977           end = info->selection_end;
4978
4979           old_min = MIN (anchor, end);
4980           old_max = MAX (anchor, end);
4981
4982           if (min < old_min)
4983             {
4984               anchor = min;
4985               end = old_max;
4986             }
4987           else if (old_max < max)
4988             {
4989               anchor = max;
4990               end = old_min;
4991             }
4992           else if (anchor == old_min)
4993             {
4994               if (anchor != min)
4995                 anchor = max;
4996             }
4997           else
4998             {
4999               if (anchor != max)
5000                 anchor = min;
5001             }
5002
5003           gtk_label_select_region_index (label, anchor, end);
5004         }
5005       else
5006         gtk_label_select_region_index (label, info->selection_anchor, index);
5007     }
5008
5009   return TRUE;
5010 }
5011
5012 static gboolean
5013 gtk_label_leave_notify (GtkWidget        *widget,
5014                         GdkEventCrossing *event)
5015 {
5016   GtkLabel *label = GTK_LABEL (widget);
5017   GtkLabelPrivate *priv = label->priv;
5018
5019   if (priv->select_info)
5020     {
5021       priv->select_info->active_link = NULL;
5022       gtk_label_update_cursor (label);
5023       gtk_widget_queue_draw (widget);
5024     }
5025
5026   if (GTK_WIDGET_CLASS (gtk_label_parent_class)->leave_notify_event)
5027     return GTK_WIDGET_CLASS (gtk_label_parent_class)->leave_notify_event (widget, event);
5028
5029  return FALSE;
5030 }
5031
5032 static void
5033 gtk_label_create_window (GtkLabel *label)
5034 {
5035   GtkLabelPrivate *priv = label->priv;
5036   GtkAllocation allocation;
5037   GtkWidget *widget;
5038   GdkWindowAttr attributes;
5039   gint attributes_mask;
5040
5041   g_assert (priv->select_info);
5042   widget = GTK_WIDGET (label);
5043   g_assert (gtk_widget_get_realized (widget));
5044
5045   if (priv->select_info->window)
5046     return;
5047
5048   gtk_widget_get_allocation (widget, &allocation);
5049
5050   attributes.x = allocation.x;
5051   attributes.y = allocation.y;
5052   attributes.width = allocation.width;
5053   attributes.height = allocation.height;
5054   attributes.window_type = GDK_WINDOW_CHILD;
5055   attributes.wclass = GDK_INPUT_ONLY;
5056   attributes.override_redirect = TRUE;
5057   attributes.event_mask = gtk_widget_get_events (widget) |
5058     GDK_BUTTON_PRESS_MASK        |
5059     GDK_BUTTON_RELEASE_MASK      |
5060     GDK_LEAVE_NOTIFY_MASK        |
5061     GDK_BUTTON_MOTION_MASK       |
5062     GDK_POINTER_MOTION_MASK      |
5063     GDK_POINTER_MOTION_HINT_MASK;
5064   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_NOREDIR;
5065   if (gtk_widget_is_sensitive (widget))
5066     {
5067       attributes.cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget),
5068                                                       GDK_XTERM);
5069       attributes_mask |= GDK_WA_CURSOR;
5070     }
5071
5072
5073   priv->select_info->window = gdk_window_new (gtk_widget_get_window (widget),
5074                                                &attributes, attributes_mask);
5075   gdk_window_set_user_data (priv->select_info->window, widget);
5076
5077   if (attributes_mask & GDK_WA_CURSOR)
5078     g_object_unref (attributes.cursor);
5079 }
5080
5081 static void
5082 gtk_label_destroy_window (GtkLabel *label)
5083 {
5084   GtkLabelPrivate *priv = label->priv;
5085
5086   g_assert (priv->select_info);
5087
5088   if (priv->select_info->window == NULL)
5089     return;
5090
5091   gdk_window_set_user_data (priv->select_info->window, NULL);
5092   gdk_window_destroy (priv->select_info->window);
5093   priv->select_info->window = NULL;
5094 }
5095
5096 static void
5097 gtk_label_ensure_select_info (GtkLabel *label)
5098 {
5099   GtkLabelPrivate *priv = label->priv;
5100
5101   if (priv->select_info == NULL)
5102     {
5103       priv->select_info = g_new0 (GtkLabelSelectionInfo, 1);
5104
5105       gtk_widget_set_can_focus (GTK_WIDGET (label), TRUE);
5106
5107       if (gtk_widget_get_realized (GTK_WIDGET (label)))
5108         gtk_label_create_window (label);
5109
5110       if (gtk_widget_get_mapped (GTK_WIDGET (label)))
5111         gdk_window_show (priv->select_info->window);
5112     }
5113 }
5114
5115 static void
5116 gtk_label_clear_select_info (GtkLabel *label)
5117 {
5118   GtkLabelPrivate *priv = label->priv;
5119
5120   if (priv->select_info == NULL)
5121     return;
5122
5123   if (!priv->select_info->selectable && !priv->select_info->links)
5124     {
5125       gtk_label_destroy_window (label);
5126
5127       g_free (priv->select_info);
5128       priv->select_info = NULL;
5129
5130       gtk_widget_set_can_focus (GTK_WIDGET (label), FALSE);
5131     }
5132 }
5133
5134 /**
5135  * gtk_label_set_selectable:
5136  * @label: a #GtkLabel
5137  * @setting: %TRUE to allow selecting text in the label
5138  *
5139  * Selectable labels allow the user to select text from the label, for
5140  * copy-and-paste.
5141  **/
5142 void
5143 gtk_label_set_selectable (GtkLabel *label,
5144                           gboolean  setting)
5145 {
5146   GtkLabelPrivate *priv;
5147   gboolean old_setting;
5148
5149   g_return_if_fail (GTK_IS_LABEL (label));
5150
5151   priv = label->priv;
5152
5153   setting = setting != FALSE;
5154   old_setting = priv->select_info && priv->select_info->selectable;
5155
5156   if (setting)
5157     {
5158       gtk_label_ensure_select_info (label);
5159       priv->select_info->selectable = TRUE;
5160       gtk_label_update_cursor (label);
5161     }
5162   else
5163     {
5164       if (old_setting)
5165         {
5166           /* unselect, to give up the selection */
5167           gtk_label_select_region (label, 0, 0);
5168
5169           priv->select_info->selectable = FALSE;
5170           gtk_label_clear_select_info (label);
5171           gtk_label_update_cursor (label);
5172         }
5173     }
5174   if (setting != old_setting)
5175     {
5176       g_object_freeze_notify (G_OBJECT (label));
5177       g_object_notify (G_OBJECT (label), "selectable");
5178       g_object_notify (G_OBJECT (label), "cursor-position");
5179       g_object_notify (G_OBJECT (label), "selection-bound");
5180       g_object_thaw_notify (G_OBJECT (label));
5181       gtk_widget_queue_draw (GTK_WIDGET (label));
5182     }
5183 }
5184
5185 /**
5186  * gtk_label_get_selectable:
5187  * @label: a #GtkLabel
5188  * 
5189  * Gets the value set by gtk_label_set_selectable().
5190  * 
5191  * Return value: %TRUE if the user can copy text from the label
5192  **/
5193 gboolean
5194 gtk_label_get_selectable (GtkLabel *label)
5195 {
5196   GtkLabelPrivate *priv;
5197
5198   g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
5199
5200   priv = label->priv;
5201
5202   return priv->select_info && priv->select_info->selectable;
5203 }
5204
5205 /**
5206  * gtk_label_set_angle:
5207  * @label: a #GtkLabel
5208  * @angle: the angle that the baseline of the label makes with
5209  *   the horizontal, in degrees, measured counterclockwise
5210  * 
5211  * Sets the angle of rotation for the label. An angle of 90 reads from
5212  * from bottom to top, an angle of 270, from top to bottom. The angle
5213  * setting for the label is ignored if the label is selectable,
5214  * wrapped, or ellipsized.
5215  *
5216  * Since: 2.6
5217  **/
5218 void
5219 gtk_label_set_angle (GtkLabel *label,
5220                      gdouble   angle)
5221 {
5222   GtkLabelPrivate *priv;
5223
5224   g_return_if_fail (GTK_IS_LABEL (label));
5225
5226   priv = label->priv;
5227
5228   /* Canonicalize to [0,360]. We don't canonicalize 360 to 0, because
5229    * double property ranges are inclusive, and changing 360 to 0 would
5230    * make a property editor behave strangely.
5231    */
5232   if (angle < 0 || angle > 360.0)
5233     angle = angle - 360. * floor (angle / 360.);
5234
5235   if (priv->angle != angle)
5236     {
5237       priv->angle = angle;
5238       
5239       gtk_label_clear_layout (label);
5240       gtk_widget_queue_resize (GTK_WIDGET (label));
5241
5242       g_object_notify (G_OBJECT (label), "angle");
5243     }
5244 }
5245
5246 /**
5247  * gtk_label_get_angle:
5248  * @label: a #GtkLabel
5249  * 
5250  * Gets the angle of rotation for the label. See
5251  * gtk_label_set_angle().
5252  * 
5253  * Return value: the angle of rotation for the label
5254  *
5255  * Since: 2.6
5256  **/
5257 gdouble
5258 gtk_label_get_angle  (GtkLabel *label)
5259 {
5260   g_return_val_if_fail (GTK_IS_LABEL (label), 0.0);
5261   
5262   return label->priv->angle;
5263 }
5264
5265 static void
5266 gtk_label_set_selection_text (GtkLabel         *label,
5267                               GtkSelectionData *selection_data)
5268 {
5269   GtkLabelPrivate *priv = label->priv;
5270
5271   if (priv->select_info &&
5272       (priv->select_info->selection_anchor !=
5273        priv->select_info->selection_end) &&
5274       priv->text)
5275     {
5276       gint start, end;
5277       gint len;
5278
5279       start = MIN (priv->select_info->selection_anchor,
5280                    priv->select_info->selection_end);
5281       end = MAX (priv->select_info->selection_anchor,
5282                  priv->select_info->selection_end);
5283
5284       len = strlen (priv->text);
5285
5286       if (end > len)
5287         end = len;
5288
5289       if (start > len)
5290         start = len;
5291
5292       gtk_selection_data_set_text (selection_data,
5293                                    priv->text + start,
5294                                    end - start);
5295     }
5296 }
5297
5298 static void
5299 gtk_label_drag_data_get (GtkWidget        *widget,
5300                          GdkDragContext   *context,
5301                          GtkSelectionData *selection_data,
5302                          guint             info,
5303                          guint             time)
5304 {
5305   gtk_label_set_selection_text (GTK_LABEL (widget), selection_data);
5306 }
5307
5308 static void
5309 get_text_callback (GtkClipboard     *clipboard,
5310                    GtkSelectionData *selection_data,
5311                    guint             info,
5312                    gpointer          user_data_or_owner)
5313 {
5314   gtk_label_set_selection_text (GTK_LABEL (user_data_or_owner), selection_data);
5315 }
5316
5317 static void
5318 clear_text_callback (GtkClipboard     *clipboard,
5319                      gpointer          user_data_or_owner)
5320 {
5321   GtkLabel *label;
5322   GtkLabelPrivate *priv;
5323
5324   label = GTK_LABEL (user_data_or_owner);
5325   priv = label->priv;
5326
5327   if (priv->select_info)
5328     {
5329       priv->select_info->selection_anchor = priv->select_info->selection_end;
5330
5331       gtk_widget_queue_draw (GTK_WIDGET (label));
5332     }
5333 }
5334
5335 static void
5336 gtk_label_select_region_index (GtkLabel *label,
5337                                gint      anchor_index,
5338                                gint      end_index)
5339 {
5340   GtkLabelPrivate *priv;
5341
5342   g_return_if_fail (GTK_IS_LABEL (label));
5343
5344   priv = label->priv;
5345
5346   if (priv->select_info && priv->select_info->selectable)
5347     {
5348       GtkClipboard *clipboard;
5349
5350       if (priv->select_info->selection_anchor == anchor_index &&
5351           priv->select_info->selection_end == end_index)
5352         return;
5353
5354       g_object_freeze_notify (G_OBJECT (label));
5355
5356       if (priv->select_info->selection_anchor != anchor_index)
5357         g_object_notify (G_OBJECT (label), "selection-bound");
5358       if (priv->select_info->selection_end != end_index)
5359         g_object_notify (G_OBJECT (label), "cursor-position");
5360
5361       priv->select_info->selection_anchor = anchor_index;
5362       priv->select_info->selection_end = end_index;
5363
5364       if (gtk_widget_has_screen (GTK_WIDGET (label)))
5365         clipboard = gtk_widget_get_clipboard (GTK_WIDGET (label),
5366                                               GDK_SELECTION_PRIMARY);
5367       else
5368         clipboard = NULL;
5369
5370       if (anchor_index != end_index)
5371         {
5372           GtkTargetList *list;
5373           GtkTargetEntry *targets;
5374           gint n_targets;
5375
5376           list = gtk_target_list_new (NULL, 0);
5377           gtk_target_list_add_text_targets (list, 0);
5378           targets = gtk_target_table_new_from_list (list, &n_targets);
5379
5380           if (clipboard)
5381             gtk_clipboard_set_with_owner (clipboard,
5382                                           targets, n_targets,
5383                                           get_text_callback,
5384                                           clear_text_callback,
5385                                           G_OBJECT (label));
5386
5387           gtk_target_table_free (targets, n_targets);
5388           gtk_target_list_unref (list);
5389         }
5390       else
5391         {
5392           if (clipboard &&
5393               gtk_clipboard_get_owner (clipboard) == G_OBJECT (label))
5394             gtk_clipboard_clear (clipboard);
5395         }
5396
5397       gtk_widget_queue_draw (GTK_WIDGET (label));
5398
5399       g_object_thaw_notify (G_OBJECT (label));
5400     }
5401 }
5402
5403 /**
5404  * gtk_label_select_region:
5405  * @label: a #GtkLabel
5406  * @start_offset: start offset (in characters not bytes)
5407  * @end_offset: end offset (in characters not bytes)
5408  *
5409  * Selects a range of characters in the label, if the label is selectable.
5410  * See gtk_label_set_selectable(). If the label is not selectable,
5411  * this function has no effect. If @start_offset or
5412  * @end_offset are -1, then the end of the label will be substituted.
5413  **/
5414 void
5415 gtk_label_select_region  (GtkLabel *label,
5416                           gint      start_offset,
5417                           gint      end_offset)
5418 {
5419   GtkLabelPrivate *priv;
5420
5421   g_return_if_fail (GTK_IS_LABEL (label));
5422
5423   priv = label->priv;
5424
5425   if (priv->text && priv->select_info)
5426     {
5427       if (start_offset < 0)
5428         start_offset = g_utf8_strlen (priv->text, -1);
5429       
5430       if (end_offset < 0)
5431         end_offset = g_utf8_strlen (priv->text, -1);
5432       
5433       gtk_label_select_region_index (label,
5434                                      g_utf8_offset_to_pointer (priv->text, start_offset) - priv->text,
5435                                      g_utf8_offset_to_pointer (priv->text, end_offset) - priv->text);
5436     }
5437 }
5438
5439 /**
5440  * gtk_label_get_selection_bounds:
5441  * @label: a #GtkLabel
5442  * @start: (out): return location for start of selection, as a character offset
5443  * @end: (out): return location for end of selection, as a character offset
5444  * 
5445  * Gets the selected range of characters in the label, returning %TRUE
5446  * if there's a selection.
5447  * 
5448  * Return value: %TRUE if selection is non-empty
5449  **/
5450 gboolean
5451 gtk_label_get_selection_bounds (GtkLabel  *label,
5452                                 gint      *start,
5453                                 gint      *end)
5454 {
5455   GtkLabelPrivate *priv;
5456
5457   g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
5458
5459   priv = label->priv;
5460
5461   if (priv->select_info == NULL)
5462     {
5463       /* not a selectable label */
5464       if (start)
5465         *start = 0;
5466       if (end)
5467         *end = 0;
5468
5469       return FALSE;
5470     }
5471   else
5472     {
5473       gint start_index, end_index;
5474       gint start_offset, end_offset;
5475       gint len;
5476       
5477       start_index = MIN (priv->select_info->selection_anchor,
5478                    priv->select_info->selection_end);
5479       end_index = MAX (priv->select_info->selection_anchor,
5480                  priv->select_info->selection_end);
5481
5482       len = strlen (priv->text);
5483
5484       if (end_index > len)
5485         end_index = len;
5486
5487       if (start_index > len)
5488         start_index = len;
5489       
5490       start_offset = g_utf8_strlen (priv->text, start_index);
5491       end_offset = g_utf8_strlen (priv->text, end_index);
5492
5493       if (start_offset > end_offset)
5494         {
5495           gint tmp = start_offset;
5496           start_offset = end_offset;
5497           end_offset = tmp;
5498         }
5499       
5500       if (start)
5501         *start = start_offset;
5502
5503       if (end)
5504         *end = end_offset;
5505
5506       return start_offset != end_offset;
5507     }
5508 }
5509
5510
5511 /**
5512  * gtk_label_get_layout:
5513  * @label: a #GtkLabel
5514  * 
5515  * Gets the #PangoLayout used to display the label.
5516  * The layout is useful to e.g. convert text positions to
5517  * pixel positions, in combination with gtk_label_get_layout_offsets().
5518  * The returned layout is owned by the @label so need not be
5519  * freed by the caller. The @label is free to recreate its layout at
5520  * any time, so it should be considered read-only.
5521  *
5522  * Return value: (transfer none): the #PangoLayout for this label
5523  **/
5524 PangoLayout*
5525 gtk_label_get_layout (GtkLabel *label)
5526 {
5527   GtkLabelPrivate *priv;
5528
5529   g_return_val_if_fail (GTK_IS_LABEL (label), NULL);
5530
5531   priv = label->priv;
5532
5533   gtk_label_ensure_layout (label);
5534
5535   return priv->layout;
5536 }
5537
5538 /**
5539  * gtk_label_get_layout_offsets:
5540  * @label: a #GtkLabel
5541  * @x: (out) (allow-none): location to store X offset of layout, or %NULL
5542  * @y: (out) (allow-none): location to store Y offset of layout, or %NULL
5543  *
5544  * Obtains the coordinates where the label will draw the #PangoLayout
5545  * representing the text in the label; useful to convert mouse events
5546  * into coordinates inside the #PangoLayout, e.g. to take some action
5547  * if some part of the label is clicked. Of course you will need to
5548  * create a #GtkEventBox to receive the events, and pack the label
5549  * inside it, since labels are a #GTK_NO_WINDOW widget. Remember
5550  * when using the #PangoLayout functions you need to convert to
5551  * and from pixels using PANGO_PIXELS() or #PANGO_SCALE.
5552  **/
5553 void
5554 gtk_label_get_layout_offsets (GtkLabel *label,
5555                               gint     *x,
5556                               gint     *y)
5557 {
5558   g_return_if_fail (GTK_IS_LABEL (label));
5559
5560   gtk_label_ensure_layout (label);
5561
5562   get_layout_location (label, x, y);
5563 }
5564
5565 /**
5566  * gtk_label_set_use_markup:
5567  * @label: a #GtkLabel
5568  * @setting: %TRUE if the label's text should be parsed for markup.
5569  *
5570  * Sets whether the text of the label contains markup in <link
5571  * linkend="PangoMarkupFormat">Pango's text markup
5572  * language</link>. See gtk_label_set_markup().
5573  **/
5574 void
5575 gtk_label_set_use_markup (GtkLabel *label,
5576                           gboolean  setting)
5577 {
5578   g_return_if_fail (GTK_IS_LABEL (label));
5579
5580   g_object_freeze_notify (G_OBJECT (label));
5581
5582   gtk_label_set_use_markup_internal (label, setting);
5583   gtk_label_recalculate (label);
5584
5585   g_object_thaw_notify (G_OBJECT (label));
5586 }
5587
5588 /**
5589  * gtk_label_get_use_markup:
5590  * @label: a #GtkLabel
5591  *
5592  * Returns whether the label's text is interpreted as marked up with
5593  * the <link linkend="PangoMarkupFormat">Pango text markup
5594  * language</link>. See gtk_label_set_use_markup ().
5595  *
5596  * Return value: %TRUE if the label's text will be parsed for markup.
5597  **/
5598 gboolean
5599 gtk_label_get_use_markup (GtkLabel *label)
5600 {
5601   g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
5602
5603   return label->priv->use_markup;
5604 }
5605
5606 /**
5607  * gtk_label_set_use_underline:
5608  * @label: a #GtkLabel
5609  * @setting: %TRUE if underlines in the text indicate mnemonics
5610  *
5611  * If true, an underline in the text indicates the next character should be
5612  * used for the mnemonic accelerator key.
5613  */
5614 void
5615 gtk_label_set_use_underline (GtkLabel *label,
5616                              gboolean  setting)
5617 {
5618   g_return_if_fail (GTK_IS_LABEL (label));
5619
5620   g_object_freeze_notify (G_OBJECT (label));
5621
5622   gtk_label_set_use_underline_internal (label, setting);
5623   gtk_label_recalculate (label);
5624
5625   g_object_thaw_notify (G_OBJECT (label));
5626 }
5627
5628 /**
5629  * gtk_label_get_use_underline:
5630  * @label: a #GtkLabel
5631  *
5632  * Returns whether an embedded underline in the label indicates a
5633  * mnemonic. See gtk_label_set_use_underline().
5634  *
5635  * Return value: %TRUE whether an embedded underline in the label indicates
5636  *               the mnemonic accelerator keys.
5637  **/
5638 gboolean
5639 gtk_label_get_use_underline (GtkLabel *label)
5640 {
5641   g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
5642
5643   return label->priv->use_underline;
5644 }
5645
5646 /**
5647  * gtk_label_set_single_line_mode:
5648  * @label: a #GtkLabel
5649  * @single_line_mode: %TRUE if the label should be in single line mode
5650  *
5651  * Sets whether the label is in single line mode.
5652  *
5653  * Since: 2.6
5654  */
5655 void
5656 gtk_label_set_single_line_mode (GtkLabel *label,
5657                                 gboolean single_line_mode)
5658 {
5659   GtkLabelPrivate *priv;
5660
5661   g_return_if_fail (GTK_IS_LABEL (label));
5662
5663   priv = label->priv;
5664
5665   single_line_mode = single_line_mode != FALSE;
5666
5667   if (priv->single_line_mode != single_line_mode)
5668     {
5669       priv->single_line_mode = single_line_mode;
5670
5671       gtk_label_clear_layout (label);
5672       gtk_widget_queue_resize (GTK_WIDGET (label));
5673
5674       g_object_notify (G_OBJECT (label), "single-line-mode");
5675     }
5676 }
5677
5678 /**
5679  * gtk_label_get_single_line_mode:
5680  * @label: a #GtkLabel
5681  *
5682  * Returns whether the label is in single line mode.
5683  *
5684  * Return value: %TRUE when the label is in single line mode.
5685  *
5686  * Since: 2.6
5687  **/
5688 gboolean
5689 gtk_label_get_single_line_mode  (GtkLabel *label)
5690 {
5691   g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
5692
5693   return label->priv->single_line_mode;
5694 }
5695
5696 /* Compute the X position for an offset that corresponds to the "more important
5697  * cursor position for that offset. We use this when trying to guess to which
5698  * end of the selection we should go to when the user hits the left or
5699  * right arrow key.
5700  */
5701 static void
5702 get_better_cursor (GtkLabel *label,
5703                    gint      index,
5704                    gint      *x,
5705                    gint      *y)
5706 {
5707   GtkLabelPrivate *priv = label->priv;
5708   GdkKeymap *keymap = gdk_keymap_get_for_display (gtk_widget_get_display (GTK_WIDGET (label)));
5709   PangoDirection keymap_direction = gdk_keymap_get_direction (keymap);
5710   PangoDirection cursor_direction = get_cursor_direction (label);
5711   gboolean split_cursor;
5712   PangoRectangle strong_pos, weak_pos;
5713   
5714   g_object_get (gtk_widget_get_settings (GTK_WIDGET (label)),
5715                 "gtk-split-cursor", &split_cursor,
5716                 NULL);
5717
5718   gtk_label_ensure_layout (label);
5719   
5720   pango_layout_get_cursor_pos (priv->layout, index,
5721                                &strong_pos, &weak_pos);
5722
5723   if (split_cursor)
5724     {
5725       *x = strong_pos.x / PANGO_SCALE;
5726       *y = strong_pos.y / PANGO_SCALE;
5727     }
5728   else
5729     {
5730       if (keymap_direction == cursor_direction)
5731         {
5732           *x = strong_pos.x / PANGO_SCALE;
5733           *y = strong_pos.y / PANGO_SCALE;
5734         }
5735       else
5736         {
5737           *x = weak_pos.x / PANGO_SCALE;
5738           *y = weak_pos.y / PANGO_SCALE;
5739         }
5740     }
5741 }
5742
5743
5744 static gint
5745 gtk_label_move_logically (GtkLabel *label,
5746                           gint      start,
5747                           gint      count)
5748 {
5749   GtkLabelPrivate *priv = label->priv;
5750   gint offset = g_utf8_pointer_to_offset (priv->text,
5751                                           priv->text + start);
5752
5753   if (priv->text)
5754     {
5755       PangoLogAttr *log_attrs;
5756       gint n_attrs;
5757       gint length;
5758
5759       gtk_label_ensure_layout (label);
5760       
5761       length = g_utf8_strlen (priv->text, -1);
5762
5763       pango_layout_get_log_attrs (priv->layout, &log_attrs, &n_attrs);
5764
5765       while (count > 0 && offset < length)
5766         {
5767           do
5768             offset++;
5769           while (offset < length && !log_attrs[offset].is_cursor_position);
5770           
5771           count--;
5772         }
5773       while (count < 0 && offset > 0)
5774         {
5775           do
5776             offset--;
5777           while (offset > 0 && !log_attrs[offset].is_cursor_position);
5778           
5779           count++;
5780         }
5781       
5782       g_free (log_attrs);
5783     }
5784
5785   return g_utf8_offset_to_pointer (priv->text, offset) - priv->text;
5786 }
5787
5788 static gint
5789 gtk_label_move_visually (GtkLabel *label,
5790                          gint      start,
5791                          gint      count)
5792 {
5793   GtkLabelPrivate *priv = label->priv;
5794   gint index;
5795
5796   index = start;
5797   
5798   while (count != 0)
5799     {
5800       int new_index, new_trailing;
5801       gboolean split_cursor;
5802       gboolean strong;
5803
5804       gtk_label_ensure_layout (label);
5805
5806       g_object_get (gtk_widget_get_settings (GTK_WIDGET (label)),
5807                     "gtk-split-cursor", &split_cursor,
5808                     NULL);
5809
5810       if (split_cursor)
5811         strong = TRUE;
5812       else
5813         {
5814           GdkKeymap *keymap = gdk_keymap_get_for_display (gtk_widget_get_display (GTK_WIDGET (label)));
5815           PangoDirection keymap_direction = gdk_keymap_get_direction (keymap);
5816
5817           strong = keymap_direction == get_cursor_direction (label);
5818         }
5819       
5820       if (count > 0)
5821         {
5822           pango_layout_move_cursor_visually (priv->layout, strong, index, 0, 1, &new_index, &new_trailing);
5823           count--;
5824         }
5825       else
5826         {
5827           pango_layout_move_cursor_visually (priv->layout, strong, index, 0, -1, &new_index, &new_trailing);
5828           count++;
5829         }
5830
5831       if (new_index < 0 || new_index == G_MAXINT)
5832         break;
5833
5834       index = new_index;
5835       
5836       while (new_trailing--)
5837         index = g_utf8_next_char (priv->text + new_index) - priv->text;
5838     }
5839   
5840   return index;
5841 }
5842
5843 static gint
5844 gtk_label_move_forward_word (GtkLabel *label,
5845                              gint      start)
5846 {
5847   GtkLabelPrivate *priv = label->priv;
5848   gint new_pos = g_utf8_pointer_to_offset (priv->text,
5849                                            priv->text + start);
5850   gint length;
5851
5852   length = g_utf8_strlen (priv->text, -1);
5853   if (new_pos < length)
5854     {
5855       PangoLogAttr *log_attrs;
5856       gint n_attrs;
5857
5858       gtk_label_ensure_layout (label);
5859
5860       pango_layout_get_log_attrs (priv->layout, &log_attrs, &n_attrs);
5861
5862       /* Find the next word end */
5863       new_pos++;
5864       while (new_pos < n_attrs && !log_attrs[new_pos].is_word_end)
5865         new_pos++;
5866
5867       g_free (log_attrs);
5868     }
5869
5870   return g_utf8_offset_to_pointer (priv->text, new_pos) - priv->text;
5871 }
5872
5873
5874 static gint
5875 gtk_label_move_backward_word (GtkLabel *label,
5876                               gint      start)
5877 {
5878   GtkLabelPrivate *priv = label->priv;
5879   gint new_pos = g_utf8_pointer_to_offset (priv->text,
5880                                            priv->text + start);
5881
5882   if (new_pos > 0)
5883     {
5884       PangoLogAttr *log_attrs;
5885       gint n_attrs;
5886
5887       gtk_label_ensure_layout (label);
5888
5889       pango_layout_get_log_attrs (priv->layout, &log_attrs, &n_attrs);
5890
5891       new_pos -= 1;
5892
5893       /* Find the previous word beginning */
5894       while (new_pos > 0 && !log_attrs[new_pos].is_word_start)
5895         new_pos--;
5896
5897       g_free (log_attrs);
5898     }
5899
5900   return g_utf8_offset_to_pointer (priv->text, new_pos) - priv->text;
5901 }
5902
5903 static void
5904 gtk_label_move_cursor (GtkLabel       *label,
5905                        GtkMovementStep step,
5906                        gint            count,
5907                        gboolean        extend_selection)
5908 {
5909   GtkLabelPrivate *priv = label->priv;
5910   gint old_pos;
5911   gint new_pos;
5912
5913   if (priv->select_info == NULL)
5914     return;
5915
5916   old_pos = new_pos = priv->select_info->selection_end;
5917
5918   if (priv->select_info->selection_end != priv->select_info->selection_anchor &&
5919       !extend_selection)
5920     {
5921       /* If we have a current selection and aren't extending it, move to the
5922        * start/or end of the selection as appropriate
5923        */
5924       switch (step)
5925         {
5926         case GTK_MOVEMENT_VISUAL_POSITIONS:
5927           {
5928             gint end_x, end_y;
5929             gint anchor_x, anchor_y;
5930             gboolean end_is_left;
5931
5932             get_better_cursor (label, priv->select_info->selection_end, &end_x, &end_y);
5933             get_better_cursor (label, priv->select_info->selection_anchor, &anchor_x, &anchor_y);
5934
5935             end_is_left = (end_y < anchor_y) || (end_y == anchor_y && end_x < anchor_x);
5936
5937             if (count < 0)
5938               new_pos = end_is_left ? priv->select_info->selection_end : priv->select_info->selection_anchor;
5939             else
5940               new_pos = !end_is_left ? priv->select_info->selection_end : priv->select_info->selection_anchor;
5941             break;
5942           }
5943         case GTK_MOVEMENT_LOGICAL_POSITIONS:
5944         case GTK_MOVEMENT_WORDS:
5945           if (count < 0)
5946             new_pos = MIN (priv->select_info->selection_end, priv->select_info->selection_anchor);
5947           else
5948             new_pos = MAX (priv->select_info->selection_end, priv->select_info->selection_anchor);
5949           break;
5950         case GTK_MOVEMENT_DISPLAY_LINE_ENDS:
5951         case GTK_MOVEMENT_PARAGRAPH_ENDS:
5952         case GTK_MOVEMENT_BUFFER_ENDS:
5953           /* FIXME: Can do better here */
5954           new_pos = count < 0 ? 0 : strlen (priv->text);
5955           break;
5956         case GTK_MOVEMENT_DISPLAY_LINES:
5957         case GTK_MOVEMENT_PARAGRAPHS:
5958         case GTK_MOVEMENT_PAGES:
5959         case GTK_MOVEMENT_HORIZONTAL_PAGES:
5960           break;
5961         }
5962     }
5963   else
5964     {
5965       switch (step)
5966         {
5967         case GTK_MOVEMENT_LOGICAL_POSITIONS:
5968           new_pos = gtk_label_move_logically (label, new_pos, count);
5969           break;
5970         case GTK_MOVEMENT_VISUAL_POSITIONS:
5971           new_pos = gtk_label_move_visually (label, new_pos, count);
5972           if (new_pos == old_pos)
5973             {
5974               if (!extend_selection)
5975                 {
5976                   if (!gtk_widget_keynav_failed (GTK_WIDGET (label),
5977                                                  count > 0 ?
5978                                                  GTK_DIR_RIGHT : GTK_DIR_LEFT))
5979                     {
5980                       GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (label));
5981
5982                       if (toplevel)
5983                         gtk_widget_child_focus (toplevel,
5984                                                 count > 0 ?
5985                                                 GTK_DIR_RIGHT : GTK_DIR_LEFT);
5986                     }
5987                 }
5988               else
5989                 {
5990                   gtk_widget_error_bell (GTK_WIDGET (label));
5991                 }
5992             }
5993           break;
5994         case GTK_MOVEMENT_WORDS:
5995           while (count > 0)
5996             {
5997               new_pos = gtk_label_move_forward_word (label, new_pos);
5998               count--;
5999             }
6000           while (count < 0)
6001             {
6002               new_pos = gtk_label_move_backward_word (label, new_pos);
6003               count++;
6004             }
6005           if (new_pos == old_pos)
6006             gtk_widget_error_bell (GTK_WIDGET (label));
6007           break;
6008         case GTK_MOVEMENT_DISPLAY_LINE_ENDS:
6009         case GTK_MOVEMENT_PARAGRAPH_ENDS:
6010         case GTK_MOVEMENT_BUFFER_ENDS:
6011           /* FIXME: Can do better here */
6012           new_pos = count < 0 ? 0 : strlen (priv->text);
6013           if (new_pos == old_pos)
6014             gtk_widget_error_bell (GTK_WIDGET (label));
6015           break;
6016         case GTK_MOVEMENT_DISPLAY_LINES:
6017         case GTK_MOVEMENT_PARAGRAPHS:
6018         case GTK_MOVEMENT_PAGES:
6019         case GTK_MOVEMENT_HORIZONTAL_PAGES:
6020           break;
6021         }
6022     }
6023
6024   if (extend_selection)
6025     gtk_label_select_region_index (label,
6026                                    priv->select_info->selection_anchor,
6027                                    new_pos);
6028   else
6029     gtk_label_select_region_index (label, new_pos, new_pos);
6030 }
6031
6032 static void
6033 gtk_label_copy_clipboard (GtkLabel *label)
6034 {
6035   GtkLabelPrivate *priv = label->priv;
6036
6037   if (priv->text && priv->select_info)
6038     {
6039       gint start, end;
6040       gint len;
6041       GtkClipboard *clipboard;
6042
6043       start = MIN (priv->select_info->selection_anchor,
6044                    priv->select_info->selection_end);
6045       end = MAX (priv->select_info->selection_anchor,
6046                  priv->select_info->selection_end);
6047
6048       len = strlen (priv->text);
6049
6050       if (end > len)
6051         end = len;
6052
6053       if (start > len)
6054         start = len;
6055
6056       clipboard = gtk_widget_get_clipboard (GTK_WIDGET (label), GDK_SELECTION_CLIPBOARD);
6057
6058       if (start != end)
6059         gtk_clipboard_set_text (clipboard, priv->text + start, end - start);
6060       else
6061         {
6062           GtkLabelLink *link;
6063
6064           link = gtk_label_get_focus_link (label);
6065           if (link)
6066             gtk_clipboard_set_text (clipboard, link->uri, -1);
6067         }
6068     }
6069 }
6070
6071 static void
6072 gtk_label_select_all (GtkLabel *label)
6073 {
6074   GtkLabelPrivate *priv = label->priv;
6075
6076   gtk_label_select_region_index (label, 0, strlen (priv->text));
6077 }
6078
6079 /* Quick hack of a popup menu
6080  */
6081 static void
6082 activate_cb (GtkWidget *menuitem,
6083              GtkLabel  *label)
6084 {
6085   const gchar *signal = g_object_get_data (G_OBJECT (menuitem), "gtk-signal");
6086   g_signal_emit_by_name (label, signal);
6087 }
6088
6089 static void
6090 append_action_signal (GtkLabel     *label,
6091                       GtkWidget    *menu,
6092                       const gchar  *stock_id,
6093                       const gchar  *signal,
6094                       gboolean      sensitive)
6095 {
6096   GtkWidget *menuitem = gtk_image_menu_item_new_from_stock (stock_id, NULL);
6097
6098   g_object_set_data (G_OBJECT (menuitem), I_("gtk-signal"), (char *)signal);
6099   g_signal_connect (menuitem, "activate",
6100                     G_CALLBACK (activate_cb), label);
6101
6102   gtk_widget_set_sensitive (menuitem, sensitive);
6103   
6104   gtk_widget_show (menuitem);
6105   gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
6106 }
6107
6108 static void
6109 popup_menu_detach (GtkWidget *attach_widget,
6110                    GtkMenu   *menu)
6111 {
6112   GtkLabel *label = GTK_LABEL (attach_widget);
6113   GtkLabelPrivate *priv = label->priv;
6114
6115   if (priv->select_info)
6116     priv->select_info->popup_menu = NULL;
6117 }
6118
6119 static void
6120 popup_position_func (GtkMenu   *menu,
6121                      gint      *x,
6122                      gint      *y,
6123                      gboolean  *push_in,
6124                      gpointer   user_data)
6125 {
6126   GtkLabel *label;
6127   GtkWidget *widget;
6128   GtkAllocation allocation;
6129   GtkRequisition req;
6130   GdkScreen *screen;
6131
6132   label = GTK_LABEL (user_data);
6133   widget = GTK_WIDGET (label);
6134
6135   g_return_if_fail (gtk_widget_get_realized (widget));
6136
6137   screen = gtk_widget_get_screen (widget);
6138   gdk_window_get_origin (gtk_widget_get_window (widget), x, y);
6139
6140   gtk_widget_get_allocation (widget, &allocation);
6141
6142   *x += allocation.x;
6143   *y += allocation.y;
6144
6145   gtk_widget_get_preferred_size (GTK_WIDGET (menu),
6146                                  &req, NULL);
6147
6148   gtk_widget_get_allocation (widget, &allocation);
6149
6150   *x += allocation.width / 2;
6151   *y += allocation.height;
6152
6153   *x = CLAMP (*x, 0, MAX (0, gdk_screen_get_width (screen) - req.width));
6154   *y = CLAMP (*y, 0, MAX (0, gdk_screen_get_height (screen) - req.height));
6155 }
6156
6157 static void
6158 open_link_activate_cb (GtkMenuItem *menu_item,
6159                        GtkLabel    *label)
6160 {
6161   GtkLabelLink *link;
6162
6163   link = gtk_label_get_current_link (label);
6164
6165   if (link)
6166     emit_activate_link (label, link);
6167 }
6168
6169 static void
6170 copy_link_activate_cb (GtkMenuItem *menu_item,
6171                        GtkLabel    *label)
6172 {
6173   GtkClipboard *clipboard;
6174   const gchar *uri;
6175
6176   uri = gtk_label_get_current_uri (label);
6177   if (uri)
6178     {
6179       clipboard = gtk_widget_get_clipboard (GTK_WIDGET (label), GDK_SELECTION_CLIPBOARD);
6180       gtk_clipboard_set_text (clipboard, uri, -1);
6181     }
6182 }
6183
6184 static gboolean
6185 gtk_label_popup_menu (GtkWidget *widget)
6186 {
6187   gtk_label_do_popup (GTK_LABEL (widget), NULL);
6188
6189   return TRUE;
6190 }
6191
6192 static void
6193 gtk_label_do_popup (GtkLabel       *label,
6194                     GdkEventButton *event)
6195 {
6196   GtkLabelPrivate *priv = label->priv;
6197   GtkWidget *menuitem;
6198   GtkWidget *menu;
6199   GtkWidget *image;
6200   gboolean have_selection;
6201   GtkLabelLink *link;
6202
6203   if (!priv->select_info)
6204     return;
6205
6206   if (priv->select_info->popup_menu)
6207     gtk_widget_destroy (priv->select_info->popup_menu);
6208
6209   priv->select_info->popup_menu = menu = gtk_menu_new ();
6210
6211   gtk_menu_attach_to_widget (GTK_MENU (menu), GTK_WIDGET (label), popup_menu_detach);
6212
6213   have_selection =
6214     priv->select_info->selection_anchor != priv->select_info->selection_end;
6215
6216   if (event)
6217     {
6218       if (priv->select_info->link_clicked)
6219         link = priv->select_info->active_link;
6220       else
6221         link = NULL;
6222     }
6223   else
6224     link = gtk_label_get_focus_link (label);
6225
6226   if (!have_selection && link)
6227     {
6228       /* Open Link */
6229       menuitem = gtk_image_menu_item_new_with_mnemonic (_("_Open Link"));
6230       gtk_widget_show (menuitem);
6231       gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
6232
6233       g_signal_connect (G_OBJECT (menuitem), "activate",
6234                         G_CALLBACK (open_link_activate_cb), label);
6235
6236       image = gtk_image_new_from_stock (GTK_STOCK_JUMP_TO, GTK_ICON_SIZE_MENU);
6237       gtk_widget_show (image);
6238       gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem), image);
6239
6240       /* Copy Link Address */
6241       menuitem = gtk_image_menu_item_new_with_mnemonic (_("Copy _Link Address"));
6242       gtk_widget_show (menuitem);
6243       gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
6244
6245       g_signal_connect (G_OBJECT (menuitem), "activate",
6246                         G_CALLBACK (copy_link_activate_cb), label);
6247
6248       image = gtk_image_new_from_stock (GTK_STOCK_COPY, GTK_ICON_SIZE_MENU);
6249       gtk_widget_show (image);
6250       gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem), image);
6251     }
6252   else
6253     {
6254       append_action_signal (label, menu, GTK_STOCK_CUT, "cut-clipboard", FALSE);
6255       append_action_signal (label, menu, GTK_STOCK_COPY, "copy-clipboard", have_selection);
6256       append_action_signal (label, menu, GTK_STOCK_PASTE, "paste-clipboard", FALSE);
6257   
6258       menuitem = gtk_image_menu_item_new_from_stock (GTK_STOCK_DELETE, NULL);
6259       gtk_widget_set_sensitive (menuitem, FALSE);
6260       gtk_widget_show (menuitem);
6261       gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
6262
6263       menuitem = gtk_separator_menu_item_new ();
6264       gtk_widget_show (menuitem);
6265       gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
6266
6267       menuitem = gtk_image_menu_item_new_from_stock (GTK_STOCK_SELECT_ALL, NULL);
6268       g_signal_connect_swapped (menuitem, "activate",
6269                                 G_CALLBACK (gtk_label_select_all), label);
6270       gtk_widget_show (menuitem);
6271       gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
6272     }
6273
6274   g_signal_emit (label, signals[POPULATE_POPUP], 0, menu);
6275
6276   if (event)
6277     gtk_menu_popup (GTK_MENU (menu), NULL, NULL,
6278                     NULL, NULL,
6279                     event->button, event->time);
6280   else
6281     {
6282       gtk_menu_popup (GTK_MENU (menu), NULL, NULL,
6283                       popup_position_func, label,
6284                       0, gtk_get_current_event_time ());
6285       gtk_menu_shell_select_first (GTK_MENU_SHELL (menu), FALSE);
6286     }
6287 }
6288
6289 static void
6290 gtk_label_clear_links (GtkLabel *label)
6291 {
6292   GtkLabelPrivate *priv = label->priv;
6293
6294   if (!priv->select_info)
6295     return;
6296
6297   g_list_free_full (priv->select_info->links, (GDestroyNotify) link_free);
6298   priv->select_info->links = NULL;
6299   priv->select_info->active_link = NULL;
6300 }
6301
6302 static gboolean
6303 gtk_label_activate_link (GtkLabel    *label,
6304                          const gchar *uri)
6305 {
6306   GtkWidget *widget = GTK_WIDGET (label);
6307   GError *error = NULL;
6308
6309   if (!gtk_show_uri (gtk_widget_get_screen (widget),
6310                      uri, gtk_get_current_event_time (), &error))
6311     {
6312       g_warning ("Unable to show '%s': %s", uri, error->message);
6313       g_error_free (error);
6314     }
6315
6316   return TRUE;
6317 }
6318
6319 static void
6320 emit_activate_link (GtkLabel     *label,
6321                     GtkLabelLink *link)
6322 {
6323   GtkLabelPrivate *priv = label->priv;
6324   gboolean handled;
6325
6326   g_signal_emit (label, signals[ACTIVATE_LINK], 0, link->uri, &handled);
6327   if (handled && priv->track_links && !link->visited)
6328     {
6329       link->visited = TRUE;
6330       /* FIXME: shouldn't have to redo everything here */
6331       gtk_label_recalculate (label);
6332     }
6333 }
6334
6335 static void
6336 gtk_label_activate_current_link (GtkLabel *label)
6337 {
6338   GtkLabelLink *link;
6339   GtkWidget *widget = GTK_WIDGET (label);
6340
6341   link = gtk_label_get_focus_link (label);
6342
6343   if (link)
6344     {
6345       emit_activate_link (label, link);
6346     }
6347   else
6348     {
6349       GtkWidget *toplevel;
6350       GtkWindow *window;
6351       GtkWidget *default_widget, *focus_widget;
6352
6353       toplevel = gtk_widget_get_toplevel (widget);
6354       if (GTK_IS_WINDOW (toplevel))
6355         {
6356           window = GTK_WINDOW (toplevel);
6357
6358           if (window)
6359             {
6360               default_widget = gtk_window_get_default_widget (window);
6361               focus_widget = gtk_window_get_focus (window);
6362
6363               if (default_widget != widget &&
6364                   !(widget == focus_widget && (!default_widget || !gtk_widget_is_sensitive (default_widget))))
6365                 gtk_window_activate_default (window);
6366             }
6367         }
6368     }
6369 }
6370
6371 static GtkLabelLink *
6372 gtk_label_get_current_link (GtkLabel *label)
6373 {
6374   GtkLabelPrivate *priv = label->priv;
6375   GtkLabelLink *link;
6376
6377   if (!priv->select_info)
6378     return NULL;
6379
6380   if (priv->select_info->link_clicked)
6381     link = priv->select_info->active_link;
6382   else
6383     link = gtk_label_get_focus_link (label);
6384
6385   return link;
6386 }
6387
6388 /**
6389  * gtk_label_get_current_uri:
6390  * @label: a #GtkLabel
6391  *
6392  * Returns the URI for the currently active link in the label.
6393  * The active link is the one under the mouse pointer or, in a
6394  * selectable label, the link in which the text cursor is currently
6395  * positioned.
6396  *
6397  * This function is intended for use in a #GtkLabel::activate-link handler
6398  * or for use in a #GtkWidget::query-tooltip handler.
6399  *
6400  * Returns: the currently active URI. The string is owned by GTK+ and must
6401  *   not be freed or modified.
6402  *
6403  * Since: 2.18
6404  */
6405 const gchar *
6406 gtk_label_get_current_uri (GtkLabel *label)
6407 {
6408   GtkLabelLink *link;
6409
6410   g_return_val_if_fail (GTK_IS_LABEL (label), NULL);
6411
6412   link = gtk_label_get_current_link (label);
6413
6414   if (link)
6415     return link->uri;
6416
6417   return NULL;
6418 }
6419
6420 /**
6421  * gtk_label_set_track_visited_links:
6422  * @label: a #GtkLabel
6423  * @track_links: %TRUE to track visited links
6424  *
6425  * Sets whether the label should keep track of clicked
6426  * links (and use a different color for them).
6427  *
6428  * Since: 2.18
6429  */
6430 void
6431 gtk_label_set_track_visited_links (GtkLabel *label,
6432                                    gboolean  track_links)
6433 {
6434   GtkLabelPrivate *priv;
6435
6436   g_return_if_fail (GTK_IS_LABEL (label));
6437
6438   priv = label->priv;
6439
6440   track_links = track_links != FALSE;
6441
6442   if (priv->track_links != track_links)
6443     {
6444       priv->track_links = track_links;
6445
6446       /* FIXME: shouldn't have to redo everything here */
6447       gtk_label_recalculate (label);
6448
6449       g_object_notify (G_OBJECT (label), "track-visited-links");
6450     }
6451 }
6452
6453 /**
6454  * gtk_label_get_track_visited_links:
6455  * @label: a #GtkLabel
6456  *
6457  * Returns whether the label is currently keeping track
6458  * of clicked links.
6459  *
6460  * Returns: %TRUE if clicked links are remembered
6461  *
6462  * Since: 2.18
6463  */
6464 gboolean
6465 gtk_label_get_track_visited_links (GtkLabel *label)
6466 {
6467   g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
6468
6469   return label->priv->track_links;
6470 }
6471
6472 static gboolean
6473 gtk_label_query_tooltip (GtkWidget  *widget,
6474                          gint        x,
6475                          gint        y,
6476                          gboolean    keyboard_tip,
6477                          GtkTooltip *tooltip)
6478 {
6479   GtkLabel *label = GTK_LABEL (widget);
6480   GtkLabelPrivate *priv = label->priv;
6481   GtkLabelSelectionInfo *info = priv->select_info;
6482   gint index = -1;
6483   GList *l;
6484
6485   if (info && info->links)
6486     {
6487       if (keyboard_tip)
6488         {
6489           if (info->selection_anchor == info->selection_end)
6490             index = info->selection_anchor;
6491         }
6492       else
6493         {
6494           if (!get_layout_index (label, x, y, &index))
6495             index = -1;
6496         }
6497
6498       if (index != -1)
6499         {
6500           for (l = info->links; l != NULL; l = l->next)
6501             {
6502               GtkLabelLink *link = l->data;
6503               if (index >= link->start && index <= link->end)
6504                 {
6505                   if (link->title)
6506                     {
6507                       gtk_tooltip_set_markup (tooltip, link->title);
6508                       return TRUE;
6509                     }
6510                   break;
6511                 }
6512             }
6513         }
6514     }
6515
6516   return GTK_WIDGET_CLASS (gtk_label_parent_class)->query_tooltip (widget,
6517                                                                    x, y,
6518                                                                    keyboard_tip,
6519                                                                    tooltip);
6520 }
6521
6522 gint
6523 _gtk_label_get_cursor_position (GtkLabel *label)
6524 {
6525   GtkLabelPrivate *priv = label->priv;
6526
6527   if (priv->select_info && priv->select_info->selectable)
6528     return g_utf8_pointer_to_offset (priv->text,
6529                                      priv->text + priv->select_info->selection_end);
6530
6531   return 0;
6532 }
6533
6534 gint
6535 _gtk_label_get_selection_bound (GtkLabel *label)
6536 {
6537   GtkLabelPrivate *priv = label->priv;
6538
6539   if (priv->select_info && priv->select_info->selectable)
6540     return g_utf8_pointer_to_offset (priv->text,
6541                                      priv->text + priv->select_info->selection_anchor);
6542
6543   return 0;
6544 }