]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtklabel.c
Fix typo: Italian uses ISO-8859-1, not -2. Add en_GB.
[~andy/gtk] / gtk / gtklabel.c
index 50166fa0debefa671a5104c4d3db810923aa5c87..697f5e10b03c0a648e96bf3f5194a718fa0cf629 100644 (file)
@@ -1,4 +1,4 @@
- /* GTK - The GIMP Toolkit
+/* GTK - The GIMP Toolkit
  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
  *
  * This library is free software; you can redistribute it and/or
  * License along with this library; if not, write to the Free
  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include <math.h>
 #include <string.h>
 #include "gtklabel.h"
 #include "gdk/gdkkeysyms.h"
@@ -24,7 +33,8 @@ enum {
   ARG_0,
   ARG_LABEL,
   ARG_PATTERN,
-  ARG_JUSTIFY
+  ARG_JUSTIFY,
+  ARG_WRAP
 };
 
 typedef struct _GtkLabelULine GtkLabelULine;
@@ -32,7 +42,7 @@ struct _GtkLabelWord
 {
   GdkWChar *beginning;
   gint length;
-
+  
   /* FIXME:
    * We need (space,width) only before we've set (x,y), so to save
    * memory, these pairs should really be wrapped in a union.
@@ -67,24 +77,22 @@ static void gtk_label_get_arg          (GtkObject      *object,
 static void gtk_label_finalize    (GtkObject      *object);
 static void gtk_label_size_request (GtkWidget     *widget,
                                    GtkRequisition *requisition);
+static void gtk_label_style_set    (GtkWidget      *widget,
+                                   GtkStyle       *previous_style);
 static gint gtk_label_expose      (GtkWidget      *widget,
                                    GdkEventExpose *event);
 
-static GtkLabelWord * gtk_label_word_alloc (void);
-static GtkLabelULine * gtk_label_uline_alloc (void);
-static void gtk_label_free_words   (GtkLabel       *label);
-static void gtk_label_free_ulines   (GtkLabelWord *word);
-static gint gtk_label_split_text   (GtkLabel * label);
-static void gtk_label_finalize_lines    (GtkLabel * label, gint line_width);
-static void gtk_label_finalize_lines_wrap(GtkLabel * label, gint line_width);
+static GtkLabelWord*  gtk_label_word_alloc          (void);
+static GtkLabelULine* gtk_label_uline_alloc         (void);
+static void           gtk_label_free_words          (GtkLabel     *label);
+static void           gtk_label_free_ulines         (GtkLabelWord *word);
+static gint           gtk_label_split_text          (GtkLabel     *label);
 
 
 static GtkMiscClass *parent_class = NULL;
 
-static GMemChunk *word_chunk = 0;
-static GtkLabelWord *free_words = 0;
-static GMemChunk *uline_chunk = 0;
-static GtkLabelULine *free_ulines = 0;
+static GMemChunk *word_chunk = NULL;
+static GMemChunk *uline_chunk = NULL;
 
 GtkType
 gtk_label_get_type (void)
@@ -105,7 +113,7 @@ gtk_label_get_type (void)
        (GtkClassInitFunc) NULL,
       };
       
-      label_type = gtk_type_unique (gtk_misc_get_type (), &label_info);
+      label_type = gtk_type_unique (GTK_TYPE_MISC, &label_info);
       gtk_type_set_chunk_alloc (label_type, 32);
     }
   
@@ -121,17 +129,19 @@ gtk_label_class_init (GtkLabelClass *class)
   object_class = (GtkObjectClass*) class;
   widget_class = (GtkWidgetClass*) class;
   
-  parent_class = gtk_type_class (gtk_misc_get_type ());
+  parent_class = gtk_type_class (GTK_TYPE_MISC);
   
   gtk_object_add_arg_type ("GtkLabel::label", GTK_TYPE_STRING, GTK_ARG_READWRITE, ARG_LABEL);
   gtk_object_add_arg_type ("GtkLabel::pattern", GTK_TYPE_STRING, GTK_ARG_READWRITE, ARG_PATTERN);
   gtk_object_add_arg_type ("GtkLabel::justify", GTK_TYPE_JUSTIFICATION, GTK_ARG_READWRITE, ARG_JUSTIFY);
-
+  gtk_object_add_arg_type ("GtkLabel::wrap", GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_WRAP);
+  
   object_class->set_arg = gtk_label_set_arg;
   object_class->get_arg = gtk_label_get_arg;
   object_class->finalize = gtk_label_finalize;
   
   widget_class->size_request = gtk_label_size_request;
+  widget_class->style_set = gtk_label_style_set;
   widget_class->expose_event = gtk_label_expose;
 }
 
@@ -141,13 +151,13 @@ gtk_label_set_arg (GtkObject        *object,
                   guint           arg_id)
 {
   GtkLabel *label;
-
+  
   label = GTK_LABEL (object);
-
+  
   switch (arg_id)
     {
     case ARG_LABEL:
-      gtk_label_set_text (label, GTK_VALUE_STRING (*arg) ? GTK_VALUE_STRING (*arg) : "");
+      gtk_label_set_text (label, GTK_VALUE_STRING (*arg));
       break;
     case ARG_PATTERN:
       gtk_label_set_pattern (label, GTK_VALUE_STRING (*arg));
@@ -155,6 +165,9 @@ gtk_label_set_arg (GtkObject          *object,
     case ARG_JUSTIFY:
       gtk_label_set_justify (label, GTK_VALUE_ENUM (*arg));
       break;
+    case ARG_WRAP:
+      gtk_label_set_line_wrap (label, GTK_VALUE_BOOL (*arg));
+      break;     
     default:
       break;
     }
@@ -166,9 +179,9 @@ gtk_label_get_arg (GtkObject          *object,
                   guint           arg_id)
 {
   GtkLabel *label;
-
+  
   label = GTK_LABEL (object);
-
+  
   switch (arg_id)
     {
     case ARG_LABEL:
@@ -180,6 +193,9 @@ gtk_label_get_arg (GtkObject          *object,
     case ARG_JUSTIFY:
       GTK_VALUE_ENUM (*arg) = label->jtype;
       break;
+    case ARG_WRAP:
+      GTK_VALUE_BOOL (*arg) = label->wrap;
+      break;
     default:
       arg->type = GTK_TYPE_INVALID;
       break;
@@ -192,58 +208,72 @@ gtk_label_init (GtkLabel *label)
   GTK_WIDGET_SET_FLAGS (label, GTK_NO_WINDOW);
   
   label->label = NULL;
+  label->label_wc = NULL;
+  label->pattern = NULL;
+
   label->words = NULL;
+
   label->max_width = 0;
   label->jtype = GTK_JUSTIFY_CENTER;
-  label->pattern = NULL;
   label->wrap = FALSE;
-
+  
   gtk_label_set_text (label, "");
 }
 
 GtkWidget*
-gtk_label_new (const char *str)
+gtk_label_new (const gchar *str)
 {
   GtkLabel *label;
+  
+  label = gtk_type_new (GTK_TYPE_LABEL);
 
-  g_return_val_if_fail (str != NULL, NULL);
-
-  label = gtk_type_new (gtk_label_get_type ());
-
-  gtk_label_set_text (label, str);
-
+  if (str && *str)
+    gtk_label_set_text (label, str);
+  
   return GTK_WIDGET (label);
 }
 
+static inline void
+gtk_label_set_text_internal (GtkLabel *label,
+                            gchar    *str,
+                            GdkWChar *str_wc)
+{
+  gtk_label_free_words (label);
+      
+  g_free (label->label);
+  g_free (label->label_wc);
+  
+  label->label = str;
+  label->label_wc = str_wc;
+  
+  gtk_widget_queue_resize (GTK_WIDGET (label));
+}
+
 void
-gtk_label_set_text (GtkLabel *label,
-                   const char *str)
+gtk_label_set_text (GtkLabel    *label,
+                   const gchar *str)
 {
-  guint len;
-  guint wc_len;
+  GdkWChar *str_wc;
+  gint len;
+  gint wc_len;
   
-  g_return_if_fail (label != NULL);
   g_return_if_fail (GTK_IS_LABEL (label));
-  g_return_if_fail (str != NULL);
-
-  if (label->label)
-    g_free (label->label);
-  label->label = g_strdup (str);
-
-  /* Convert text to wide characters */
-  len = strlen (str);
-  label->label_wc = g_new (GdkWChar, len + 1);
-  wc_len = gdk_mbstowcs (label->label_wc, str, len + 1);
-  label->label_wc[wc_len] = '\0';
-
-  gtk_label_free_words (label);
+  if (!str)
+    str = "";
 
