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