]> Pileus Git - ~andy/gtk/blob - gtk/gtklabel.c
Make gtkmarshal.list/gtkmarshal.h only for compatibility with GTK+-1.2;
[~andy/gtk] / gtk / gtklabel.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free
16  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18
19 /*
20  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
21  * file for a list of people on the GTK+ Team.  See the ChangeLog
22  * files for a list of changes.  These files are distributed with
23  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
24  */
25
26 #include <math.h>
27 #include <string.h>
28 #include "gtklabel.h"
29 #include "gtkmain.h"
30 #include "gtkmarshalers.h"
31 #include "gtksignal.h"
32 #include "gtkwindow.h"
33 #include "gdk/gdkkeysyms.h"
34 #include "gtkclipboard.h"
35 #include "gdk/gdki18n.h"
36 #include <pango/pango.h>
37 #include "gtkimagemenuitem.h"
38 #include "gtkintl.h"
39 #include "gtkseparatormenuitem.h"
40 #include "gtkmenuitem.h"
41 #include "gtknotebook.h"
42 #include "gtkstock.h"
43 #include "gtkbindings.h"
44
45 struct _GtkLabelSelectionInfo
46 {
47   GdkWindow *window;
48   gint selection_anchor;
49   gint selection_end;
50   GdkGC *cursor_gc;
51   GtkWidget *popup_menu;
52 };
53
54 enum {
55   MOVE_CURSOR,
56   COPY_CLIPBOARD,
57   POPULATE_POPUP,
58   LAST_SIGNAL
59 };
60
61 enum {
62   PROP_0,
63   PROP_LABEL,
64   PROP_ATTRIBUTES,
65   PROP_USE_MARKUP,
66   PROP_USE_UNDERLINE,
67   PROP_JUSTIFY,
68   PROP_PATTERN,
69   PROP_WRAP,
70   PROP_SELECTABLE,
71   PROP_MNEMONIC_KEYVAL,
72   PROP_MNEMONIC_WIDGET,
73   PROP_CURSOR_POSITION,
74   PROP_SELECTION_BOUND
75 };
76
77 static guint signals[LAST_SIGNAL] = { 0 };
78
79 static void gtk_label_class_init        (GtkLabelClass    *klass);
80 static void gtk_label_init              (GtkLabel         *label);
81 static void gtk_label_set_property      (GObject          *object,
82                                          guint             prop_id,
83                                          const GValue     *value,
84                                          GParamSpec       *pspec);
85 static void gtk_label_get_property      (GObject          *object,
86                                          guint             prop_id,
87                                          GValue           *value,
88                                          GParamSpec       *pspec);
89 static void gtk_label_destroy           (GtkObject        *object);
90 static void gtk_label_finalize          (GObject          *object);
91 static void gtk_label_size_request      (GtkWidget        *widget,
92                                          GtkRequisition   *requisition);
93 static void gtk_label_size_allocate     (GtkWidget        *widget,
94                                          GtkAllocation    *allocation);
95 static void gtk_label_state_changed     (GtkWidget        *widget,
96                                          GtkStateType      state);
97 static void gtk_label_style_set         (GtkWidget        *widget,
98                                          GtkStyle         *previous_style);
99 static void gtk_label_direction_changed (GtkWidget        *widget,
100                                          GtkTextDirection  previous_dir);
101 static gint gtk_label_expose            (GtkWidget        *widget,
102                                          GdkEventExpose   *event);
103
104 static void gtk_label_realize           (GtkWidget        *widget);
105 static void gtk_label_unrealize         (GtkWidget        *widget);
106 static void gtk_label_map               (GtkWidget        *widget);
107 static void gtk_label_unmap             (GtkWidget        *widget);
108 static gint gtk_label_button_press      (GtkWidget        *widget,
109                                          GdkEventButton   *event);
110 static gint gtk_label_button_release    (GtkWidget        *widget,
111                                          GdkEventButton   *event);
112 static gint gtk_label_motion            (GtkWidget        *widget,
113                                          GdkEventMotion   *event);
114
115
116 static void gtk_label_set_text_internal          (GtkLabel      *label,
117                                                   gchar         *str);
118 static void gtk_label_set_label_internal         (GtkLabel      *label,
119                                                   gchar         *str);
120 static void gtk_label_set_use_markup_internal    (GtkLabel      *label,
121                                                   gboolean       val);
122 static void gtk_label_set_use_underline_internal (GtkLabel      *label,
123                                                   gboolean       val);
124 static void gtk_label_set_attributes_internal    (GtkLabel      *label,
125                                                   PangoAttrList *attrs);
126 static void gtk_label_set_uline_text_internal    (GtkLabel      *label,
127                                                   const gchar   *str);
128 static void gtk_label_set_pattern_internal       (GtkLabel      *label,
129                                                   const gchar   *pattern);
130 static void set_markup                           (GtkLabel      *label,
131                                                   const gchar   *str,
132                                                   gboolean       with_uline);
133 static void gtk_label_recalculate                (GtkLabel      *label);
134 static void gtk_label_hierarchy_changed          (GtkWidget     *widget,
135                                                   GtkWidget     *old_toplevel);
136
137 static void gtk_label_create_window       (GtkLabel *label);
138 static void gtk_label_destroy_window      (GtkLabel *label);
139 static void gtk_label_clear_layout        (GtkLabel *label);
140 static void gtk_label_ensure_layout       (GtkLabel *label);
141 static void gtk_label_select_region_index (GtkLabel *label,
142                                            gint      anchor_index,
143                                            gint      end_index);
144
145 static gboolean gtk_label_mnemonic_activate (GtkWidget         *widget,
146                                              gboolean           group_cycling);
147 static void     gtk_label_setup_mnemonic    (GtkLabel          *label,
148                                              guint              last_key);
149 static gboolean gtk_label_focus             (GtkWidget         *widget,
150                                              GtkDirectionType   direction);
151
152 /* For selectable lables: */
153 static void gtk_label_move_cursor        (GtkLabel        *label,
154                                           GtkMovementStep  step,
155                                           gint             count,
156                                           gboolean         extend_selection);
157 static void gtk_label_copy_clipboard     (GtkLabel        *label);
158 static void gtk_label_select_all         (GtkLabel        *label);
159 static void gtk_label_do_popup           (GtkLabel        *label,
160                                           GdkEventButton  *event);
161
162 static gint gtk_label_move_forward_word  (GtkLabel        *label,
163                                           gint             start);
164 static gint gtk_label_move_backward_word (GtkLabel        *label,
165                                           gint             start);
166
167 static GtkMiscClass *parent_class = NULL;
168
169
170 GtkType
171 gtk_label_get_type (void)
172 {
173   static GtkType label_type = 0;
174   
175   if (!label_type)
176     {
177       static const GTypeInfo label_info =
178       {
179         sizeof (GtkLabelClass),
180         NULL,           /* base_init */
181         NULL,           /* base_finalize */
182         (GClassInitFunc) gtk_label_class_init,
183         NULL,           /* class_finalize */
184         NULL,           /* class_data */
185         sizeof (GtkLabel),
186         32,             /* n_preallocs */
187         (GInstanceInitFunc) gtk_label_init,
188       };
189
190       label_type = g_type_register_static (GTK_TYPE_MISC, "GtkLabel", &label_info, 0);
191     }
192   
193   return label_type;
194 }
195
196 static void
197 add_move_binding (GtkBindingSet  *binding_set,
198                   guint           keyval,
199                   guint           modmask,
200                   GtkMovementStep step,
201                   gint            count)
202 {
203   g_return_if_fail ((modmask & GDK_SHIFT_MASK) == 0);
204   
205   gtk_binding_entry_add_signal (binding_set, keyval, modmask,
206                                 "move_cursor", 3,
207                                 GTK_TYPE_ENUM, step,
208                                 G_TYPE_INT, count,
209                                 G_TYPE_BOOLEAN, FALSE);
210
211   /* Selection-extending version */
212   gtk_binding_entry_add_signal (binding_set, keyval, modmask | GDK_SHIFT_MASK,
213                                 "move_cursor", 3,
214                                 GTK_TYPE_ENUM, step,
215                                 G_TYPE_INT, count,
216                                 G_TYPE_BOOLEAN, TRUE);
217 }
218
219 static void
220 gtk_label_class_init (GtkLabelClass *class)
221 {
222   GObjectClass *gobject_class = G_OBJECT_CLASS (class);
223   GtkObjectClass *object_class = GTK_OBJECT_CLASS (class);
224   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
225   GtkBindingSet *binding_set;
226
227   parent_class = gtk_type_class (GTK_TYPE_MISC);
228   
229   gobject_class->set_property = gtk_label_set_property;
230   gobject_class->get_property = gtk_label_get_property;
231   gobject_class->finalize = gtk_label_finalize;
232
233   object_class->destroy = gtk_label_destroy;
234   
235   widget_class->size_request = gtk_label_size_request;
236   widget_class->size_allocate = gtk_label_size_allocate;
237   widget_class->state_changed = gtk_label_state_changed;
238   widget_class->style_set = gtk_label_style_set;
239   widget_class->direction_changed = gtk_label_direction_changed;
240   widget_class->expose_event = gtk_label_expose;
241   widget_class->realize = gtk_label_realize;
242   widget_class->unrealize = gtk_label_unrealize;
243   widget_class->map = gtk_label_map;
244   widget_class->unmap = gtk_label_unmap;
245   widget_class->button_press_event = gtk_label_button_press;
246   widget_class->button_release_event = gtk_label_button_release;
247   widget_class->motion_notify_event = gtk_label_motion;
248   widget_class->hierarchy_changed = gtk_label_hierarchy_changed;
249   widget_class->mnemonic_activate = gtk_label_mnemonic_activate;
250   widget_class->focus = gtk_label_focus;
251
252   class->move_cursor = gtk_label_move_cursor;
253   class->copy_clipboard = gtk_label_copy_clipboard;
254   
255   signals[MOVE_CURSOR] = 
256       gtk_signal_new ("move_cursor",
257                       GTK_RUN_LAST | GTK_RUN_ACTION,
258                       GTK_CLASS_TYPE (object_class),
259                       GTK_SIGNAL_OFFSET (GtkLabelClass, move_cursor),
260                       _gtk_marshal_VOID__ENUM_INT_BOOLEAN,
261                       GTK_TYPE_NONE, 3, GTK_TYPE_MOVEMENT_STEP, GTK_TYPE_INT, GTK_TYPE_BOOL);
262   
263   signals[COPY_CLIPBOARD] =
264     gtk_signal_new ("copy_clipboard",
265                     GTK_RUN_LAST | GTK_RUN_ACTION,
266                     GTK_CLASS_TYPE (object_class),
267                     GTK_SIGNAL_OFFSET (GtkLabelClass, copy_clipboard),
268                     _gtk_marshal_VOID__VOID,
269                     GTK_TYPE_NONE, 0);
270   
271   signals[POPULATE_POPUP] =
272     gtk_signal_new ("populate_popup",
273                     GTK_RUN_LAST,
274                     GTK_CLASS_TYPE (object_class),
275                     GTK_SIGNAL_OFFSET (GtkLabelClass, populate_popup),
276                     _gtk_marshal_VOID__OBJECT,
277                     GTK_TYPE_NONE, 1, GTK_TYPE_MENU);
278
279   g_object_class_install_property (G_OBJECT_CLASS(object_class),
280                                    PROP_LABEL,
281                                    g_param_spec_string ("label",
282                                                         _("Label"),
283                                                         _("The text of the label."),
284                                                         NULL,
285                                                         G_PARAM_READWRITE));
286   g_object_class_install_property (gobject_class,
287                                    PROP_ATTRIBUTES,
288                                    g_param_spec_boxed ("attributes",
289                                                        _("Attributes"),
290                                                        _("A list of style attributes to apply to the text of the label."),
291                                                        PANGO_TYPE_ATTR_LIST,
292                                                        G_PARAM_READWRITE));
293   g_object_class_install_property (gobject_class,
294                                    PROP_USE_MARKUP,
295                                    g_param_spec_boolean ("use_markup",
296                                                          _("Use markup"),
297                                                          _("The text of the label includes XML markup. See pango_parse_markup()."),
298                                                         FALSE,
299                                                         G_PARAM_READWRITE));
300   g_object_class_install_property (gobject_class,
301                                    PROP_USE_UNDERLINE,
302                                    g_param_spec_boolean ("use_underline",
303                                                          _("Use underline"),
304                                                          _("If set, an underline in the text indicates the next character should be used for the mnemonic accelerator key"),
305                                                         FALSE,
306                                                         G_PARAM_READWRITE));
307
308   g_object_class_install_property (gobject_class,
309                                    PROP_JUSTIFY,
310                                    g_param_spec_enum ("justify",
311                                                       _("Justification"),
312                                                       _("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."),
313                                                       GTK_TYPE_JUSTIFICATION,
314                                                       GTK_JUSTIFY_LEFT,
315                                                       G_PARAM_READWRITE));
316
317   g_object_class_install_property (gobject_class,
318                                    PROP_PATTERN,
319                                    g_param_spec_string ("pattern",
320                                                         _("Pattern"),
321                                                         _("A string with _ characters in positions correspond to characters in the text to underline."),
322                                                         NULL,
323                                                         G_PARAM_WRITABLE));
324
325   g_object_class_install_property (gobject_class,
326                                    PROP_WRAP,
327                                    g_param_spec_boolean ("wrap",
328                                                         _("Line wrap"),
329                                                         _("If set, wrap lines if the text becomes too wide."),
330                                                         TRUE,
331                                                         G_PARAM_READWRITE));
332   g_object_class_install_property (gobject_class,
333                                    PROP_SELECTABLE,
334                                    g_param_spec_boolean ("selectable",
335                                                         _("Selectable"),
336                                                         _("Whether the label text can be selected with the mouse."),
337                                                         FALSE,
338                                                         G_PARAM_READWRITE));
339   g_object_class_install_property (gobject_class,
340                                    PROP_MNEMONIC_KEYVAL,
341                                    g_param_spec_uint ("mnemonic_keyval",
342                                                       _("Mnemonic key"),
343                                                       _("The mnemonic accelerator key for this label."),
344                                                       0,
345                                                       G_MAXUINT,
346                                                       GDK_VoidSymbol,
347                                                       G_PARAM_READABLE));
348   g_object_class_install_property (gobject_class,
349                                    PROP_MNEMONIC_WIDGET,
350                                    g_param_spec_object ("mnemonic_widget",
351                                                         _("Mnemonic widget"),
352                                                         _("The widget to be activated when the label's mnemonic "
353                                                           "key is pressed."),
354                                                         GTK_TYPE_WIDGET,
355                                                         G_PARAM_READWRITE));
356
357   g_object_class_install_property (gobject_class,
358                                    PROP_CURSOR_POSITION,
359                                    g_param_spec_int ("cursor_position",
360                                                      _("Cursor Position"),
361                                                      _("The current position of the insertion cursor in chars."),
362                                                      0,
363                                                      G_MAXINT,
364                                                      0,
365                                                      G_PARAM_READABLE));
366   
367   g_object_class_install_property (gobject_class,
368                                    PROP_SELECTION_BOUND,
369                                    g_param_spec_int ("selection_bound",
370                                                      _("Selection Bound"),
371                                                      _("The position of the opposite end of the selection from the cursor in chars."),
372                                                      0,
373                                                      G_MAXINT,
374                                                      0,
375                                                      G_PARAM_READABLE));
376   
377   gtk_widget_class_install_style_property (widget_class,
378                                            g_param_spec_boxed ("cursor_color",
379                                                                _("Cursor color"),
380                                                                _("Color with which to draw insertion cursor"),
381                                                                GDK_TYPE_COLOR,
382                                                                G_PARAM_READABLE));
383   
384   /*
385    * Key bindings
386    */
387
388   binding_set = gtk_binding_set_by_class (class);
389
390   /* Moving the insertion point */
391   add_move_binding (binding_set, GDK_Right, 0,
392                     GTK_MOVEMENT_VISUAL_POSITIONS, 1);
393   
394   add_move_binding (binding_set, GDK_Left, 0,
395                     GTK_MOVEMENT_VISUAL_POSITIONS, -1);
396
397   add_move_binding (binding_set, GDK_KP_Right, 0,
398                     GTK_MOVEMENT_VISUAL_POSITIONS, 1);
399   
400   add_move_binding (binding_set, GDK_KP_Left, 0,
401                     GTK_MOVEMENT_VISUAL_POSITIONS, -1);
402   
403   add_move_binding (binding_set, GDK_f, GDK_CONTROL_MASK,
404                     GTK_MOVEMENT_LOGICAL_POSITIONS, 1);
405   
406   add_move_binding (binding_set, GDK_b, GDK_CONTROL_MASK,
407                     GTK_MOVEMENT_LOGICAL_POSITIONS, -1);
408   
409   add_move_binding (binding_set, GDK_Right, GDK_CONTROL_MASK,
410                     GTK_MOVEMENT_WORDS, 1);
411
412   add_move_binding (binding_set, GDK_Left, GDK_CONTROL_MASK,
413                     GTK_MOVEMENT_WORDS, -1);
414
415   add_move_binding (binding_set, GDK_KP_Right, GDK_CONTROL_MASK,
416                     GTK_MOVEMENT_WORDS, 1);
417
418   add_move_binding (binding_set, GDK_KP_Left, GDK_CONTROL_MASK,
419                     GTK_MOVEMENT_WORDS, -1);
420   
421   add_move_binding (binding_set, GDK_a, GDK_CONTROL_MASK,
422                     GTK_MOVEMENT_PARAGRAPH_ENDS, -1);
423
424   add_move_binding (binding_set, GDK_e, GDK_CONTROL_MASK,
425                     GTK_MOVEMENT_PARAGRAPH_ENDS, 1);
426
427   add_move_binding (binding_set, GDK_f, GDK_MOD1_MASK,
428                     GTK_MOVEMENT_WORDS, 1);
429
430   add_move_binding (binding_set, GDK_b, GDK_MOD1_MASK,
431                     GTK_MOVEMENT_WORDS, -1);
432
433   add_move_binding (binding_set, GDK_Home, 0,
434                     GTK_MOVEMENT_DISPLAY_LINE_ENDS, -1);
435
436   add_move_binding (binding_set, GDK_End, 0,
437                     GTK_MOVEMENT_DISPLAY_LINE_ENDS, 1);
438
439   add_move_binding (binding_set, GDK_KP_Home, 0,
440                     GTK_MOVEMENT_DISPLAY_LINE_ENDS, -1);
441
442   add_move_binding (binding_set, GDK_KP_End, 0,
443                     GTK_MOVEMENT_DISPLAY_LINE_ENDS, 1);
444   
445   add_move_binding (binding_set, GDK_Home, GDK_CONTROL_MASK,
446                     GTK_MOVEMENT_BUFFER_ENDS, -1);
447
448   add_move_binding (binding_set, GDK_End, GDK_CONTROL_MASK,
449                     GTK_MOVEMENT_BUFFER_ENDS, 1);
450
451   add_move_binding (binding_set, GDK_KP_Home, GDK_CONTROL_MASK,
452                     GTK_MOVEMENT_BUFFER_ENDS, -1);
453
454   add_move_binding (binding_set, GDK_KP_End, GDK_CONTROL_MASK,
455                     GTK_MOVEMENT_BUFFER_ENDS, 1);
456
457   /* copy */
458   gtk_binding_entry_add_signal (binding_set, GDK_c, GDK_CONTROL_MASK,
459                                 "copy_clipboard", 0);
460 }
461
462 static void 
463 gtk_label_set_property (GObject      *object,
464                         guint         prop_id,
465                         const GValue *value,
466                         GParamSpec   *pspec)
467 {
468   GtkLabel *label;
469   guint last_keyval;
470
471   label = GTK_LABEL (object);
472   last_keyval = label->mnemonic_keyval;
473   
474   switch (prop_id)
475     {
476     case PROP_LABEL:
477       gtk_label_set_label (label, g_value_get_string (value));
478       break;
479     case PROP_ATTRIBUTES:
480       gtk_label_set_attributes (label, g_value_get_boxed (value));
481       break;
482     case PROP_USE_MARKUP:
483       gtk_label_set_use_markup (label, g_value_get_boolean (value));
484       break;
485     case PROP_USE_UNDERLINE:
486       gtk_label_set_use_underline (label, g_value_get_boolean (value));
487       break;
488     case PROP_JUSTIFY:
489       gtk_label_set_justify (label, g_value_get_enum (value));
490       break;
491     case PROP_PATTERN:
492       gtk_label_set_pattern (label, g_value_get_string (value));
493       break;
494     case PROP_WRAP:
495       gtk_label_set_line_wrap (label, g_value_get_boolean (value));
496       break;      
497     case PROP_SELECTABLE:
498       gtk_label_set_selectable (label, g_value_get_boolean (value));
499       break;      
500     case PROP_MNEMONIC_WIDGET:
501       gtk_label_set_mnemonic_widget (label, (GtkWidget*) g_value_get_object (value));
502       break;
503     default:
504       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
505       break;
506     }
507 }
508
509 static void 
510 gtk_label_get_property (GObject     *object,
511                         guint        prop_id,
512                         GValue      *value,
513                         GParamSpec  *pspec)
514 {
515   GtkLabel *label;
516   
517   label = GTK_LABEL (object);
518   
519   switch (prop_id)
520     {
521     case PROP_LABEL:
522       g_value_set_string (value, label->label);
523       break;
524     case PROP_ATTRIBUTES:
525       g_value_set_boxed (value, label->attrs);
526       break;
527     case PROP_USE_MARKUP:
528       g_value_set_boolean (value, label->use_markup);
529       break;
530     case PROP_USE_UNDERLINE:
531       g_value_set_boolean (value, label->use_underline);
532       break;
533     case PROP_JUSTIFY:
534       g_value_set_enum (value, label->jtype);
535       break;
536     case PROP_WRAP:
537       g_value_set_boolean (value, label->wrap);
538       break;
539     case PROP_SELECTABLE:
540       g_value_set_boolean (value, gtk_label_get_selectable (label));
541       break;
542     case PROP_MNEMONIC_KEYVAL:
543       g_value_set_uint (value, label->mnemonic_keyval);
544       break;
545     case PROP_MNEMONIC_WIDGET:
546       g_value_set_object (value, (GObject*) label->mnemonic_widget);
547       break;
548     case PROP_CURSOR_POSITION:
549       if (label->select_info)
550         {
551           gint offset = g_utf8_pointer_to_offset (label->label,
552                                                   label->label + label->select_info->selection_end);
553           g_value_set_int (value, offset);
554         }
555       else
556         g_value_set_int (value, 0);
557       break;
558     case PROP_SELECTION_BOUND:
559       if (label->select_info)
560         {
561           gint offset = g_utf8_pointer_to_offset (label->label,
562                                                   label->label + label->select_info->selection_anchor);
563           g_value_set_int (value, offset);
564         }
565       else
566         g_value_set_int (value, 0);
567       break;
568
569     default:
570       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
571       break;
572     }
573 }
574
575 static void
576 gtk_label_init (GtkLabel *label)
577 {
578   GTK_WIDGET_SET_FLAGS (label, GTK_NO_WINDOW);
579   
580   label->label = NULL;
581
582   label->jtype = GTK_JUSTIFY_CENTER;
583   label->wrap = FALSE;
584
585   label->use_underline = FALSE;
586   label->use_markup = FALSE;
587   
588   label->mnemonic_keyval = GDK_VoidSymbol;
589   label->layout = NULL;
590   label->text = NULL;
591   label->attrs = NULL;
592
593   label->mnemonic_widget = NULL;
594   label->mnemonic_window = NULL;
595   
596   gtk_label_set_text (label, "");
597 }
598
599 /**
600  * gtk_label_new:
601  * @str: The text of the label
602  *
603  * Creates a new #GtkLabel, containing the text in @str.
604  *
605  * Return value: the new #GtkLabel
606  **/
607 GtkWidget*
608 gtk_label_new (const gchar *str)
609 {
610   GtkLabel *label;
611   
612   label = gtk_type_new (GTK_TYPE_LABEL);
613
614   if (str && *str)
615     gtk_label_set_text (label, str);
616   
617   return GTK_WIDGET (label);
618 }
619
620 /**
621  * gtk_label_new_with_mnemonic:
622  * @str: The text of the label, with an underscore in front of the
623  *       mnemonic character
624  *
625  * Creates a new #GtkLabel, containing the text in @str.
626  *
627  * If characters in @str are preceded by an underscore, they are
628  * underlined indicating that they represent a keyboard accelerator
629  * called a mnemonic.  The mnemonic key can be used to activate
630  * another widget, chosen automatically, or explicitly using
631  * gtk_label_set_mnemonic_widget().
632  * 
633  * If gtk_label_set_mnemonic_widget()
634  * is not called, then the first activatable ancestor of the #GtkLabel
635  * will be chosen as the mnemonic widget. For instance, if the
636  * label is inside a button or menu item, the button or menu item will
637  * automatically become the mnemonic widget and be activated by
638  * the mnemonic.
639  *
640  * Return value: the new #GtkLabel
641  **/
642 GtkWidget*
643 gtk_label_new_with_mnemonic (const gchar *str)
644 {
645   GtkLabel *label;
646   
647   label = gtk_type_new (GTK_TYPE_LABEL);
648
649   if (str && *str)
650     gtk_label_set_text_with_mnemonic (label, str);
651   
652   return GTK_WIDGET (label);
653 }
654
655 static gboolean
656 gtk_label_mnemonic_activate (GtkWidget *widget,
657                              gboolean   group_cycling)
658 {
659   GtkWidget *parent;
660
661   if (GTK_LABEL (widget)->mnemonic_widget)
662     return gtk_widget_mnemonic_activate (GTK_LABEL (widget)->mnemonic_widget, group_cycling);
663
664   /* Try to find the widget to activate by traversing the
665    * widget's ancestry.
666    */
667   parent = widget->parent;
668   while (parent)
669     {
670       if (GTK_WIDGET_CAN_FOCUS (parent) ||
671           (!group_cycling && GTK_WIDGET_GET_CLASS (parent)->activate_signal) ||
672           (parent->parent && GTK_IS_NOTEBOOK (parent->parent)) ||
673           (GTK_IS_MENU_ITEM (parent)))
674         return gtk_widget_mnemonic_activate (parent, group_cycling);
675       parent = parent->parent;
676     }
677
678   /* barf if there was nothing to activate */
679   g_warning ("Couldn't find a target for a mnemonic activation.");
680   gdk_beep ();
681   
682   return FALSE;
683 }
684
685 static void
686 gtk_label_setup_mnemonic (GtkLabel *label,
687                           guint     last_key)
688 {
689   GtkWidget *toplevel;
690
691   if (last_key != GDK_VoidSymbol && label->mnemonic_window)
692     {
693       gtk_window_remove_mnemonic  (label->mnemonic_window,
694                                    last_key,
695                                    GTK_WIDGET (label));
696       label->mnemonic_window = NULL;
697     }
698   
699   if (label->mnemonic_keyval == GDK_VoidSymbol)
700     return;
701   
702   toplevel = gtk_widget_get_toplevel (GTK_WIDGET (label));
703   if (GTK_WIDGET_TOPLEVEL (toplevel))
704     {
705       gtk_window_add_mnemonic (GTK_WINDOW (toplevel),
706                                label->mnemonic_keyval,
707                                GTK_WIDGET (label));
708       label->mnemonic_window = GTK_WINDOW (toplevel);
709     }
710 }
711
712 static void
713 gtk_label_hierarchy_changed (GtkWidget *widget,
714                              GtkWidget *old_toplevel)
715 {
716   GtkLabel *label = GTK_LABEL (widget);
717   
718   gtk_label_setup_mnemonic (label, label->mnemonic_keyval);
719 }
720
721
722 /**
723  * gtk_label_set_mnemonic_widget:
724  * @label: a #GtkLabel
725  * @widget: the target #GtkWidget 
726  *
727  * If the label has been set so that it has an mnemonic key (using
728  * i.e.  gtk_label_set_markup_with_mnemonic(),
729  * gtk_label_set_text_with_mnemonic(), gtk_label_new_with_mnemonic()
730  * or the "use_underline" property) the label can be associated with a
731  * widget that is the target of the mnemonic. When the label is inside
732  * a widget (like a #GtkButton or a #GtkNotebook tab) it is
733  * automatically associated with the correct widget, but sometimes
734  * (i.e. when the target is a #GtkEntry next to the label) you need to
735  * set it explicitly using this function.
736  *
737  * The target widget will be accelerated by emitting "mnemonic_activate" on it.
738  * The default handler for this signal will activate the widget if there are no
739  * mnemonic collisions and toggle focus between the colliding widgets otherwise.
740  **/
741 void
742 gtk_label_set_mnemonic_widget (GtkLabel  *label,
743                                GtkWidget *widget)
744 {
745   g_return_if_fail (GTK_IS_LABEL (label));
746   if (widget)
747     g_return_if_fail (GTK_IS_WIDGET (widget));
748
749   if (label->mnemonic_widget)
750     gtk_widget_unref (label->mnemonic_widget);
751   label->mnemonic_widget = widget;
752   if (label->mnemonic_widget)
753     gtk_widget_ref (label->mnemonic_widget);
754 }
755
756 /**
757  * gtk_label_get_mnemonic_widget:
758  * @label: a #GtkLabel
759  *
760  * Retrieves the target of the mnemonic (keyboard shortcut) of this
761  * label. See gtk_label_set_mnemonic_widget ().
762  *
763  * Return value: the target of the label's mnemonic, or %NULL if none
764  *               has been set and the default algorithm will be used.
765  **/
766 GtkWidget *
767 gtk_label_get_mnemonic_widget (GtkLabel *label)
768 {
769   g_return_val_if_fail (GTK_IS_LABEL (label), NULL);
770
771   return label->mnemonic_widget;
772 }
773
774 /**
775  * gtk_label_get_mnemonic_keyval:
776  * @label: a #GtkLabel
777  *
778  * If the label has been set so that it has an mnemonic key this function
779  * returns the keyval used for the mnemonic accelerator. If there is no
780  * mnemonic set up it returns #GDK_VoidSymbol.
781  *
782  * Returns: GDK keyval usable for accelerators, or #GDK_VoidSymbol
783  **/
784 guint
785 gtk_label_get_mnemonic_keyval (GtkLabel *label)
786 {
787   g_return_val_if_fail (GTK_IS_LABEL (label), GDK_VoidSymbol);
788
789   return label->mnemonic_keyval;
790 }
791
792 static void
793 gtk_label_set_text_internal (GtkLabel *label,
794                              gchar    *str)
795 {
796   g_free (label->text);
797   
798   label->text = str;
799
800   gtk_label_select_region_index (label, 0, 0);
801 }
802
803 static void
804 gtk_label_set_label_internal (GtkLabel *label,
805                               gchar    *str)
806 {
807   g_free (label->label);
808   
809   label->label = str;
810
811   g_object_notify (G_OBJECT (label), "label");
812 }
813
814 static void
815 gtk_label_set_use_markup_internal (GtkLabel *label,
816                                    gboolean  val)
817 {
818   val = val != FALSE;
819   if (label->use_markup != val)
820     {
821       g_object_notify (G_OBJECT (label), "use_markup");
822       label->use_markup = val;
823     }
824 }
825
826 static void
827 gtk_label_set_use_underline_internal (GtkLabel *label,
828                                       gboolean val)
829 {
830   val = val != FALSE;
831   if (label->use_underline != val)
832     {
833       g_object_notify (G_OBJECT (label), "use_underline");
834       label->use_underline = val;
835     }
836 }
837
838 static void
839 gtk_label_set_attributes_internal (GtkLabel      *label,
840                                    PangoAttrList *attrs)
841 {
842   if (attrs)
843     pango_attr_list_ref (attrs);
844   
845   if (label->attrs)
846     pango_attr_list_unref (label->attrs);
847
848   if (!label->use_markup && !label->use_underline)
849     {
850       pango_attr_list_ref (attrs);
851       if (label->effective_attrs)
852         pango_attr_list_unref (label->effective_attrs);
853       label->effective_attrs = attrs;
854     }
855
856   label->attrs = attrs;
857   g_object_notify (G_OBJECT (label), "attributes");
858 }
859
860
861 /* Calculates text, attrs and mnemonic_keyval from
862  * label, use_underline and use_markup
863  */
864 static void
865 gtk_label_recalculate (GtkLabel *label)
866 {
867   if (label->use_markup)
868     set_markup (label, label->label, label->use_underline);
869   else
870     {
871       if (label->use_underline)
872         gtk_label_set_uline_text_internal (label, label->label);
873       else
874         {
875           gtk_label_set_text_internal (label, g_strdup (label->label));
876           if (label->attrs)
877             pango_attr_list_ref (label->attrs);
878           if (label->effective_attrs)
879             pango_attr_list_unref (label->effective_attrs);
880           label->effective_attrs = label->attrs;
881         }
882     }
883
884   if (!label->use_underline)
885     {
886       guint keyval = label->mnemonic_keyval;
887
888       label->mnemonic_keyval = GDK_VoidSymbol;
889       gtk_label_setup_mnemonic (label, keyval);
890     }
891
892   gtk_label_clear_layout (label);  
893   gtk_widget_queue_resize (GTK_WIDGET (label));
894 }
895
896 /**
897  * gtk_label_set_text:
898  * @label: a #GtkLabel
899  * @str: a string
900  *
901  * Sets the text of the label to @str.
902  *
903  * This will also clear any previously set mnemonic accelerators.
904  **/
905 void
906 gtk_label_set_text (GtkLabel    *label,
907                     const gchar *str)
908 {
909   g_return_if_fail (GTK_IS_LABEL (label));
910   
911   gtk_label_set_label_internal (label, g_strdup (str ? str : ""));
912   gtk_label_set_use_markup_internal (label, FALSE);
913   gtk_label_set_use_underline_internal (label, FALSE);
914   
915   gtk_label_recalculate (label);
916 }
917
918 /**
919  * gtk_label_set_attributes:
920  * @label: a #GtkLabel
921  * @attrs: a #PangoAttrList
922  * 
923  * Sets a #PangoAttrList; the attributes in the list are applied to the
924  * label text. The attributes set with this function will be ignored
925  * if label->use_underline or label->use_markup is %TRUE.
926  **/
927 void
928 gtk_label_set_attributes (GtkLabel         *label,
929                           PangoAttrList    *attrs)
930 {
931   g_return_if_fail (GTK_IS_LABEL (label));
932
933   gtk_label_set_attributes_internal (label, attrs);
934   
935   gtk_label_clear_layout (label);  
936   gtk_widget_queue_resize (GTK_WIDGET (label));
937 }
938
939 /**
940  * gtk_label_get_attributes:
941  * @label: a #GtkLabel
942  *
943  * Gets the attribute list that was set on the label using
944  * gtk_label_set_attributes(), if any. This function does
945  * not reflect attributes that come from the labels markup
946  * (see gtk_label_set_markup()). If you want to get the
947  * effective attributes for the label, use
948  * pango_layout_get_attribute (gtk_label_get_layout (label)).
949  *
950  * Return value: the attribute list, or %NULL if none was set.
951  **/
952 PangoAttrList *
953 gtk_label_get_attributes (GtkLabel *label)
954 {
955   g_return_val_if_fail (GTK_IS_LABEL (label), NULL);
956
957   return label->attrs;
958 }
959
960 /**
961  * gtk_label_set_label:
962  * @label: a #GtkLabel
963  * @str: the new text to set for the label
964  *
965  * Sets the text of the label. The label is interpreted as
966  * including embedded underlines and/or Pango markup depending
967  * on the values of label->use_underline and label->use_markup.
968  **/
969 void
970 gtk_label_set_label (GtkLabel    *label,
971                      const gchar *str)
972 {
973   guint last_keyval;
974
975   g_return_if_fail (GTK_IS_LABEL (label));
976   g_return_if_fail (str != NULL);
977
978   last_keyval = label->mnemonic_keyval;
979
980   gtk_label_set_label_internal (label, g_strdup (str));
981   gtk_label_recalculate (label);
982   if (last_keyval != label->mnemonic_keyval)
983     gtk_label_setup_mnemonic (label, last_keyval);
984 }
985
986 /**
987  * gtk_label_get_label:
988  * @label: a #GtkLabel
989  *
990  * Fetches the text from a label widget including any embedded
991  * underlines indicating mnemonics and Pango markup. (See
992  * gtk_label_get_text ()).
993  *
994  * Return value: the text of the label widget. This string is
995  *   owned by the widget and must not be modified or freed.
996  **/
997 G_CONST_RETURN gchar *
998 gtk_label_get_label (GtkLabel *label)
999 {
1000   g_return_val_if_fail (GTK_IS_LABEL (label), NULL);
1001
1002   return label->label;
1003 }
1004
1005 static void
1006 set_markup (GtkLabel    *label,
1007             const gchar *str,
1008             gboolean     with_uline)
1009 {
1010   gchar *text = NULL;
1011   GError *error = NULL;
1012   PangoAttrList *attrs = NULL;
1013   gunichar accel_char = 0;
1014
1015   if (!pango_parse_markup (str,
1016                            -1,
1017                            with_uline ? '_' : 0,
1018                            &attrs,
1019                            &text,
1020                            with_uline ? &accel_char : NULL,
1021                            &error))
1022     {
1023       g_warning ("Failed to set label from markup due to error parsing markup: %s",
1024                  error->message);
1025       g_error_free (error);
1026       return;
1027     }
1028
1029   if (text)
1030     gtk_label_set_text_internal (label, text);
1031
1032   if (attrs)
1033     {
1034       if (label->effective_attrs)
1035         pango_attr_list_unref (label->effective_attrs);
1036       label->effective_attrs = attrs;
1037     }
1038
1039   if (accel_char != 0)
1040     label->mnemonic_keyval = gdk_keyval_to_lower (gdk_unicode_to_keyval (accel_char));
1041   else
1042     label->mnemonic_keyval = GDK_VoidSymbol;
1043 }
1044
1045 /**
1046  * gtk_label_set_markup:
1047  * @label: a #GtkLabel
1048  * @str: a markup string (see <link linkend="PangoMarkupFormat">Pango markup format</link>)
1049  * 
1050  * Parses @str which is marked up with the Pango text markup language,
1051  * setting the label's text and attribute list based on the parse results.
1052  **/
1053 void
1054 gtk_label_set_markup (GtkLabel    *label,
1055                       const gchar *str)
1056 {  
1057   g_return_if_fail (GTK_IS_LABEL (label));
1058
1059   gtk_label_set_label_internal (label, g_strdup (str ? str : ""));
1060   gtk_label_set_use_markup_internal (label, TRUE);
1061   gtk_label_set_use_underline_internal (label, FALSE);
1062   
1063   gtk_label_recalculate (label);
1064 }
1065
1066 /**
1067  * gtk_label_set_markup_with_mnemonic:
1068  * @label: a #GtkLabel
1069  * @str: a markup string (see <link linkend="PangoMarkupFormat">Pango markup format</link>)
1070  * 
1071  * Parses @str which is marked up with the Pango text markup language,
1072  * setting the label's text and attribute list based on the parse results.
1073  * If characters in @str are preceded by an underscore, they are underlined
1074  * indicating that they represent a keyboard accelerator called a mnemonic.
1075  *
1076  * The mnemonic key can be used to activate another widget, chosen automatically,
1077  * or explicitly using gtk_label_set_mnemonic_widget().
1078  **/
1079 void
1080 gtk_label_set_markup_with_mnemonic (GtkLabel    *label,
1081                                     const gchar *str)
1082 {
1083   guint last_keyval;
1084   g_return_if_fail (GTK_IS_LABEL (label));
1085
1086   last_keyval = label->mnemonic_keyval;
1087   gtk_label_set_label_internal (label, g_strdup (str ? str : ""));
1088   gtk_label_set_use_markup_internal (label, TRUE);
1089   gtk_label_set_use_underline_internal (label, TRUE);
1090   
1091   gtk_label_recalculate (label);
1092   gtk_label_setup_mnemonic (label, last_keyval);
1093 }
1094
1095 /**
1096  * gtk_label_get_text:
1097  * @label: a #GtkLabel
1098  * 
1099  * Fetches the text from a label widget, as displayed on the
1100  * screen. This does not include any embedded underlines
1101  * indicating mnemonics or Pango markup. (See gtk_label_get_label())
1102  * 
1103  * Return value: the text in the label widget. This is the internal
1104  *   string used by the label, and must not be modified.
1105  **/
1106 G_CONST_RETURN gchar *
1107 gtk_label_get_text (GtkLabel *label)
1108 {
1109   g_return_val_if_fail (GTK_IS_LABEL (label), NULL);
1110
1111   return label->text;
1112 }
1113
1114 static PangoAttrList *
1115 gtk_label_pattern_to_attrs (GtkLabel      *label,
1116                             const gchar   *pattern)
1117 {
1118   const char *start;
1119   const char *p = label->text;
1120   const char *q = pattern;
1121   PangoAttrList *attrs;
1122
1123   attrs = pango_attr_list_new ();
1124
1125   while (1)
1126     {
1127       while (*p && *q && *q != '_')
1128         {
1129           p = g_utf8_next_char (p);
1130           q++;
1131         }
1132       start = p;
1133       while (*p && *q && *q == '_')
1134         {
1135           p = g_utf8_next_char (p);
1136           q++;
1137         }
1138       
1139       if (p > start)
1140         {
1141           PangoAttribute *attr = pango_attr_underline_new (PANGO_UNDERLINE_LOW);
1142           attr->start_index = start - label->text;
1143           attr->end_index = p - label->text;
1144           
1145           pango_attr_list_insert (attrs, attr);
1146         }
1147       else
1148         break;
1149     }
1150
1151   return attrs;
1152 }
1153
1154 static void
1155 gtk_label_set_pattern_internal (GtkLabel    *label,
1156                                 const gchar *pattern)
1157 {
1158   PangoAttrList *attrs;
1159   g_return_if_fail (GTK_IS_LABEL (label));
1160   
1161   attrs = gtk_label_pattern_to_attrs (label, pattern);
1162
1163   if (label->effective_attrs)
1164     pango_attr_list_unref (label->effective_attrs);
1165   label->effective_attrs = attrs;
1166 }
1167
1168 void
1169 gtk_label_set_pattern (GtkLabel    *label,
1170                        const gchar *pattern)
1171 {
1172   g_return_if_fail (GTK_IS_LABEL (label));
1173   
1174   gtk_label_set_pattern_internal (label, pattern);
1175
1176   gtk_label_clear_layout (label);  
1177   gtk_widget_queue_resize (GTK_WIDGET (label));
1178 }
1179
1180
1181 /**
1182  * gtk_label_set_justify:
1183  * @label: a #GtkLabel
1184  * @jtype: a #GtkJustification
1185  *
1186  * Sets the alignment of the lines in the text of the label relative to
1187  * each other.
1188  **/
1189 void
1190 gtk_label_set_justify (GtkLabel        *label,
1191                        GtkJustification jtype)
1192 {
1193   g_return_if_fail (GTK_IS_LABEL (label));
1194   g_return_if_fail (jtype >= GTK_JUSTIFY_LEFT && jtype <= GTK_JUSTIFY_FILL);
1195   
1196   if ((GtkJustification) label->jtype != jtype)
1197     {
1198       label->jtype = jtype;
1199
1200       /* No real need to be this drastic, but easier than duplicating the code */
1201       gtk_label_clear_layout (label);
1202       
1203       g_object_notify (G_OBJECT (label), "justify");
1204       gtk_widget_queue_resize (GTK_WIDGET (label));
1205     }
1206 }
1207
1208 /**
1209  * gtk_label_get_justify:
1210  * @label: a #GtkLabel
1211  *
1212  * Returns the justification of the label. See gtk_label_set_justify ().
1213  *
1214  * Return value: #GtkJustification
1215  **/
1216 GtkJustification
1217 gtk_label_get_justify (GtkLabel *label)
1218 {
1219   g_return_val_if_fail (GTK_IS_LABEL (label), 0);
1220
1221   return label->jtype;
1222 }
1223
1224 /**
1225  * gtk_label_set_line_wrap:
1226  * @label: a #GtkLabel
1227  * @wrap: the setting
1228  *
1229  * If true, the lines will be wrapped if the text becomes too wide.
1230  */
1231 void
1232 gtk_label_set_line_wrap (GtkLabel *label,
1233                          gboolean  wrap)
1234 {
1235   g_return_if_fail (GTK_IS_LABEL (label));
1236   
1237   wrap = wrap != FALSE;
1238   
1239   if (label->wrap != wrap)
1240     {
1241       label->wrap = wrap;
1242       g_object_notify (G_OBJECT (label), "wrap");
1243       
1244       gtk_widget_queue_resize (GTK_WIDGET (label));
1245     }
1246 }
1247
1248 /**
1249  * gtk_label_get_line_wrap:
1250  * @label: a #GtkLabel
1251  *
1252  * Returns whether lines in the label are automatically wrapped. See gtk_label_set_line_wrap ().
1253  *
1254  * Return value: %TRUE if the lines of the label are automatically wrapped.
1255  */
1256 gboolean
1257 gtk_label_get_line_wrap (GtkLabel *label)
1258 {
1259   g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
1260
1261   return label->wrap;
1262 }
1263
1264 void
1265 gtk_label_get (GtkLabel *label,
1266                gchar   **str)
1267 {
1268   g_return_if_fail (GTK_IS_LABEL (label));
1269   g_return_if_fail (str != NULL);
1270   
1271   *str = label->text;
1272 }
1273
1274 static void
1275 gtk_label_destroy (GtkObject *object)
1276 {
1277   GtkLabel *label = GTK_LABEL (object);
1278
1279   gtk_label_set_mnemonic_widget (label, NULL);
1280
1281   GTK_OBJECT_CLASS (parent_class)->destroy (object);
1282 }
1283
1284 static void
1285 gtk_label_finalize (GObject *object)
1286 {
1287   GtkLabel *label;
1288   
1289   g_return_if_fail (GTK_IS_LABEL (object));
1290   
1291   label = GTK_LABEL (object);
1292   
1293   g_free (label->label);
1294   g_free (label->text);
1295
1296   if (label->layout)
1297     g_object_unref (G_OBJECT (label->layout));
1298
1299   if (label->attrs)
1300     pango_attr_list_unref (label->attrs);
1301
1302   if (label->effective_attrs)
1303     pango_attr_list_unref (label->effective_attrs);
1304
1305   g_free (label->select_info);
1306
1307   G_OBJECT_CLASS (parent_class)->finalize (object);
1308 }
1309
1310 static void
1311 gtk_label_clear_layout (GtkLabel *label)
1312 {
1313   if (label->layout)
1314     {
1315       g_object_unref (G_OBJECT (label->layout));
1316       label->layout = NULL;
1317     }
1318 }
1319
1320 static void
1321 gtk_label_ensure_layout (GtkLabel *label)
1322 {
1323   GtkWidget *widget;
1324   PangoRectangle logical_rect;
1325   gint rwidth, rheight;
1326
1327   widget = GTK_WIDGET (label);
1328
1329   rwidth = label->misc.xpad * 2;
1330   rheight = label->misc.ypad * 2;
1331
1332   if (!label->layout)
1333     {
1334       PangoAlignment align = PANGO_ALIGN_LEFT; /* Quiet gcc */
1335
1336       label->layout = gtk_widget_create_pango_layout (widget, label->text);
1337
1338       if (label->effective_attrs)
1339         pango_layout_set_attributes (label->layout, label->effective_attrs);
1340       
1341       switch (label->jtype)
1342         {
1343         case GTK_JUSTIFY_LEFT:
1344           align = PANGO_ALIGN_LEFT;
1345           break;
1346         case GTK_JUSTIFY_RIGHT:
1347           align = PANGO_ALIGN_RIGHT;
1348           break;
1349         case GTK_JUSTIFY_CENTER:
1350           align = PANGO_ALIGN_CENTER;
1351           break;
1352         case GTK_JUSTIFY_FILL:
1353           /* FIXME: This just doesn't work to do this */
1354           align = PANGO_ALIGN_LEFT;
1355           pango_layout_set_justify (label->layout, TRUE);
1356           break;
1357         default:
1358           g_assert_not_reached();
1359         }
1360
1361       pango_layout_set_alignment (label->layout, align);
1362
1363       if (label->wrap)
1364         {
1365           GtkWidgetAuxInfo *aux_info;
1366           gint longest_paragraph;
1367           gint width, height;
1368           
1369           aux_info = _gtk_widget_get_aux_info (widget, FALSE);
1370           if (aux_info && aux_info->width > 0)
1371             pango_layout_set_width (label->layout, aux_info->width * PANGO_SCALE);
1372           else
1373             {
1374               pango_layout_set_width (label->layout, -1);
1375               pango_layout_get_extents (label->layout, NULL, &logical_rect);
1376
1377               width = logical_rect.width;
1378               
1379               /* Try to guess a reasonable maximum width */
1380               longest_paragraph = width;
1381               
1382               width = MIN (width,
1383                            PANGO_SCALE * gdk_string_width (gtk_style_get_font (GTK_WIDGET (label)->style),
1384                                                            "This long string gives a good enough length for any line to have."));
1385               width = MIN (width,
1386                            PANGO_SCALE * (gdk_screen_width () + 1) / 2);
1387               
1388               pango_layout_set_width (label->layout, width);
1389               pango_layout_get_extents (label->layout, NULL, &logical_rect);
1390               height = logical_rect.height;
1391               
1392               /* Unfortunately, the above may leave us with a very unbalanced looking paragraph,
1393                * so we try short search for a narrower width that leaves us with the same height
1394                */
1395               if (longest_paragraph > 0)
1396                 {
1397                   gint nlines, perfect_width;
1398                   
1399                   nlines = pango_layout_get_line_count (label->layout);
1400                   perfect_width = (longest_paragraph + nlines - 1) / nlines;
1401                   
1402                   if (perfect_width < width)
1403                     {
1404                       pango_layout_set_width (label->layout, perfect_width);
1405                       pango_layout_get_extents (label->layout, NULL, &logical_rect);
1406                       
1407                       if (logical_rect.height <= height)
1408                         width = perfect_width;
1409                       else
1410                         {
1411                           gint mid_width = (perfect_width + width) / 2;
1412                           
1413                           if (mid_width > perfect_width)
1414                             {
1415                               pango_layout_set_width (label->layout, mid_width);
1416                               pango_layout_get_extents (label->layout, NULL, &logical_rect);
1417                               
1418                               if (logical_rect.height <= height)
1419                                 width = mid_width;
1420                             }
1421                         }
1422                     }
1423                 }
1424               pango_layout_set_width (label->layout, width);
1425             }
1426         }
1427       else              /* !label->wrap */
1428         pango_layout_set_width (label->layout, -1);
1429     }
1430 }
1431
1432 static void
1433 gtk_label_size_request (GtkWidget      *widget,
1434                         GtkRequisition *requisition)
1435 {
1436   GtkLabel *label;
1437   gint width, height;
1438   PangoRectangle logical_rect;
1439   GtkWidgetAuxInfo *aux_info;
1440   
1441   g_return_if_fail (GTK_IS_LABEL (widget));
1442   g_return_if_fail (requisition != NULL);
1443   
1444   label = GTK_LABEL (widget);
1445
1446   /*  
1447    * If word wrapping is on, then the height requisition can depend
1448    * on:
1449    *
1450    *   - Any width set on the widget via gtk_widget_set_usize().
1451    *   - The padding of the widget (xpad, set by gtk_misc_set_padding)
1452    *
1453    * Instead of trying to detect changes to these quantities, if we
1454    * are wrapping, we just rewrap for each size request. Since
1455    * size requisitions are cached by the GTK+ core, this is not
1456    * expensive.
1457    */
1458
1459   if (label->wrap)
1460     gtk_label_clear_layout (label);
1461
1462   gtk_label_ensure_layout (label);
1463
1464   width = label->misc.xpad * 2;
1465   height = label->misc.ypad * 2;
1466
1467   pango_layout_get_extents (label->layout, NULL, &logical_rect);
1468   
1469   aux_info = _gtk_widget_get_aux_info (widget, FALSE);
1470   if (label->wrap && aux_info && aux_info->width > 0)
1471     width += aux_info->width;
1472   else 
1473     width += PANGO_PIXELS (logical_rect.width);
1474   
1475   height += PANGO_PIXELS (logical_rect.height);
1476
1477   requisition->width = width;
1478   requisition->height = height;
1479 }
1480
1481 static void
1482 gtk_label_size_allocate (GtkWidget     *widget,
1483                          GtkAllocation *allocation)
1484 {
1485   GtkLabel *label;
1486
1487   label = GTK_LABEL (widget);
1488   
1489   (* GTK_WIDGET_CLASS (parent_class)->size_allocate) (widget, allocation);
1490
1491   if (label->select_info && label->select_info->window)
1492     {
1493       gdk_window_move_resize (label->select_info->window,
1494                               allocation->x,
1495                               allocation->y,
1496                               allocation->width,
1497                               allocation->height);
1498     }
1499 }
1500
1501 static void
1502 gtk_label_state_changed (GtkWidget   *widget,
1503                          GtkStateType prev_state)
1504 {
1505   GtkLabel *label;
1506   
1507   label = GTK_LABEL (widget);
1508
1509   if (label->select_info)
1510     gtk_label_select_region (label, 0, 0);
1511
1512   if (GTK_WIDGET_CLASS (parent_class)->state_changed)
1513     GTK_WIDGET_CLASS (parent_class)->state_changed (widget, prev_state);
1514 }
1515
1516 static void 
1517 gtk_label_style_set (GtkWidget *widget,
1518                      GtkStyle  *previous_style)
1519 {
1520   GtkLabel *label;
1521   
1522   g_return_if_fail (GTK_IS_LABEL (widget));
1523   
1524   label = GTK_LABEL (widget);
1525
1526   /* We have to clear the layout, fonts etc. may have changed */
1527   gtk_label_clear_layout (label);
1528 }
1529
1530 static void 
1531 gtk_label_direction_changed (GtkWidget        *widget,
1532                              GtkTextDirection previous_dir)
1533 {
1534   GtkLabel *label = GTK_LABEL (widget);
1535
1536   if (label->layout)
1537     pango_layout_context_changed (label->layout);
1538
1539   GTK_WIDGET_CLASS (parent_class)->direction_changed (widget, previous_dir);
1540 }
1541
1542 #if 0
1543 static void
1544 gtk_label_paint_word (GtkLabel     *label,
1545                       gint          x,
1546                       gint          y,
1547                       GtkLabelWord *word,
1548                       GdkRectangle *area)
1549 {
1550   GtkWidget *widget = GTK_WIDGET (label);
1551   GtkLabelULine *uline;
1552   gchar *tmp_str;
1553   
1554   tmp_str = gdk_wcstombs (word->beginning);
1555   if (tmp_str)
1556     {
1557       gtk_paint_string (widget->style, widget->window, widget->state,
1558                         area, widget, "label", 
1559                         x + word->x,
1560                         y + word->y,
1561                         tmp_str);
1562       g_free (tmp_str);
1563     }
1564   
1565   for (uline = word->uline; uline; uline = uline->next)
1566     gtk_paint_hline (widget->style, widget->window, 
1567                      widget->state, area,
1568                      widget, "label", 
1569                      x + uline->x1, x + uline->x2, y + uline->y);
1570 }
1571 #endif
1572
1573 static void
1574 get_layout_location (GtkLabel  *label,
1575                      gint      *xp,
1576                      gint      *yp)
1577 {
1578   GtkMisc *misc;
1579   GtkWidget *widget;
1580   gfloat xalign;
1581   gint x, y;
1582   
1583   misc = GTK_MISC (label);
1584   widget = GTK_WIDGET (label);
1585   
1586   if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
1587     xalign = misc->xalign;
1588   else
1589     xalign = 1.0 - misc->xalign;
1590   
1591   x = floor (widget->allocation.x + (gint)misc->xpad
1592              + ((widget->allocation.width - widget->requisition.width) * xalign)
1593              + 0.5);
1594   
1595   y = floor (widget->allocation.y + (gint)misc->ypad 
1596              + ((widget->allocation.height - widget->requisition.height) * misc->yalign)
1597              + 0.5);
1598   
1599
1600   if (xp)
1601     *xp = x;
1602
1603   if (yp)
1604     *yp = y;
1605 }
1606
1607 static void
1608 gtk_label_draw_cursor (GtkLabel  *label, gint xoffset, gint yoffset)
1609 {
1610   if (label->select_info == NULL)
1611     return;
1612   
1613   if (GTK_WIDGET_DRAWABLE (label))
1614     {
1615       GtkWidget *widget = GTK_WIDGET (label);
1616
1617       GtkTextDirection keymap_direction;
1618       GtkTextDirection widget_direction;
1619       PangoRectangle strong_pos, weak_pos;
1620       gboolean split_cursor;
1621       PangoRectangle *cursor1 = NULL;
1622       PangoRectangle *cursor2 = NULL;
1623       GdkRectangle cursor_location;
1624       GtkTextDirection dir1 = GTK_TEXT_DIR_NONE;
1625       GtkTextDirection dir2 = GTK_TEXT_DIR_NONE;
1626       GdkGC *gc1 = NULL;
1627       GdkGC *gc2 = NULL;
1628
1629       keymap_direction =
1630         (gdk_keymap_get_direction (gdk_keymap_get_default ()) == PANGO_DIRECTION_LTR) ?
1631         GTK_TEXT_DIR_LTR : GTK_TEXT_DIR_RTL;
1632
1633       widget_direction = gtk_widget_get_direction (widget);
1634
1635       gtk_label_ensure_layout (label);
1636       
1637       pango_layout_get_cursor_pos (label->layout, label->select_info->selection_end,
1638                                    &strong_pos, &weak_pos);
1639
1640       g_object_get (gtk_widget_get_settings (widget),
1641                     "gtk-split-cursor", &split_cursor,
1642                     NULL);
1643
1644       if (split_cursor)
1645         {
1646           gc1 = label->select_info->cursor_gc;
1647           cursor1 = &strong_pos;
1648
1649           if (strong_pos.x != weak_pos.x ||
1650               strong_pos.y != weak_pos.y)
1651             {
1652               dir1 = widget_direction;
1653               dir2 = (widget_direction == GTK_TEXT_DIR_LTR) ? GTK_TEXT_DIR_RTL : GTK_TEXT_DIR_LTR;
1654               
1655               gc2 = widget->style->black_gc;
1656               cursor2 = &weak_pos;
1657             }
1658         }
1659       else
1660         {
1661           gc1 = label->select_info->cursor_gc;
1662           
1663           if (keymap_direction == widget_direction)
1664             cursor1 = &strong_pos;
1665           else
1666             cursor1 = &weak_pos;
1667         }
1668       
1669       cursor_location.x = xoffset + PANGO_PIXELS (cursor1->x);
1670       cursor_location.y = yoffset + PANGO_PIXELS (cursor1->y);
1671       cursor_location.width = 0;
1672       cursor_location.height = PANGO_PIXELS (cursor1->height);
1673       
1674       _gtk_draw_insertion_cursor (widget->window, gc1,
1675                                   &cursor_location, dir1);
1676       
1677       if (gc2)
1678         {
1679           cursor_location.x = xoffset + PANGO_PIXELS (cursor2->x);
1680           cursor_location.y = yoffset + PANGO_PIXELS (cursor2->y);
1681           cursor_location.width = 0;
1682           cursor_location.height = PANGO_PIXELS (cursor2->height);
1683           
1684           _gtk_draw_insertion_cursor (widget->window, gc2,
1685                                       &cursor_location, dir2);
1686         }
1687     }
1688 }
1689
1690
1691 static gint
1692 gtk_label_expose (GtkWidget      *widget,
1693                   GdkEventExpose *event)
1694 {
1695   GtkLabel *label;
1696   gint x, y;
1697   
1698   g_return_val_if_fail (GTK_IS_LABEL (widget), FALSE);
1699   g_return_val_if_fail (event != NULL, FALSE);
1700   
1701   label = GTK_LABEL (widget);
1702
1703   gtk_label_ensure_layout (label);
1704   
1705   if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_MAPPED (widget) &&
1706       label->text && (*label->text != '\0'))
1707     {
1708       get_layout_location (label, &x, &y);
1709       
1710       gtk_paint_layout (widget->style,
1711                         widget->window,
1712                         GTK_WIDGET_STATE (widget),
1713                         FALSE,
1714                         &event->area,
1715                         widget,
1716                         "label",
1717                         x, y,
1718                         label->layout);
1719       
1720       if (label->select_info &&
1721           (label->select_info->selection_anchor !=
1722            label->select_info->selection_end))
1723         {
1724           gint range[2];
1725           GdkRegion *clip;
1726           GtkStateType state;
1727           
1728           range[0] = label->select_info->selection_anchor;
1729           range[1] = label->select_info->selection_end;
1730
1731           if (range[0] > range[1])
1732             {
1733               gint tmp = range[0];
1734               range[0] = range[1];
1735               range[1] = tmp;
1736             }
1737
1738           clip = gdk_pango_layout_get_clip_region (label->layout,
1739                                                    x, y,
1740                                                    range,
1741                                                    1);
1742
1743           /* FIXME should use gtk_paint, but it can't use a clip
1744            * region
1745            */
1746
1747           gdk_gc_set_clip_region (widget->style->black_gc, clip);
1748
1749
1750           state = GTK_STATE_SELECTED;
1751           if (!GTK_WIDGET_HAS_FOCUS (widget))
1752             state = GTK_STATE_ACTIVE;
1753               
1754           gdk_draw_layout_with_colors (widget->window,
1755                                        widget->style->black_gc,
1756                                        x, y,
1757                                        label->layout,
1758                                        &widget->style->text[state],
1759                                        &widget->style->base[state]);
1760
1761           gdk_gc_set_clip_region (widget->style->black_gc, NULL);
1762           gdk_region_destroy (clip);
1763         }
1764       else if (label->select_info && GTK_WIDGET_HAS_FOCUS (widget))
1765         gtk_label_draw_cursor (label, x, y);
1766     }
1767
1768   return TRUE;
1769 }
1770
1771 static void
1772 gtk_label_set_uline_text_internal (GtkLabel    *label,
1773                                    const gchar *str)
1774 {
1775   guint accel_key = GDK_VoidSymbol;
1776
1777   gchar *new_str;
1778   gchar *pattern;
1779   const gchar *src;
1780   gchar *dest, *pattern_dest;
1781   gboolean underscore;
1782       
1783   g_return_if_fail (GTK_IS_LABEL (label));
1784   g_return_if_fail (str != NULL);
1785
1786   /* Convert text to wide characters */
1787
1788   new_str = g_new (gchar, strlen (str) + 1);
1789   pattern = g_new (gchar, g_utf8_strlen (str, -1) + 1);
1790   
1791   underscore = FALSE;
1792
1793   if (str == NULL)
1794     str = "";
1795   
1796   src = str;
1797   dest = new_str;
1798   pattern_dest = pattern;
1799   
1800   while (*src)
1801     {
1802       gunichar c;
1803       gchar *next_src;
1804
1805       c = g_utf8_get_char (src);
1806       if (c == (gunichar)-1)
1807         {
1808           g_warning ("Invalid input string");
1809           g_free (new_str);
1810           g_free (pattern);
1811           return;
1812         }
1813       next_src = g_utf8_next_char (src);
1814       
1815       if (underscore)
1816         {
1817           if (c == '_')
1818             *pattern_dest++ = ' ';
1819           else
1820             {
1821               *pattern_dest++ = '_';
1822               if (accel_key == GDK_VoidSymbol)
1823                 accel_key = gdk_keyval_to_lower (c);
1824             }
1825
1826           while (src < next_src)
1827             *dest++ = *src++;
1828           
1829           underscore = FALSE;
1830         }
1831       else
1832         {
1833           if (c == '_')
1834             {
1835               underscore = TRUE;
1836               src = next_src;
1837             }
1838           else
1839             {
1840               while (src < next_src)
1841                 *dest++ = *src++;
1842           
1843               *pattern_dest++ = ' ';
1844             }
1845         }
1846     }
1847   *dest = 0;
1848   *pattern_dest = 0;
1849   
1850   gtk_label_set_text_internal (label, new_str);
1851   gtk_label_set_pattern_internal (label, pattern);
1852   
1853   g_free (pattern);
1854
1855   label->mnemonic_keyval = accel_key;
1856 }
1857
1858 guint      
1859 gtk_label_parse_uline (GtkLabel    *label,
1860                        const gchar *str)
1861 {
1862   guint keyval;
1863   guint orig_keyval;
1864   
1865   g_return_val_if_fail (GTK_IS_LABEL (label), GDK_VoidSymbol);
1866   g_return_val_if_fail (str != NULL, GDK_VoidSymbol);
1867
1868   orig_keyval = label->mnemonic_keyval;
1869   
1870   gtk_label_set_label_internal (label, g_strdup (str ? str : ""));
1871   gtk_label_set_use_markup_internal (label, FALSE);
1872   gtk_label_set_use_underline_internal (label, TRUE);
1873   
1874   gtk_label_recalculate (label);
1875
1876   keyval = label->mnemonic_keyval;
1877   label->mnemonic_keyval = GDK_VoidSymbol;
1878   
1879   gtk_label_setup_mnemonic (label, orig_keyval);
1880   
1881   return keyval;
1882 }
1883
1884 /**
1885  * gtk_label_set_text_with_mnemonic:
1886  * @label: a #GtkLabel
1887  * @str: a string
1888  * 
1889  * Sets the label's text from the string @str.
1890  * If characters in @str are preceded by an underscore, they are underlined
1891  * indicating that they represent a keyboard accelerator called a mnemonic.
1892  * The mnemonic key can be used to activate another widget, chosen automatically,
1893  * or explicitly using gtk_label_set_mnemonic_widget().
1894  **/
1895 void
1896 gtk_label_set_text_with_mnemonic (GtkLabel    *label,
1897                                   const gchar *str)
1898 {
1899   guint last_keyval;
1900   
1901   g_return_if_fail (GTK_IS_LABEL (label));
1902   g_return_if_fail (str != NULL);
1903
1904   last_keyval = label->mnemonic_keyval;
1905   
1906   gtk_label_set_label_internal (label, g_strdup (str ? str : ""));
1907   gtk_label_set_use_markup_internal (label, FALSE);
1908   gtk_label_set_use_underline_internal (label, TRUE);
1909   
1910   gtk_label_recalculate (label);
1911
1912   gtk_label_setup_mnemonic (label, last_keyval);
1913 }
1914
1915 static void
1916 gtk_label_realize_cursor_gc (GtkLabel *label)
1917 {
1918   GdkColor *cursor_color;
1919   GdkColor red = {0, 0xffff, 0x0000, 0x0000};
1920
1921   if (label->select_info == NULL)
1922     return;
1923   
1924   if (label->select_info->cursor_gc)
1925     gdk_gc_unref (label->select_info->cursor_gc);
1926
1927   gtk_widget_style_get (GTK_WIDGET (label), "cursor_color", &cursor_color, NULL);
1928   label->select_info->cursor_gc = gdk_gc_new (GTK_WIDGET (label)->window);
1929   if (cursor_color)
1930     gdk_gc_set_rgb_fg_color (label->select_info->cursor_gc, cursor_color);
1931   else
1932     gdk_gc_set_rgb_fg_color (label->select_info->cursor_gc, &red);
1933 }
1934
1935 static void
1936 gtk_label_realize (GtkWidget *widget)
1937 {
1938   GtkLabel *label;
1939
1940   label = GTK_LABEL (widget);
1941   
1942   (* GTK_WIDGET_CLASS (parent_class)->realize) (widget);
1943
1944   if (label->select_info)
1945     {
1946       gtk_label_create_window (label);
1947       gtk_label_realize_cursor_gc (label);
1948     }
1949 }
1950
1951 static void
1952 gtk_label_unrealize_cursor_gc (GtkLabel *label)
1953 {
1954   if (label->select_info == NULL)
1955     return;
1956   
1957   if (label->select_info->cursor_gc)
1958     {
1959       gdk_gc_unref (label->select_info->cursor_gc);
1960       label->select_info->cursor_gc = NULL;
1961     }
1962 }
1963
1964 static void
1965 gtk_label_unrealize (GtkWidget *widget)
1966 {
1967   GtkLabel *label;
1968
1969   label = GTK_LABEL (widget);
1970
1971   if (label->select_info)
1972     {
1973       gtk_label_unrealize_cursor_gc (label);
1974       gtk_label_destroy_window (label);
1975     }
1976   
1977   (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
1978 }
1979
1980 static void
1981 gtk_label_map (GtkWidget *widget)
1982 {
1983   GtkLabel *label;
1984
1985   label = GTK_LABEL (widget);
1986   
1987   (* GTK_WIDGET_CLASS (parent_class)->map) (widget);
1988   
1989   if (label->select_info)
1990     gdk_window_show (label->select_info->window);
1991 }
1992
1993 static void
1994 gtk_label_unmap (GtkWidget *widget)
1995 {
1996   GtkLabel *label;
1997
1998   label = GTK_LABEL (widget);
1999
2000   if (label->select_info)
2001     gdk_window_hide (label->select_info->window);
2002   
2003   (* GTK_WIDGET_CLASS (parent_class)->unmap) (widget);
2004 }
2005
2006 static void
2007 window_to_layout_coords (GtkLabel *label,
2008                          gint     *x,
2009                          gint     *y)
2010 {
2011   gint lx, ly;
2012   GtkWidget *widget;
2013
2014   widget = GTK_WIDGET (label);
2015   
2016   /* get layout location in widget->window coords */
2017   get_layout_location (label, &lx, &ly);
2018   
2019   if (x)
2020     {
2021       *x += widget->allocation.x; /* go to widget->window */
2022       *x -= lx;                   /* go to layout */
2023     }
2024
2025   if (y)
2026     {
2027       *y += widget->allocation.y; /* go to widget->window */
2028       *y -= ly;                   /* go to layout */
2029     }
2030 }
2031
2032 #if 0
2033 static void
2034 layout_to_window_coords (GtkLabel *label,
2035                          gint     *x,
2036                          gint     *y)
2037 {
2038   gint lx, ly;
2039   GtkWidget *widget;
2040
2041   widget = GTK_WIDGET (label);
2042   
2043   /* get layout location in widget->window coords */
2044   get_layout_location (label, &lx, &ly);
2045   
2046   if (x)
2047     {
2048       *x += lx;                   /* go to widget->window */
2049       *x -= widget->allocation.x; /* go to selection window */
2050     }
2051
2052   if (y)
2053     {
2054       *y += ly;                   /* go to widget->window */
2055       *y -= widget->allocation.y; /* go to selection window */
2056     }
2057 }
2058 #endif
2059
2060 static void
2061 get_layout_index (GtkLabel *label,
2062                   gint      x,
2063                   gint      y,
2064                   gint     *index)
2065 {
2066   gint trailing = 0;
2067   const gchar *cluster;
2068   const gchar *cluster_end;
2069
2070   *index = 0;
2071   
2072   gtk_label_ensure_layout (label);
2073   
2074   window_to_layout_coords (label, &x, &y);
2075
2076   x *= PANGO_SCALE;
2077   y *= PANGO_SCALE;
2078   
2079   pango_layout_xy_to_index (label->layout,
2080                             x, y,
2081                             index, &trailing);
2082
2083   
2084   cluster = label->text + *index;
2085   cluster_end = cluster;
2086   while (trailing)
2087     {
2088       cluster_end = g_utf8_next_char (cluster_end);
2089       --trailing;
2090     }
2091
2092   *index += (cluster_end - cluster);
2093 }
2094
2095 static void
2096 gtk_label_select_word (GtkLabel *label)
2097 {
2098   gint min, max;
2099   
2100   gint start_index = gtk_label_move_backward_word (label, label->select_info->selection_end);
2101   gint end_index = gtk_label_move_forward_word (label, label->select_info->selection_end);
2102
2103   min = MIN (label->select_info->selection_anchor,
2104              label->select_info->selection_end);
2105   max = MAX (label->select_info->selection_anchor,
2106              label->select_info->selection_end);
2107
2108   min = MIN (min, start_index);
2109   max = MAX (max, end_index);
2110
2111   gtk_label_select_region_index (label, min, max);
2112 }
2113
2114 static gint
2115 gtk_label_button_press (GtkWidget      *widget,
2116                         GdkEventButton *event)
2117 {
2118   GtkLabel *label;
2119   gint index = 0;
2120   
2121   label = GTK_LABEL (widget);
2122
2123   if (label->select_info == NULL)
2124     return FALSE;
2125
2126   if (event->button == 1)
2127     {
2128       if (!GTK_WIDGET_HAS_FOCUS (widget))
2129         gtk_widget_grab_focus (widget);
2130
2131       if (event->type == GDK_3BUTTON_PRESS)
2132         {
2133           gtk_label_select_region_index (label, 0, strlen (label->label));
2134           return TRUE;
2135         }
2136       
2137       if (event->type == GDK_2BUTTON_PRESS)
2138         {
2139           gtk_label_select_word (label);
2140           return TRUE;
2141         }
2142       
2143       get_layout_index (label, event->x, event->y, &index);
2144       
2145       if ((label->select_info->selection_anchor !=
2146            label->select_info->selection_end) &&
2147           (event->state & GDK_SHIFT_MASK))
2148         {
2149           gint min, max;
2150           
2151           /* extend (same as motion) */
2152           min = MIN (label->select_info->selection_anchor,
2153                      label->select_info->selection_end);
2154           max = MAX (label->select_info->selection_anchor,
2155                      label->select_info->selection_end);
2156           
2157           min = MIN (min, index);
2158           max = MAX (max, index);
2159           
2160           /* ensure the anchor is opposite index */
2161           if (index == min)
2162             {
2163               gint tmp = min;
2164               min = max;
2165               max = tmp;
2166             }
2167           
2168           gtk_label_select_region_index (label, min, max);
2169         }
2170       else
2171         {
2172           if (event->type == GDK_3BUTTON_PRESS)
2173               gtk_label_select_region_index (label, 0, strlen (label->label));
2174           else if (event->type == GDK_2BUTTON_PRESS)
2175               gtk_label_select_word (label);
2176           else 
2177             /* start a replacement */
2178             gtk_label_select_region_index (label, index, index);
2179         }
2180   
2181       return TRUE;
2182     }
2183   else if (event->button == 3 && event->type == GDK_BUTTON_PRESS)
2184     {
2185       gtk_label_do_popup (label, event);
2186
2187       return TRUE;
2188       
2189     }
2190   return FALSE;
2191 }
2192
2193 static gint
2194 gtk_label_button_release (GtkWidget      *widget,
2195                           GdkEventButton *event)
2196
2197 {
2198   GtkLabel *label;
2199
2200   label = GTK_LABEL (widget);
2201   
2202   if (label->select_info == NULL)
2203     return FALSE;
2204   
2205   if (event->button != 1)
2206     return FALSE;
2207   
2208   /* The goal here is to return TRUE iff we ate the
2209    * button press to start selecting.
2210    */
2211   
2212   return TRUE;
2213 }
2214
2215 static gint
2216 gtk_label_motion (GtkWidget      *widget,
2217                   GdkEventMotion *event)
2218 {
2219   GtkLabel *label;
2220   gint index;
2221   gint x, y;
2222   
2223   label = GTK_LABEL (widget);
2224   
2225   if (label->select_info == NULL)
2226     return FALSE;  
2227
2228   if ((event->state & GDK_BUTTON1_MASK) == 0)
2229     return FALSE;
2230
2231   gdk_window_get_pointer (label->select_info->window,
2232                           &x, &y, NULL);
2233   
2234   get_layout_index (label, x, y, &index);
2235
2236   gtk_label_select_region_index (label,
2237                                  label->select_info->selection_anchor,
2238                                  index);
2239   
2240   return TRUE;
2241 }
2242
2243 static void
2244 gtk_label_create_window (GtkLabel *label)
2245 {
2246   GtkWidget *widget;
2247   GdkWindowAttr attributes;
2248   gint attributes_mask;
2249   
2250   g_assert (label->select_info);
2251   g_assert (GTK_WIDGET_REALIZED (label));
2252   
2253   if (label->select_info->window)
2254     return;
2255   
2256   widget = GTK_WIDGET (label);
2257
2258   attributes.x = widget->allocation.x;
2259   attributes.y = widget->allocation.y;
2260   attributes.width = widget->allocation.width;
2261   attributes.height = widget->allocation.height;
2262   attributes.window_type = GDK_WINDOW_TEMP;
2263   attributes.wclass = GDK_INPUT_ONLY;
2264   attributes.override_redirect = TRUE;
2265   attributes.event_mask = gtk_widget_get_events (widget) |
2266     GDK_BUTTON_PRESS_MASK        |
2267     GDK_BUTTON_RELEASE_MASK      |
2268     GDK_BUTTON_MOTION_MASK;
2269
2270   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_NOREDIR;
2271
2272   label->select_info->window = gdk_window_new (widget->window,
2273                                                &attributes, attributes_mask);
2274   gdk_window_set_user_data (label->select_info->window, widget);  
2275 }
2276
2277 static void
2278 gtk_label_destroy_window (GtkLabel *label)
2279 {
2280   g_assert (label->select_info);
2281
2282   if (label->select_info->window == NULL)
2283     return;
2284   
2285   gdk_window_set_user_data (label->select_info->window, NULL);
2286   gdk_window_destroy (label->select_info->window);
2287   label->select_info->window = NULL;
2288 }
2289
2290 /**
2291  * gtk_label_set_selectable:
2292  * @label: a #GtkLabel
2293  * @setting: %TRUE to allow selecting text in the label
2294  *
2295  * Selectable labels allow the user to select text from the label, for
2296  * copy-and-paste.
2297  * 
2298  **/
2299 void
2300 gtk_label_set_selectable (GtkLabel *label,
2301                           gboolean  setting)
2302 {
2303   gboolean old_setting;
2304   
2305   g_return_if_fail (GTK_IS_LABEL (label));
2306   
2307   setting = setting != FALSE;
2308   old_setting = label->select_info != NULL;
2309   
2310   if (setting)
2311     {
2312       if (label->select_info == NULL)
2313         {
2314           label->select_info = g_new0 (GtkLabelSelectionInfo, 1);
2315
2316           GTK_WIDGET_SET_FLAGS (label, GTK_CAN_FOCUS);
2317       
2318           if (GTK_WIDGET_REALIZED (label))
2319             {
2320               gtk_label_create_window (label);
2321               gtk_label_realize_cursor_gc (label);
2322             }
2323
2324           if (GTK_WIDGET_MAPPED (label))
2325             gdk_window_show (label->select_info->window);
2326         }
2327     }
2328   else
2329     {
2330       if (label->select_info)
2331         {
2332           /* unselect, to give up the selection */
2333           gtk_label_select_region (label, 0, 0);
2334           
2335           gtk_label_unrealize_cursor_gc (label);
2336           
2337           if (label->select_info->window)
2338             {
2339               gtk_label_destroy_window (label);
2340             }
2341
2342           g_free (label->select_info);
2343
2344           label->select_info = NULL;
2345
2346           GTK_WIDGET_UNSET_FLAGS (label, GTK_CAN_FOCUS);
2347         }
2348     }
2349   if (setting != old_setting)
2350     {
2351       g_object_freeze_notify (G_OBJECT (label));
2352       g_object_notify (G_OBJECT (label), "selectable");
2353       g_object_notify (G_OBJECT (label), "cursor_position");
2354       g_object_notify (G_OBJECT (label), "selection_bound");
2355       g_object_thaw_notify (G_OBJECT (label));
2356       gtk_widget_queue_draw (GTK_WIDGET (label));
2357     }
2358 }
2359
2360 /**
2361  * gtk_label_get_selectable:
2362  * @label: a #GtkLabel
2363  * 
2364  * Gets the value set by gtk_label_set_selectable().
2365  * 
2366  * Return value: %TRUE if the user can copy text from the label
2367  **/
2368 gboolean
2369 gtk_label_get_selectable (GtkLabel *label)
2370 {
2371   g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
2372
2373   return label->select_info != NULL;
2374 }
2375
2376 static void
2377 get_text_callback (GtkClipboard     *clipboard,
2378                    GtkSelectionData *selection_data,
2379                    guint             info,
2380                    gpointer          user_data_or_owner)
2381 {
2382   GtkLabel *label;
2383   
2384   label = GTK_LABEL (user_data_or_owner);
2385   
2386   if ((label->select_info->selection_anchor !=
2387        label->select_info->selection_end) &&
2388       label->text)
2389     {
2390       gint start, end;
2391       gint len;
2392       
2393       start = MIN (label->select_info->selection_anchor,
2394                    label->select_info->selection_end);
2395       end = MAX (label->select_info->selection_anchor,
2396                  label->select_info->selection_end);
2397
2398       len = strlen (label->text);
2399
2400       if (end > len)
2401         end = len;
2402
2403       if (start > len)
2404         start = len;
2405
2406       gtk_selection_data_set_text (selection_data,
2407                                    label->text + start,
2408                                    end - start);
2409     }
2410 }
2411
2412 static void
2413 clear_text_callback (GtkClipboard     *clipboard,
2414                      gpointer          user_data_or_owner)
2415 {
2416   GtkLabel *label;
2417
2418   label = GTK_LABEL (user_data_or_owner);
2419
2420   if (label->select_info)
2421     {
2422       label->select_info->selection_anchor = label->select_info->selection_end;
2423       
2424       gtk_widget_queue_draw (GTK_WIDGET (label));
2425     }
2426 }
2427
2428 static void
2429 gtk_label_select_region_index (GtkLabel *label,
2430                                gint      anchor_index,
2431                                gint      end_index)
2432 {
2433   static const GtkTargetEntry targets[] = {
2434     { "STRING", 0, 0 },
2435     { "TEXT",   0, 0 }, 
2436     { "COMPOUND_TEXT", 0, 0 },
2437     { "UTF8_STRING", 0, 0 }
2438   };
2439
2440   g_return_if_fail (GTK_IS_LABEL (label));
2441   
2442   if (label->select_info)
2443     {
2444       GtkClipboard *clipboard;
2445
2446       if (label->select_info->selection_anchor == anchor_index &&
2447           label->select_info->selection_end == end_index)
2448         return;
2449
2450       label->select_info->selection_anchor = anchor_index;
2451       label->select_info->selection_end = end_index;
2452
2453       clipboard = gtk_clipboard_get (GDK_SELECTION_PRIMARY);      
2454       
2455       if (anchor_index != end_index)
2456         {
2457           gtk_clipboard_set_with_owner (clipboard,
2458                                         targets,
2459                                         G_N_ELEMENTS (targets),
2460                                         get_text_callback,
2461                                         clear_text_callback,
2462                                         G_OBJECT (label));
2463         }
2464       else
2465         {
2466           if (gtk_clipboard_get_owner (clipboard) == G_OBJECT (label))
2467             gtk_clipboard_clear (clipboard);
2468         }
2469
2470       gtk_widget_queue_draw (GTK_WIDGET (label));
2471
2472       g_object_freeze_notify (G_OBJECT (label));
2473       g_object_notify (G_OBJECT (label), "cursor_position");
2474       g_object_notify (G_OBJECT (label), "selection_bound");
2475       g_object_thaw_notify (G_OBJECT (label));
2476     }
2477 }
2478
2479 /**
2480  * gtk_label_select_region:
2481  * @label: a #GtkLabel
2482  * @start_offset: start offset (in characters not bytes)
2483  * @end_offset: end offset (in characters not bytes)
2484  *
2485  * Selects a range of characters in the label, if the label is selectable.
2486  * See gtk_label_set_selectable(). If the label is not selectable,
2487  * this function has no effect. If @start_offset or
2488  * @end_offset are -1, then the end of the label will be substituted.
2489  * 
2490  **/
2491 void
2492 gtk_label_select_region  (GtkLabel *label,
2493                           gint      start_offset,
2494                           gint      end_offset)
2495 {
2496   g_return_if_fail (GTK_IS_LABEL (label));
2497   
2498   if (label->text && label->select_info)
2499     {
2500       if (start_offset < 0)
2501         start_offset = g_utf8_strlen (label->text, -1);
2502       
2503       if (end_offset < 0)
2504         end_offset = g_utf8_strlen (label->text, -1);
2505       
2506       gtk_label_select_region_index (label,
2507                                      g_utf8_offset_to_pointer (label->text, start_offset) - label->text,
2508                                      g_utf8_offset_to_pointer (label->text, end_offset) - label->text);
2509     }
2510 }
2511
2512 /**
2513  * gtk_label_get_selection_bounds:
2514  * @label: a #GtkLabel
2515  * @start: return location for start of selection, as a character offset
2516  * @end: return location for end of selection, as a character offset
2517  * 
2518  * Gets the selected range of characters in the label, returning %TRUE
2519  * if there's a selection.
2520  * 
2521  * Return value: %TRUE if selection is non-empty
2522  **/
2523 gboolean
2524 gtk_label_get_selection_bounds (GtkLabel  *label,
2525                                 gint      *start,
2526                                 gint      *end)
2527 {
2528   g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
2529
2530   if (label->select_info == NULL)
2531     {
2532       /* not a selectable label */
2533       if (start)
2534         *start = 0;
2535       if (end)
2536         *end = 0;
2537
2538       return FALSE;
2539     }
2540   else
2541     {
2542       gint start_index, end_index;
2543       gint start_offset, end_offset;
2544       gint len;
2545       
2546       start_index = MIN (label->select_info->selection_anchor,
2547                    label->select_info->selection_end);
2548       end_index = MAX (label->select_info->selection_anchor,
2549                  label->select_info->selection_end);
2550
2551       len = strlen (label->text);
2552
2553       if (end_index > len)
2554         end_index = len;
2555
2556       if (start_index > len)
2557         start_index = len;
2558       
2559       start_offset = g_utf8_strlen (label->text, start_index);
2560       end_offset = g_utf8_strlen (label->text, end_index);
2561
2562       if (start_offset > end_offset)
2563         {
2564           gint tmp = start_offset;
2565           start_offset = end_offset;
2566           end_offset = tmp;
2567         }
2568       
2569       if (start)
2570         *start = start_offset;
2571
2572       if (end)
2573         *end = end_offset;
2574
2575       return start_offset != end_offset;
2576     }
2577 }
2578
2579
2580 /**
2581  * gtk_label_get_layout:
2582  * @label: a #GtkLabel
2583  * 
2584  * Gets the #PangoLayout used to display the label.
2585  * The layout is useful to e.g. convert text positions to
2586  * pixel positions, in combination with gtk_label_get_layout_offsets().
2587  * The returned layout is owned by the label so need not be
2588  * freed by the caller.
2589  * 
2590  * Return value: the #PangoLayout for this label
2591  **/
2592 PangoLayout*
2593 gtk_label_get_layout (GtkLabel *label)
2594 {
2595   g_return_val_if_fail (GTK_IS_LABEL (label), NULL);
2596
2597   gtk_label_ensure_layout (label);
2598
2599   return label->layout;
2600 }
2601
2602 /**
2603  * gtk_label_get_layout_offsets:
2604  * @label: a #GtkLabel
2605  * @x: location to store X offset of layout, or %NULL
2606  * @y: location to store Y offset of layout, or %NULL
2607  *
2608  * Obtains the coordinates where the label will draw the #PangoLayout
2609  * representing the text in the label; useful to convert mouse events
2610  * into coordinates inside the #PangoLayout, e.g. to take some action
2611  * if some part of the label is clicked. Of course you will need to
2612  * create a #GtkEventBox to receive the events, and pack the label
2613  * inside it, since labels are a #GTK_NO_WINDOW widget. Remember
2614  * when using the #PangoLayout functions you need to convert to
2615  * and from pixels using PANGO_PIXELS() or #PANGO_SCALE.
2616  * 
2617  **/
2618 void
2619 gtk_label_get_layout_offsets (GtkLabel *label,
2620                               gint     *x,
2621                               gint     *y)
2622 {
2623   g_return_if_fail (GTK_IS_LABEL (label));
2624   
2625   get_layout_location (label, x, y);
2626 }
2627
2628 /**
2629  * gtk_label_set_use_markup:
2630  * @label: a #GtkLabel
2631  * @setting: %TRUE if the label's text should be parsed for markup.
2632  *
2633  * Sets whether the text of the label contains markup in Pango's
2634  * text markup lango. See gtk_label_set_markup().
2635  **/
2636 void
2637 gtk_label_set_use_markup (GtkLabel *label,
2638                           gboolean  setting)
2639 {
2640   g_return_if_fail (GTK_IS_LABEL (label));
2641
2642   gtk_label_set_use_markup_internal (label, setting);
2643   gtk_label_recalculate (label);
2644 }
2645
2646 /**
2647  * gtk_label_get_use_markup:
2648  * @label: a #GtkLabel
2649  *
2650  * Returns whether the label's text is interpreted as marked up with the
2651  * Pango text markup language. See gtk_label_set_use_markup ().
2652  *
2653  * Return value: %TRUE if the label's text will be parsed for markup.
2654  **/
2655 gboolean
2656 gtk_label_get_use_markup (GtkLabel *label)
2657 {
2658   g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
2659   
2660   return label->use_markup;
2661 }
2662
2663 /**
2664  * gtk_label_set_use_underline:
2665  * @label: a #GtkLabel
2666  * @setting: %TRUE if underlines in the text indicate mnemonics
2667  *
2668  * If true, an underline in the text indicates the next character should be
2669  * used for the mnemonic accelerator key.
2670  */
2671 void
2672 gtk_label_set_use_underline (GtkLabel *label,
2673                              gboolean  setting)
2674 {
2675   g_return_if_fail (GTK_IS_LABEL (label));
2676
2677   gtk_label_set_use_underline_internal (label, setting);
2678   gtk_label_recalculate (label);
2679   if (label->use_underline)
2680     gtk_label_setup_mnemonic (label, label->mnemonic_keyval);
2681 }
2682
2683 /**
2684  * gtk_label_get_use_underline:
2685  * @label: a #GtkLabel
2686  *
2687  * Returns whether an embedded underline in the label indicates a
2688  * mnemonic. See gtk_label_set_use_underline ().
2689  *
2690  * Return value: %TRUE whether an embedded underline in the label indicates
2691  *               the mnemonic accelerator keys.
2692  **/
2693 gboolean
2694 gtk_label_get_use_underline (GtkLabel *label)
2695 {
2696   g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
2697   
2698   return label->use_underline;
2699 }
2700
2701 static gboolean
2702 gtk_label_focus (GtkWidget         *widget,
2703                  GtkDirectionType   direction)
2704 {
2705   /* We never want to be in the tab chain */
2706   return FALSE;
2707 }
2708
2709 /* Compute the X position for an offset that corresponds to the "more important
2710  * cursor position for that offset. We use this when trying to guess to which
2711  * end of the selection we should go to when the user hits the left or
2712  * right arrow key.
2713  */
2714 static void
2715 get_better_cursor (GtkLabel *label,
2716                    gint      index,
2717                    gint      *x,
2718                    gint      *y)
2719 {
2720   GtkTextDirection keymap_direction =
2721     (gdk_keymap_get_direction (gdk_keymap_get_default ()) == PANGO_DIRECTION_LTR) ?
2722     GTK_TEXT_DIR_LTR : GTK_TEXT_DIR_RTL;
2723   GtkTextDirection widget_direction = gtk_widget_get_direction (GTK_WIDGET (label));
2724   gboolean split_cursor;
2725   PangoRectangle strong_pos, weak_pos;
2726   
2727   g_object_get (gtk_widget_get_settings (GTK_WIDGET (label)),
2728                 "gtk-split-cursor", &split_cursor,
2729                 NULL);
2730
2731   gtk_label_ensure_layout (label);
2732   
2733   pango_layout_get_cursor_pos (label->layout, index,
2734                                &strong_pos, &weak_pos);
2735
2736   if (split_cursor)
2737     {
2738       *x = strong_pos.x / PANGO_SCALE;
2739       *y = strong_pos.y / PANGO_SCALE;
2740     }
2741   else
2742     {
2743       if (keymap_direction == widget_direction)
2744         {
2745           *x = strong_pos.x / PANGO_SCALE;
2746           *y = strong_pos.y / PANGO_SCALE;
2747         }
2748       else
2749         {
2750           *x = weak_pos.x / PANGO_SCALE;
2751           *y = weak_pos.y / PANGO_SCALE;
2752         }
2753     }
2754 }
2755
2756
2757 static gint
2758 gtk_label_move_logically (GtkLabel *label,
2759                           gint      start,
2760                           gint      count)
2761 {
2762   gint offset = g_utf8_pointer_to_offset (label->label,
2763                                           label->label + start);
2764
2765   if (label->label)
2766     {
2767       PangoLogAttr *log_attrs;
2768       gint n_attrs;
2769       gint length;
2770
2771       gtk_label_ensure_layout (label);
2772       
2773       length = g_utf8_strlen (label->label, -1);
2774
2775       pango_layout_get_log_attrs (label->layout, &log_attrs, &n_attrs);
2776
2777       while (count > 0 && offset < length)
2778         {
2779           do
2780             offset++;
2781           while (offset < length && !log_attrs[offset].is_cursor_position);
2782           
2783           count--;
2784         }
2785       while (count < 0 && offset > 0)
2786         {
2787           do
2788             offset--;
2789           while (offset > 0 && !log_attrs[offset].is_cursor_position);
2790           
2791           count++;
2792         }
2793       
2794       g_free (log_attrs);
2795     }
2796
2797   return g_utf8_offset_to_pointer (label->label, offset) - label->label;
2798 }
2799
2800 static gint
2801 gtk_label_move_visually (GtkLabel *label,
2802                          gint      start,
2803                          gint      count)
2804 {
2805   gint index;
2806
2807   index = start;
2808   
2809   while (count != 0)
2810     {
2811       int new_index, new_trailing;
2812       gboolean split_cursor;
2813       gboolean strong;
2814
2815       gtk_label_ensure_layout (label);
2816
2817       g_object_get (gtk_widget_get_settings (GTK_WIDGET (label)),
2818                     "gtk-split-cursor", &split_cursor,
2819                     NULL);
2820
2821       if (split_cursor)
2822         strong = TRUE;
2823       else
2824         {
2825           GtkTextDirection keymap_direction =
2826             (gdk_keymap_get_direction (gdk_keymap_get_default ()) == PANGO_DIRECTION_LTR) ?
2827             GTK_TEXT_DIR_LTR : GTK_TEXT_DIR_RTL;
2828
2829           strong = keymap_direction == gtk_widget_get_direction (GTK_WIDGET (label));
2830         }
2831       
2832       if (count > 0)
2833         {
2834           pango_layout_move_cursor_visually (label->layout, strong, index, 0, 1, &new_index, &new_trailing);
2835           count--;
2836         }
2837       else
2838         {
2839           pango_layout_move_cursor_visually (label->layout, strong, index, 0, -1, &new_index, &new_trailing);
2840           count++;
2841         }
2842
2843       if (new_index < 0 || new_index == G_MAXINT)
2844         break;
2845
2846       index = new_index;
2847       
2848       while (new_trailing--)
2849         index = g_utf8_next_char (label->label + new_index) - label->label;
2850     }
2851   
2852   return index;
2853 }
2854
2855 static gint
2856 gtk_label_move_forward_word (GtkLabel *label,
2857                              gint      start)
2858 {
2859   gint new_pos = g_utf8_pointer_to_offset (label->label,
2860                                            label->label + start);
2861   gint length;
2862
2863   length = g_utf8_strlen (label->label, -1);
2864   if (new_pos < length)
2865     {
2866       PangoLogAttr *log_attrs;
2867       gint n_attrs;
2868
2869       gtk_label_ensure_layout (label);
2870       
2871       pango_layout_get_log_attrs (label->layout, &log_attrs, &n_attrs);
2872       
2873       /* Find the next word end */
2874       new_pos++;
2875       while (new_pos < n_attrs && !log_attrs[new_pos].is_word_end)
2876         new_pos++;
2877
2878       g_free (log_attrs);
2879     }
2880
2881   return g_utf8_offset_to_pointer (label->label, new_pos) - label->label;
2882 }
2883
2884
2885 static gint
2886 gtk_label_move_backward_word (GtkLabel *label,
2887                               gint      start)
2888 {
2889   gint new_pos = g_utf8_pointer_to_offset (label->label,
2890                                            label->label + start);
2891   gint length;
2892
2893   length = g_utf8_strlen (label->label, -1);
2894   
2895   if (new_pos > 0)
2896     {
2897       PangoLogAttr *log_attrs;
2898       gint n_attrs;
2899
2900       gtk_label_ensure_layout (label);
2901       
2902       pango_layout_get_log_attrs (label->layout, &log_attrs, &n_attrs);
2903       
2904       new_pos -= 1;
2905
2906       /* Find the previous word beginning */
2907       while (new_pos > 0 && !log_attrs[new_pos].is_word_start)
2908         new_pos--;
2909
2910       g_free (log_attrs);
2911     }
2912
2913   return g_utf8_offset_to_pointer (label->label, new_pos) - label->label;
2914 }
2915
2916 static void
2917 gtk_label_move_cursor (GtkLabel       *label,
2918                        GtkMovementStep step,
2919                        gint            count,
2920                        gboolean        extend_selection)
2921 {
2922   gint new_pos;
2923   
2924   if (label->select_info == NULL)
2925     return;
2926   
2927   new_pos = label->select_info->selection_end;
2928
2929   if (label->select_info->selection_end != label->select_info->selection_anchor &&
2930       !extend_selection)
2931     {
2932       /* If we have a current selection and aren't extending it, move to the
2933        * start/or end of the selection as appropriate
2934        */
2935       switch (step)
2936         {
2937         case GTK_MOVEMENT_VISUAL_POSITIONS:
2938           {
2939             gint end_x, end_y;
2940             gint anchor_x, anchor_y;
2941             gboolean end_is_left;
2942             
2943             get_better_cursor (label, label->select_info->selection_end, &end_x, &end_y);
2944             get_better_cursor (label, label->select_info->selection_anchor, &anchor_x, &anchor_y);
2945
2946             end_is_left = (end_y < anchor_y) || (end_y == anchor_y && end_x < anchor_x);
2947             
2948             if (count < 0)
2949               new_pos = end_is_left ? label->select_info->selection_end : label->select_info->selection_anchor;
2950             else
2951               new_pos = !end_is_left ? label->select_info->selection_end : label->select_info->selection_anchor;
2952
2953             break;
2954           }
2955         case GTK_MOVEMENT_LOGICAL_POSITIONS:
2956         case GTK_MOVEMENT_WORDS:
2957           if (count < 0)
2958             new_pos = MIN (label->select_info->selection_end, label->select_info->selection_anchor);
2959           else
2960             new_pos = MAX (label->select_info->selection_end, label->select_info->selection_anchor);
2961           break;
2962         case GTK_MOVEMENT_DISPLAY_LINE_ENDS:
2963         case GTK_MOVEMENT_PARAGRAPH_ENDS:
2964         case GTK_MOVEMENT_BUFFER_ENDS:
2965           /* FIXME: Can do better here */
2966           new_pos = count < 0 ? 0 : strlen (label->label);
2967           break;
2968         case GTK_MOVEMENT_DISPLAY_LINES:
2969         case GTK_MOVEMENT_PARAGRAPHS:
2970         case GTK_MOVEMENT_PAGES:
2971           break;
2972         }
2973     }
2974   else
2975     {
2976       switch (step)
2977         {
2978         case GTK_MOVEMENT_LOGICAL_POSITIONS:
2979           new_pos = gtk_label_move_logically (label, new_pos, count);
2980           break;
2981         case GTK_MOVEMENT_VISUAL_POSITIONS:
2982           new_pos = gtk_label_move_visually (label, new_pos, count);
2983           break;
2984         case GTK_MOVEMENT_WORDS:
2985           while (count > 0)
2986             {
2987               new_pos = gtk_label_move_forward_word (label, new_pos);
2988               count--;
2989             }
2990           while (count < 0)
2991             {
2992               new_pos = gtk_label_move_backward_word (label, new_pos);
2993               count++;
2994             }
2995           break;
2996         case GTK_MOVEMENT_DISPLAY_LINE_ENDS:
2997         case GTK_MOVEMENT_PARAGRAPH_ENDS:
2998         case GTK_MOVEMENT_BUFFER_ENDS:
2999           /* FIXME: Can do better here */
3000           new_pos = count < 0 ? 0 : strlen (label->label);
3001           break;
3002         case GTK_MOVEMENT_DISPLAY_LINES:
3003         case GTK_MOVEMENT_PARAGRAPHS:
3004         case GTK_MOVEMENT_PAGES:
3005           break;
3006         }
3007     }
3008
3009   if (extend_selection)
3010     gtk_label_select_region_index (label,
3011                                    label->select_info->selection_anchor,
3012                                    new_pos);
3013   else
3014     gtk_label_select_region_index (label, new_pos, new_pos);
3015 }
3016
3017 static void
3018 gtk_label_copy_clipboard (GtkLabel *label)
3019 {
3020   if (label->text && label->select_info)
3021     {
3022       gint start, end;
3023       gint len;
3024       
3025       start = MIN (label->select_info->selection_anchor,
3026                    label->select_info->selection_end);
3027       end = MAX (label->select_info->selection_anchor,
3028                  label->select_info->selection_end);
3029
3030       len = strlen (label->text);
3031
3032       if (end > len)
3033         end = len;
3034
3035       if (start > len)
3036         start = len;
3037
3038       if (start != end)
3039         gtk_clipboard_set_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
3040                                 label->text + start, end - start);
3041     }
3042 }
3043
3044 static void
3045 gtk_label_select_all (GtkLabel *label)
3046 {
3047   gtk_label_select_region_index (label, 0, strlen (label->label));
3048 }
3049
3050 /* Quick hack of a popup menu
3051  */
3052 static void
3053 activate_cb (GtkWidget *menuitem,
3054              GtkLabel  *label)
3055 {
3056   const gchar *signal = gtk_object_get_data (GTK_OBJECT (menuitem), "gtk-signal");
3057   gtk_signal_emit_by_name (GTK_OBJECT (label), signal);
3058 }
3059
3060 static void
3061 append_action_signal (GtkLabel     *label,
3062                       GtkWidget    *menu,
3063                       const gchar  *stock_id,
3064                       const gchar  *signal,
3065                       gboolean      sensitive)
3066 {
3067   GtkWidget *menuitem = gtk_image_menu_item_new_from_stock (stock_id, NULL);
3068
3069   gtk_object_set_data (GTK_OBJECT (menuitem), "gtk-signal", (char *)signal);
3070   gtk_signal_connect (GTK_OBJECT (menuitem), "activate",
3071                       GTK_SIGNAL_FUNC (activate_cb), label);
3072
3073   gtk_widget_set_sensitive (menuitem, sensitive);
3074   
3075   gtk_widget_show (menuitem);
3076   gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
3077 }
3078
3079 static void
3080 popup_menu_detach (GtkWidget *attach_widget,
3081                    GtkMenu   *menu)
3082 {
3083   GtkLabel *label;
3084   label = GTK_LABEL (attach_widget);
3085
3086   if (label->select_info)
3087     label->select_info->popup_menu = NULL;
3088 }
3089
3090 static void
3091 popup_position_func (GtkMenu   *menu,
3092                      gint      *x,
3093                      gint      *y,
3094                      gboolean  *push_in,
3095                      gpointer   user_data)
3096 {
3097   GtkLabel *label;
3098   GtkWidget *widget;
3099   GtkRequisition req;
3100   
3101   label = GTK_LABEL (user_data);  
3102   widget = GTK_WIDGET (label);
3103
3104   if (label->select_info == NULL)
3105     return;
3106   
3107   g_return_if_fail (GTK_WIDGET_REALIZED (label));
3108
3109   gdk_window_get_origin (widget->window, x, y);      
3110
3111   gtk_widget_size_request (label->select_info->popup_menu, &req);
3112   
3113   *x += widget->allocation.width / 2;
3114   *y += widget->allocation.height;
3115
3116   *x = CLAMP (*x, 0, MAX (0, gdk_screen_width () - req.width));
3117   *y = CLAMP (*y, 0, MAX (0, gdk_screen_height () - req.height));
3118 }
3119
3120
3121 static void
3122 gtk_label_do_popup (GtkLabel       *label,
3123                     GdkEventButton *event)
3124 {
3125   GtkWidget *menuitem;
3126   gboolean have_selection;
3127
3128   if (label->select_info == NULL)
3129     return;
3130     
3131   if (label->select_info->popup_menu)
3132     gtk_widget_destroy (label->select_info->popup_menu);
3133   
3134   label->select_info->popup_menu = gtk_menu_new ();
3135
3136   gtk_menu_attach_to_widget (GTK_MENU (label->select_info->popup_menu),
3137                              GTK_WIDGET (label),
3138                              popup_menu_detach);
3139
3140   have_selection =
3141     label->select_info->selection_anchor != label->select_info->selection_end;
3142
3143
3144   append_action_signal (label, label->select_info->popup_menu, GTK_STOCK_CUT, "cut_clipboard",
3145                         FALSE);
3146   append_action_signal (label, label->select_info->popup_menu, GTK_STOCK_COPY, "copy_clipboard",
3147                         have_selection);
3148   append_action_signal (label, label->select_info->popup_menu, GTK_STOCK_PASTE, "paste_clipboard",
3149                         FALSE);
3150   
3151   menuitem = gtk_menu_item_new_with_label (_("Select All"));
3152   gtk_signal_connect_object (GTK_OBJECT (menuitem), "activate",
3153                              GTK_SIGNAL_FUNC (gtk_label_select_all), label);
3154   gtk_widget_show (menuitem);
3155   gtk_menu_shell_append (GTK_MENU_SHELL (label->select_info->popup_menu), menuitem);
3156
3157   menuitem = gtk_separator_menu_item_new ();
3158   gtk_widget_show (menuitem);
3159   gtk_menu_shell_append (GTK_MENU_SHELL (label->select_info->popup_menu), menuitem);
3160       
3161   menuitem = gtk_menu_item_new_with_label (_("Input Methods"));
3162   gtk_widget_show (menuitem);
3163   gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), gtk_menu_new ());
3164   gtk_widget_set_sensitive (menuitem, FALSE);
3165   gtk_menu_shell_append (GTK_MENU_SHELL (label->select_info->popup_menu), menuitem);
3166
3167   gtk_signal_emit (GTK_OBJECT (label),
3168                    signals[POPULATE_POPUP],
3169                    label->select_info->popup_menu);
3170   
3171   if (event)
3172     gtk_menu_popup (GTK_MENU (label->select_info->popup_menu), NULL, NULL,
3173                     NULL, NULL,
3174                     event->button, event->time);
3175   else
3176     gtk_menu_popup (GTK_MENU (label->select_info->popup_menu), NULL, NULL,
3177                     popup_position_func, label,
3178                     0, gtk_get_current_event_time ());
3179 }