-  if (GTK_WIDGET_VISIBLE (label))
+  if (!label->label || strcmp (label->label, str))
     {
-      if (GTK_WIDGET_MAPPED (label))
-       gtk_widget_queue_clear (GTK_WIDGET (label));
-
-      gtk_widget_queue_resize (GTK_WIDGET (label));
+      /* Convert text to wide characters */
+      len = strlen (str);
+      str_wc = g_new (GdkWChar, len + 1);
+      wc_len = gdk_mbstowcs (str_wc, str, len + 1);
+      if (wc_len >= 0)
+       {
+         str_wc[wc_len] = '\0';
+         gtk_label_set_text_internal (label, g_strdup (str), str_wc);
+       }
+      else
+       g_free (str_wc);
     }
 }
 
@@ -251,73 +281,59 @@ void
 gtk_label_set_pattern (GtkLabel           *label,
                       const gchar *pattern)
 {
-  g_return_if_fail (label != NULL);
   g_return_if_fail (GTK_IS_LABEL (label));
   
-  if (label->pattern)
-    g_free (label->pattern);
-  label->pattern = g_strdup (pattern);
+  gtk_label_free_words (label);
   
-  if (GTK_WIDGET_VISIBLE (label))
-    {
-      if (GTK_WIDGET_MAPPED (label))
-       gtk_widget_queue_clear (GTK_WIDGET (label));
-      
-      gtk_widget_queue_resize (GTK_WIDGET (label));
-    }
+  g_free (label->pattern);
+  label->pattern = g_strdup (pattern);
+
+  gtk_widget_queue_resize (GTK_WIDGET (label));
 }
 
 void
