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