-gtk_label_set_justify (GtkLabel *label, GtkJustification jtype)
+gtk_label_set_justify (GtkLabel        *label,
+                      GtkJustification jtype)
 {
-  g_return_if_fail (label != NULL);
   g_return_if_fail (GTK_IS_LABEL (label));
-
+  g_return_if_fail (jtype >= GTK_JUSTIFY_LEFT && jtype <= GTK_JUSTIFY_FILL);
+  
   if ((GtkJustification) label->jtype != jtype)
     {
-      if ((label->jtype == GTK_JUSTIFY_FILL) || 
-         (jtype == GTK_JUSTIFY_FILL))
-       /* FIXME: think about this a little */
-         gtk_label_free_words (label);
-         
-      label->jtype = jtype;
+      gtk_label_free_words (label);
       
-      if (GTK_WIDGET_VISIBLE (label))
-        {
-          if (GTK_WIDGET_MAPPED (label))
-           gtk_widget_queue_clear (GTK_WIDGET (label));
-          
-          gtk_widget_queue_resize (GTK_WIDGET (label));
-        }
+      label->jtype = jtype;
+
+      gtk_widget_queue_resize (GTK_WIDGET (label));
     }
 }
 
 void
-gtk_label_set_line_wrap (GtkLabel *label, gboolean wrap)
+gtk_label_set_line_wrap (GtkLabel *label,
+                        gboolean  wrap)
 {
-  g_return_if_fail (label != NULL);
   g_return_if_fail (GTK_IS_LABEL (label));
+  
+  wrap = wrap != FALSE;
+  
+  if (label->wrap != wrap)
+    {
+      gtk_label_free_words (label);
 
-  if (label->wrap != wrap) {
-    if (GTK_WIDGET_VISIBLE (label))
-      {
-       if (GTK_WIDGET_MAPPED (label))
-         gtk_widget_queue_clear (GTK_WIDGET (label));
-       
-       gtk_widget_queue_resize (GTK_WIDGET (label));
-      }
-    label->wrap = wrap;
-  }
+      label->wrap = wrap;
+
+      gtk_widget_queue_resize (GTK_WIDGET (label));
+    }
 }
 
 void
-gtk_label_get (GtkLabel  *label,
-              char     **str)
+gtk_label_get (GtkLabel *label,
+              gchar   **str)
 {
   g_return_if_fail (label != NULL);
   g_return_if_fail (GTK_IS_LABEL (label));
   g_return_if_fail (str != NULL);
-
+  
   *str = label->label;
 }
 
@@ -332,126 +348,101 @@ gtk_label_finalize (GtkObject *object)
   label = GTK_LABEL (object);
   
   g_free (label->label);
-  if (label->pattern) 
-    g_free (label->pattern);
+  g_free (label->label_wc);
+  g_free (label->pattern);
+
   gtk_label_free_words (label);
-  (* GTK_OBJECT_CLASS (parent_class)->finalize) (object);
+
+  GTK_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
-static GtkLabelWord *
-gtk_label_word_alloc ()
+static GtkLabelULine*
+gtk_label_uline_alloc (void)
 {
-  GtkLabelWord * word;
+  GtkLabelULine *uline;
+  
+  if (!uline_chunk)
+    uline_chunk = g_mem_chunk_create (GtkLabelWord, 32, G_ALLOC_AND_FREE);
 
-  if (!word_chunk)
-    {
-      word_chunk = g_mem_chunk_new ("GtkLabelWord chunk",
-                                   sizeof (GtkLabelWord),
-                                   32 * sizeof (GtkLabelWord),
-                                   G_ALLOC_ONLY);
-    }
+  uline = g_chunk_new0 (GtkLabelULine, uline_chunk);
   
-  if (free_words)
-    {
-      word = free_words;
-      free_words = word->next;
-    }
-  else
-    {
-      word = g_mem_chunk_alloc (word_chunk);
-    }
-    
-  word->next = 0;
-  word->uline = 0;
-  return word;
+  uline->next = NULL;
+  
+  return uline;
 }
 
 static void
-gtk_label_free_words (GtkLabel * label)
+gtk_label_free_ulines (GtkLabelWord *word)
 {
-  GtkLabelWord * last;
-
-  if (label->words)
+  while (word->uline)
     {
-      for (last = label->words; last->next != 0; last = last->next)
-       gtk_label_free_ulines (label->words);
-      last->next = free_words;
-      free_words = label->words;
-      label->words = 0;
+      GtkLabelULine *uline = word->uline;
+
+      word->uline = uline->next;
+      g_chunk_free (uline, uline_chunk);
     }
 }
-static GtkLabelULine *
-gtk_label_uline_alloc ()
-{
-  GtkLabelULine * uline;
 
-  if (!uline_chunk)
-    {
-      uline_chunk = g_mem_chunk_new ("GtkLabelWord chunk",
-                                    sizeof (GtkLabelULine),
-                                    32 * sizeof (GtkLabelULine),
-                                    G_ALLOC_ONLY);
-    }
+static GtkLabelWord*
+gtk_label_word_alloc (void)
+{
+  GtkLabelWord * word;
   
-  if (free_ulines)
-    {
-      uline = free_ulines;
-      free_ulines = uline->next;
-    }
-  else
-    {
-      uline = g_mem_chunk_alloc (uline_chunk);
-    }
-    
-  uline->next = 0;
-  return uline;
+  if (!word_chunk)
+    word_chunk = g_mem_chunk_create (GtkLabelWord, 32, G_ALLOC_AND_FREE);
+  
+  word = g_chunk_new0 (GtkLabelWord, word_chunk);
+  
+  word->beginning = NULL;
+  word->next = NULL;
+  word->uline = NULL;
+
+  return word;
 }
 
 static void
-gtk_label_free_ulines (GtkLabelWord *word)
+gtk_label_free_words (GtkLabel *label)
 {
-  GtkLabelULine *last;
-  if (word->uline)
+  while (label->words)
     {
-      for (last = word->uline; last->next != 0; last = last->next)
-         ;
-      last->next = free_ulines;
-      free_ulines = word->uline;
-      word->uline = 0;
+      GtkLabelWord *word = label->words;
+
+      label->words = word->next;
+
+      gtk_label_free_ulines (word);
+
+      g_chunk_free (word, word_chunk);
     }
 }
-  
+
 static gint
-gtk_label_split_text (GtkLabel * label)
+gtk_label_split_text (GtkLabel *label)
 {
   GtkLabelWord *word, **tailp;
   gint space_width, line_width, max_line_width;
   GdkWChar *str, *p;
   
-  g_return_val_if_fail (GTK_WIDGET (label)->style->font != 0, 0);
-
   gtk_label_free_words (label);
-  if (label->label == 0)
-      return 0;
+  if (label->label == NULL)
+    return 0;
   
-  /*
-   * Split text at new-lines.
-   */
+  /* Split text at new-lines. */
   space_width = gdk_string_width (GTK_WIDGET (label)->style->font, " ");
-
+  
   line_width = 0;
   max_line_width = 0;
   tailp = &label->words;
   str = label->label_wc;
+  
   while (*str)
     {
       word = gtk_label_word_alloc ();
-
-      if ((str == label->label_wc) || (str[-1] == '\n'))
+      
+      if (str == label->label_wc || str[-1] == '\n')
        {
          /* Paragraph break */
          word->space = 0;
-
+         
          max_line_width = MAX (line_width, max_line_width);
          line_width = 0;
        }
@@ -468,51 +459,62 @@ gtk_label_split_text (GtkLabel * label)
          /* Regular inter-word space */
          word->space = space_width;
        }
-
+      
       word->beginning = str;
       
       word->length = 0;
       p = word->beginning;
-      while (*p && (*p != '\n'))
+      while (*p && *p != '\n')
        {
          word->length++;
          p++;
        }
-
+      
       word->width = gdk_text_width_wc (GTK_WIDGET (label)->style->font, str, word->length);
-
+      
       str += word->length;
       if (*str)
-         str++;
+       str++;
       
       line_width += word->space + word->width;
-
+      
       *tailp = word;
       tailp = &word->next;
     }
-
+  
+  /* Add an empty word to represent an empty line
+   */
+  if (str == label->label_wc || str[-1] == '\n')
+    {
+      word = gtk_label_word_alloc ();
+      
+      word->space = 0;
+      word->beginning = str;
+      word->length = 0;
+      word->width = 0;
+      
+      *tailp = word;
+      tailp = &word->next;
+    }
+  
   return MAX (line_width, max_line_width);
 }
 
+/* this needs to handle white space better. */
 static gint
-gtk_label_split_text_wrapped (GtkLabel * label)
+gtk_label_split_text_wrapped (GtkLabel *label)
 {
-  /* this needs to handle white space better. */
   GtkLabelWord *word, **tailp;
   gint space_width, line_width, max_line_width;
   GdkWChar *str, *p;
   
-  g_return_val_if_fail (GTK_WIDGET (label)->style->font != 0, 0);
-
   gtk_label_free_words (label);
-  if (label->label == 0)
-      return 0;
+  if (label->label == NULL)
+    return 0;
   
-  /*
-   * Split text at new-lines.  (Or at spaces in the case of paragraphs).
-   */
+  /* Split text at new-lines.  (Or at spaces in the case of paragraphs). */
   space_width = gdk_string_width (GTK_WIDGET (label)->style->font, " ");
-
+  
   line_width = 0;
   max_line_width = 0;
   tailp = &label->words;
@@ -520,61 +522,60 @@ gtk_label_split_text_wrapped (GtkLabel * label)
   while (*str)
     {
       word = gtk_label_word_alloc ();
-
+      
       if (str == label->label_wc || str[-1] == '\n')
        {
          /* Paragraph break */
          word->space = 0;
-
+         
          max_line_width = MAX (line_width, max_line_width);
          line_width = 0;
        }
       else if (str[0] == ' ')
        {
          gint nspaces = 0;
-
+         
          while (str[0] == ' ')
            {
              nspaces++;
              str++;
            }
-
+         
          if (label->jtype == GTK_JUSTIFY_FILL)
            word->space = (space_width * 3 + 1) / 2;
          else
-           word->space += space_width * nspaces;
+           word->space = space_width * nspaces;
        }
       else
        {
          /* Regular inter-word space */
          word->space = space_width;
        }
-
+      
       word->beginning = str;
       word->length = 0;
       p = word->beginning;
-      while (*p && (!gdk_iswspace (*p)))
+      while (*p && !gdk_iswspace (*p))
        {
          word->length++;
          p++;
        }
       word->width = gdk_text_width_wc (GTK_WIDGET (label)->style->font, str, word->length);
-
+      
       str += word->length;
       if (*str)
-         str++;
+       str++;
       
       line_width += word->space + word->width;
-
+      
       *tailp = word;
       tailp = &word->next;
     }
-
+  
   return MAX (line_width, max_line_width);
 }
 
-/*
- * gtk_label_pick_width
+/* gtk_label_pick_width
  *
  * Split paragraphs, trying to make each line at least min_width,
  * and trying even harder to make each line no longer than max_width.
@@ -586,13 +587,15 @@ gtk_label_split_text_wrapped (GtkLabel * label)
  * short final line.)
  */
 static gint
-gtk_label_pick_width (GtkLabel * label, gint min_width, gint max_width)
+gtk_label_pick_width (GtkLabel *label,
+                     gint      min_width,
+                     gint      max_width)
 {
   GtkLabelWord *word;
   gint width, line_width;
   
   g_return_val_if_fail (label->wrap, min_width);
-
+  
   line_width = 0;
   width = 0;
   for (word = label->words; word; word = word->next)
@@ -608,45 +611,47 @@ gtk_label_pick_width (GtkLabel * label, gint min_width, gint max_width)
        }
       line_width += word->space + word->width;
     }
-
+  
   return MAX (width, line_width);
 }
 
-/*
- * Here, we finalize the lines.
+/* Here, we finalize the lines.
  * This is only for non-wrap labels.  Wrapped labels
  * use gtk_label_finalize_wrap instead.
  */
 static void
-gtk_label_finalize_lines (GtkLabel * label, gint line_width)
+gtk_label_finalize_lines (GtkLabel       *label,
+                         GtkRequisition *requisition,
+                         gint            max_line_width)
 {
-  GtkLabelWord * line;
+  GtkLabelWord *line;
   gint y, baseline_skip, y_max;
   gint i, j;
   gchar *ptrn;
   
   g_return_if_fail (!label->wrap);
   ptrn = label->pattern;
-
+  
   y = 0;
-  baseline_skip = GTK_WIDGET (label)->style->font->ascent + GTK_WIDGET (label)->style->font->descent + 2;
+  baseline_skip = (GTK_WIDGET (label)->style->font->ascent +
+                  GTK_WIDGET (label)->style->font->descent + 2);
   
   for (line = label->words; line; line = line->next)
     {
       if (label->jtype == GTK_JUSTIFY_CENTER)
-         line->x = (line_width - line->width) / 2;
+       line->x = (max_line_width - line->width) / 2;
       else if (label->jtype == GTK_JUSTIFY_RIGHT)
-         line->x = line_width - line->width;
+       line->x = max_line_width - line->width;
       else
-         line->x = 0;
-
+       line->x = 0;
+      
       line->y = y + GTK_WIDGET (label)->style->font->ascent + 1;
       y_max = 0;
-
+      
       /* now we deal with the underline stuff; */
-      if (ptrn && (ptrn[0] != '\0'))
+      if (ptrn && ptrn[0] != '\0')
        {
-         for (i=0;i<line->length;i++)
+         for (i = 0; i < line->length; i++)
            {
              if (ptrn[i] == '\0')
                break;
@@ -658,16 +663,16 @@ gtk_label_finalize_lines (GtkLabel * label, gint line_width)
                  gint width;
                  gint offset;
                  GtkLabelULine *uline;
-             
-                 for (j=i+1;j<line->length;j++)
+                 
+                 for (j = i + 1; j < line->length; j++)
                    {
                      if (ptrn[j] == '\0')
                        break;
                      else if (ptrn[j] == ' ')
                        break;
                    }
-                 /*
-                  * good.  Now we have an underlined segment.
+                 
+                 /* good.  Now we have an underlined segment.
                   * let's measure it and record it.
                   */
                  offset = gdk_text_width_wc (GTK_WIDGET (label)->style->font,
@@ -697,14 +702,16 @@ gtk_label_finalize_lines (GtkLabel * label, gint line_width)
       y += (baseline_skip + y_max);
     }
   
-  label->max_width = line_width;
-  GTK_WIDGET (label)->requisition.width = line_width + 2 * label->misc.xpad;
-  GTK_WIDGET (label)->requisition.height = y + 2 * label->misc.ypad;
+  label->max_width = max_line_width;
+  requisition->width = max_line_width + 2 * label->misc.xpad;
+  requisition->height = y + 2 * label->misc.ypad;
 }
 
 /* this finalizes word-wrapped words */
 static void
-gtk_label_finalize_lines_wrap (GtkLabel * label, gint line_width)
+gtk_label_finalize_lines_wrap (GtkLabel       *label,
+                              GtkRequisition *requisition,
+                              gint            max_line_width)
 {
   GtkLabelWord *word, *line, *next_line;
   GtkWidget *widget;
@@ -712,31 +719,32 @@ gtk_label_finalize_lines_wrap (GtkLabel * label, gint line_width)
   gint x, y, space, extra_width, add_space, baseline_skip;
   
   g_return_if_fail (label->wrap);
-
+  
   ptrn = label->pattern;
   y = 0;
-  baseline_skip = GTK_WIDGET (label)->style->font->ascent + GTK_WIDGET (label)->style->font->descent + 1;
+  baseline_skip = (GTK_WIDGET (label)->style->font->ascent +
+                  GTK_WIDGET (label)->style->font->descent + 1);
   
   for (line = label->words; line != 0; line = next_line)
     {
       space = 0;
-      extra_width = line_width - line->width;
+      extra_width = max_line_width - line->width;
       
       for (next_line = line->next; next_line; next_line = next_line->next)
        {
          if (next_line->space == 0)
-             break;            /* New paragraph */
+           break;              /* New paragraph */
          if (next_line->space + next_line->width > extra_width)
-             break;
+           break;
          extra_width -= next_line->space + next_line->width;
          space += next_line->space;
        }
-
+      
       line->x = 0;
       line->y = y + GTK_WIDGET (label)->style->font->ascent + 1;
       x = line->width;
       add_space = 0;
-
+      
       for (word = line->next; word != next_line; word = word->next)
        {
          if (next_line && next_line->space)
@@ -753,26 +761,25 @@ gtk_label_finalize_lines_wrap (GtkLabel * label, gint line_width)
          word->y = line->y;
          x = word->x + word->width;
        }
-
+      
       y += (baseline_skip);
     }
-
-  label->max_width = line_width;
+  
+  label->max_width = max_line_width;
   widget = GTK_WIDGET (label);
-  widget->requisition.width = line_width + 2 * label->misc.xpad;
-  widget->requisition.height = y + 2 * label->misc.ypad + 1;
+  requisition->width = max_line_width + 2 * label->misc.xpad;
+  requisition->height = y + 2 * label->misc.ypad + 1;
 }
-      
+
 static void
 gtk_label_size_request (GtkWidget      *widget,
                        GtkRequisition *requisition)
 {
   GtkLabel *label;
   
-  g_return_if_fail (widget != NULL);
   g_return_if_fail (GTK_IS_LABEL (widget));
   g_return_if_fail (requisition != NULL);
-
+  
   label = GTK_LABEL (widget);
 
   /*
@@ -795,7 +802,7 @@ gtk_label_size_request (GtkWidget      *widget,
    * Too much of a pain to detect all these case, so always re-fill.  I
    * don't think it's really that slow.
    */
-
+  
   if (label->wrap)
     {
       GtkWidgetAuxInfo *aux_info;
@@ -806,13 +813,13 @@ gtk_label_size_request (GtkWidget      *widget,
       aux_info = gtk_object_get_data (GTK_OBJECT (widget), "gtk-aux-info");
       if (aux_info && aux_info->width > 0)
        {
-         label->max_width = MAX(aux_info->width - 2 * label->misc.xpad, 1);
+         label->max_width = MAX (aux_info->width - 2 * label->misc.xpad, 1);
          gtk_label_split_text_wrapped (label);
        }
       else
        {
          label->max_width = gdk_string_width (GTK_WIDGET (label)->style->font,
-                                       "This is a good enough length for any line to have.");
+                                              "This is a good enough length for any line to have.");
          label->max_width = MIN (label->max_width, (gdk_screen_width () + 1) / 2);
          label->max_width = MIN (label->max_width, longest_paragraph);
          if (longest_paragraph > 0)
@@ -822,49 +829,65 @@ gtk_label_size_request (GtkWidget      *widget,
              nlines = (longest_paragraph + label->max_width - 1) / label->max_width;
              perfect_width = (longest_paragraph + nlines - 1) / nlines;
              label->max_width = gtk_label_pick_width (label,
-                                                perfect_width,
-                                                label->max_width);
+                                                      perfect_width,
+                                                      label->max_width);
            }
        }
-      gtk_label_finalize_lines_wrap (label, label->max_width);
+      gtk_label_finalize_lines_wrap (label, requisition, label->max_width);
     }
-  else if (label->words == 0)
+  else if (!label->words)
     {
       label->max_width = gtk_label_split_text (label);
-      gtk_label_finalize_lines (label, label->max_width);
-      
+      gtk_label_finalize_lines (label, requisition, label->max_width);
     }
+}
+
+static void 
+gtk_label_style_set (GtkWidget *widget,
+                    GtkStyle  *previous_style)
+{
+  GtkLabel *label;
 
-  if (requisition != &widget->requisition)
-    *requisition = widget->requisition;
+  g_return_if_fail (GTK_IS_LABEL (widget));
+  
+  label = GTK_LABEL (widget);
+  
+  /* Clear the list of words so that they are recomputed on
+   * size_request
+   */
+  if (previous_style && label->words)
+    gtk_label_free_words (label);
 }
+
 static void
-gtk_label_paint_word (GtkLabel *label,
-                     gint x,
-                     gint y,
+gtk_label_paint_word (GtkLabel     *label,
+                     gint          x,
+                     gint          y,
                      GtkLabelWord *word,
                      GdkRectangle *area)
 {
   GtkWidget *widget = GTK_WIDGET (label);
   GtkLabelULine *uline;
   gchar *tmp_str;
-
+  
   tmp_str = gdk_wcstombs (word->beginning);
-  gtk_paint_string (widget->style, widget->window, widget->state,
-                   area, widget, "label", 
-                   x + word->x,
-                   y + word->y,
-                   tmp_str);
-  g_free (tmp_str);
-  
-  for (uline = word->uline;uline;uline = uline->next)
+  if (tmp_str)
+    {
+      gtk_paint_string (widget->style, widget->window, widget->state,
+                       area, widget, "label", 
+                       x + word->x,
+                       y + word->y,
+                       tmp_str);
+      g_free (tmp_str);
+    }
+  
+  for (uline = word->uline; uline; uline = uline->next)
     gtk_paint_hline (widget->style, widget->window, 
                     widget->state, area,
                     widget, "label", 
-                    x + uline->x1, x +uline->x2, y + uline->y);
-
-
+                    x + uline->x1, x + uline->x2, y + uline->y);
 }
+
 static gint
 gtk_label_expose (GtkWidget      *widget,
                  GdkEventExpose *event)
@@ -873,34 +896,33 @@ gtk_label_expose (GtkWidget      *widget,
   GtkMisc *misc;
   GtkLabelWord *word;
   gint x, y;
-
-  g_return_val_if_fail (widget != NULL, FALSE);
+  
   g_return_val_if_fail (GTK_IS_LABEL (widget), FALSE);
   g_return_val_if_fail (event != NULL, FALSE);
   
-
-  if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_MAPPED (widget))
+  label = GTK_LABEL (widget);
+  
+  if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_MAPPED (widget) &&
+      label->label && (*label->label != '\0'))
     {
-      label = GTK_LABEL (widget);
       misc = GTK_MISC (widget);
-
-      g_return_val_if_fail (label->words != 0 || label->label == 0, FALSE);
-
-
+      
       /*
        * GC Clipping
        */
       gdk_gc_set_clip_rectangle (widget->style->white_gc, &event->area);
       gdk_gc_set_clip_rectangle (widget->style->fg_gc[widget->state], &event->area);
+      
+      x = floor (widget->allocation.x + (gint)misc->xpad
+                + (((gint)widget->allocation.width - 
+                   (gint)label->max_width - 2 * (gint)misc->xpad)
+                   * misc->xalign) + 0.5);
+      
+      y = floor (widget->allocation.y + (gint)misc->ypad 
+                + (((gint)widget->allocation.height
+                    - (gint)widget->requisition.height)
+                   * misc->yalign) + 0.5);
 
-      x = widget->allocation.x + misc->xpad +
-       (widget->allocation.width - label->max_width) 
-       * misc->xalign + 0.5;
-
-      y = (widget->allocation.y
-          + (widget->allocation.height
-             - widget->requisition.height) * misc->yalign
-          + misc->ypad + 0.5);
       for (word = label->words; word; word = word->next)
        {
          gchar save = word->beginning[word->length];
@@ -908,34 +930,47 @@ gtk_label_expose (GtkWidget      *widget,
          gtk_label_paint_word (label, x, y, word, &event->area);
          word->beginning[word->length] = save;
        }
-
+      
       gdk_gc_set_clip_mask (widget->style->white_gc, NULL);
       gdk_gc_set_clip_mask (widget->style->fg_gc[widget->state], NULL);
     }
+
   return TRUE;
 }
+
 guint      
-gtk_label_parse_uline (GtkLabel         *label,
-                      const gchar      *string)
+gtk_label_parse_uline (GtkLabel    *label,
+                      const gchar *string)
 {
   guint accel_key = GDK_VoidSymbol;
-  GdkWChar *p, *q;
+  GdkWChar *p, *q, *string_wc;
   gchar *r;
   gchar *pattern;
-
-  gint length;
+  gint length, wc_length;
   gboolean underscore;
+  
+  g_return_val_if_fail (GTK_IS_LABEL (label), GDK_VoidSymbol);
+  g_return_val_if_fail (string != NULL, GDK_VoidSymbol);
 
+  /* Convert text to wide characters */
   length = strlen (string);
+  string_wc = g_new (GdkWChar, length + 1);
+  wc_length = gdk_mbstowcs (string_wc, string, length + 1);
+  if (wc_length < 0)
+    {
+      g_free (string_wc);
+      return GDK_VoidSymbol;
+    }
+
+  string_wc[wc_length] = '\0';
   
-  gtk_label_set_text (label, string);
   pattern = g_new (gchar, length+1);
-
+  
   underscore = FALSE;
-
-  p = q = label->label_wc;
+  
+  p = q = string_wc;
   r = pattern;
-
+  
   while (*p)
     {
       if (underscore)
@@ -948,7 +983,7 @@ gtk_label_parse_uline (GtkLabel         *label,
              if (accel_key == GDK_VoidSymbol)
                accel_key = gdk_keyval_to_lower (*p);
            }
-
+         
          *q++ = *p;
          underscore = FALSE;
        }
@@ -966,10 +1001,11 @@ gtk_label_parse_uline (GtkLabel         *label,
     }
   *q = 0;
   *r = 0;
+  
+  gtk_label_set_text_internal (label, gdk_wcstombs (string_wc), string_wc);
   gtk_label_set_pattern (label, pattern);
   
   g_free (pattern);
-
+  
   return accel_key;
 }