]> Pileus Git - ~andy/gtk/blob - gtk/gtkcellrenderertext.c
Intern some more strings.
[~andy/gtk] / gtk / gtkcellrenderertext.c
1 /* gtkcellrenderertext.c
2  * Copyright (C) 2000  Red Hat, Inc.,  Jonathan Blandford <jrb@redhat.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library 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  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #include <config.h>
21 #include <stdlib.h>
22 #include "gtkcellrenderertext.h"
23 #include "gtkeditable.h"
24 #include "gtkentry.h"
25 #include "gtkmarshalers.h"
26 #include "gtkintl.h"
27 #include "gtkprivate.h"
28 #include "gtktreeprivate.h"
29 #include "gtkalias.h"
30
31 static void gtk_cell_renderer_text_init       (GtkCellRendererText      *celltext);
32 static void gtk_cell_renderer_text_class_init (GtkCellRendererTextClass *class);
33 static void gtk_cell_renderer_text_finalize   (GObject                  *object);
34
35 static void gtk_cell_renderer_text_get_property  (GObject                  *object,
36                                                   guint                     param_id,
37                                                   GValue                   *value,
38                                                   GParamSpec               *pspec);
39 static void gtk_cell_renderer_text_set_property  (GObject                  *object,
40                                                   guint                     param_id,
41                                                   const GValue             *value,
42                                                   GParamSpec               *pspec);
43 static void gtk_cell_renderer_text_get_size   (GtkCellRenderer          *cell,
44                                                GtkWidget                *widget,
45                                                GdkRectangle             *cell_area,
46                                                gint                     *x_offset,
47                                                gint                     *y_offset,
48                                                gint                     *width,
49                                                gint                     *height);
50 static void gtk_cell_renderer_text_render     (GtkCellRenderer          *cell,
51                                                GdkWindow                *window,
52                                                GtkWidget                *widget,
53                                                GdkRectangle             *background_area,
54                                                GdkRectangle             *cell_area,
55                                                GdkRectangle             *expose_area,
56                                                GtkCellRendererState      flags);
57
58 static GtkCellEditable *gtk_cell_renderer_text_start_editing (GtkCellRenderer      *cell,
59                                                               GdkEvent             *event,
60                                                               GtkWidget            *widget,
61                                                               const gchar          *path,
62                                                               GdkRectangle         *background_area,
63                                                               GdkRectangle         *cell_area,
64                                                               GtkCellRendererState  flags);
65
66 enum {
67   EDITED,
68   LAST_SIGNAL
69 };
70
71 enum {
72   PROP_0,
73
74   PROP_TEXT,
75   PROP_MARKUP,
76   PROP_ATTRIBUTES,
77   PROP_SINGLE_PARAGRAPH_MODE,
78   PROP_WIDTH_CHARS,
79   PROP_WRAP_WIDTH,
80   
81   /* Style args */
82   PROP_BACKGROUND,
83   PROP_FOREGROUND,
84   PROP_BACKGROUND_GDK,
85   PROP_FOREGROUND_GDK,
86   PROP_FONT,
87   PROP_FONT_DESC,
88   PROP_FAMILY,
89   PROP_STYLE,
90   PROP_VARIANT,
91   PROP_WEIGHT,
92   PROP_STRETCH,
93   PROP_SIZE,
94   PROP_SIZE_POINTS,
95   PROP_SCALE,
96   PROP_EDITABLE,
97   PROP_STRIKETHROUGH,
98   PROP_UNDERLINE,
99   PROP_RISE,
100   PROP_LANGUAGE,
101   PROP_ELLIPSIZE,
102   PROP_WRAP_MODE,
103   
104   /* Whether-a-style-arg-is-set args */
105   PROP_BACKGROUND_SET,
106   PROP_FOREGROUND_SET,
107   PROP_FAMILY_SET,
108   PROP_STYLE_SET,
109   PROP_VARIANT_SET,
110   PROP_WEIGHT_SET,
111   PROP_STRETCH_SET,
112   PROP_SIZE_SET,
113   PROP_SCALE_SET,
114   PROP_EDITABLE_SET,
115   PROP_STRIKETHROUGH_SET,
116   PROP_UNDERLINE_SET,
117   PROP_RISE_SET,
118   PROP_LANGUAGE_SET,
119   PROP_ELLIPSIZE_SET
120 };
121
122 static gpointer parent_class;
123 static guint text_cell_renderer_signals [LAST_SIGNAL];
124
125 #define GTK_CELL_RENDERER_TEXT_PATH "gtk-cell-renderer-text-path"
126
127 #define GTK_CELL_RENDERER_TEXT_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_CELL_RENDERER_TEXT, GtkCellRendererTextPrivate))
128
129 typedef struct _GtkCellRendererTextPrivate GtkCellRendererTextPrivate;
130 struct _GtkCellRendererTextPrivate
131 {
132   guint single_paragraph : 1;
133   guint language_set : 1;
134   guint markup_set : 1;
135   guint ellipsize_set : 1;
136   
137   gulong focus_out_id;
138   PangoLanguage *language;
139   PangoEllipsizeMode ellipsize;
140   PangoWrapMode wrap_mode;
141   
142   gulong populate_popup_id;
143   gulong entry_menu_popdown_timeout;
144   gboolean in_entry_menu;
145   
146   gint width_chars;
147   gint wrap_width;
148   
149   GtkWidget *entry;
150 };
151
152
153 GType
154 gtk_cell_renderer_text_get_type (void)
155 {
156   static GType cell_text_type = 0;
157
158   if (!cell_text_type)
159     {
160       static const GTypeInfo cell_text_info =
161       {
162         sizeof (GtkCellRendererTextClass),
163         NULL,           /* base_init */
164         NULL,           /* base_finalize */
165         (GClassInitFunc) gtk_cell_renderer_text_class_init,
166         NULL,           /* class_finalize */
167         NULL,           /* class_data */
168         sizeof (GtkCellRendererText),
169         0,              /* n_preallocs */
170         (GInstanceInitFunc) gtk_cell_renderer_text_init,
171       };
172
173       cell_text_type =
174         g_type_register_static (GTK_TYPE_CELL_RENDERER, I_("GtkCellRendererText"),
175                                 &cell_text_info, 0);
176     }
177
178   return cell_text_type;
179 }
180
181 static void
182 gtk_cell_renderer_text_init (GtkCellRendererText *celltext)
183 {
184   GtkCellRendererTextPrivate *priv;
185
186   priv = GTK_CELL_RENDERER_TEXT_GET_PRIVATE (celltext);
187
188   GTK_CELL_RENDERER (celltext)->xalign = 0.0;
189   GTK_CELL_RENDERER (celltext)->yalign = 0.5;
190   GTK_CELL_RENDERER (celltext)->xpad = 2;
191   GTK_CELL_RENDERER (celltext)->ypad = 2;
192   celltext->fixed_height_rows = -1;
193   celltext->font = pango_font_description_new ();
194
195   priv->width_chars = -1;
196   priv->wrap_width = -1;
197 }
198
199 static void
200 gtk_cell_renderer_text_class_init (GtkCellRendererTextClass *class)
201 {
202   GObjectClass *object_class = G_OBJECT_CLASS (class);
203   GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (class);
204
205   parent_class = g_type_class_peek_parent (class);
206   
207   object_class->finalize = gtk_cell_renderer_text_finalize;
208   
209   object_class->get_property = gtk_cell_renderer_text_get_property;
210   object_class->set_property = gtk_cell_renderer_text_set_property;
211
212   cell_class->get_size = gtk_cell_renderer_text_get_size;
213   cell_class->render = gtk_cell_renderer_text_render;
214   cell_class->start_editing = gtk_cell_renderer_text_start_editing;
215
216   g_object_class_install_property (object_class,
217                                    PROP_TEXT,
218                                    g_param_spec_string ("text",
219                                                         P_("Text"),
220                                                         P_("Text to render"),
221                                                         NULL,
222                                                         GTK_PARAM_READWRITE));
223   
224   g_object_class_install_property (object_class,
225                                    PROP_MARKUP,
226                                    g_param_spec_string ("markup",
227                                                         P_("Markup"),
228                                                         P_("Marked up text to render"),
229                                                         NULL,
230                                                         GTK_PARAM_WRITABLE));
231
232   g_object_class_install_property (object_class,
233                                    PROP_ATTRIBUTES,
234                                    g_param_spec_boxed ("attributes",
235                                                        P_("Attributes"),
236                                                        P_("A list of style attributes to apply to the text of the renderer"),
237                                                        PANGO_TYPE_ATTR_LIST,
238                                                        GTK_PARAM_READWRITE));
239
240   g_object_class_install_property (object_class,
241                                    PROP_SINGLE_PARAGRAPH_MODE,
242                                    g_param_spec_boolean ("single-paragraph-mode",
243                                                          P_("Single Paragraph Mode"),
244                                                          P_("Whether or not to keep all text in a single paragraph"),
245                                                          FALSE,
246                                                          GTK_PARAM_READWRITE));
247
248   
249   g_object_class_install_property (object_class,
250                                    PROP_BACKGROUND,
251                                    g_param_spec_string ("background",
252                                                         P_("Background color name"),
253                                                         P_("Background color as a string"),
254                                                         NULL,
255                                                         GTK_PARAM_WRITABLE));
256
257   g_object_class_install_property (object_class,
258                                    PROP_BACKGROUND_GDK,
259                                    g_param_spec_boxed ("background-gdk",
260                                                        P_("Background color"),
261                                                        P_("Background color as a GdkColor"),
262                                                        GDK_TYPE_COLOR,
263                                                        GTK_PARAM_READWRITE));  
264
265   g_object_class_install_property (object_class,
266                                    PROP_FOREGROUND,
267                                    g_param_spec_string ("foreground",
268                                                         P_("Foreground color name"),
269                                                         P_("Foreground color as a string"),
270                                                         NULL,
271                                                         GTK_PARAM_WRITABLE));
272
273   g_object_class_install_property (object_class,
274                                    PROP_FOREGROUND_GDK,
275                                    g_param_spec_boxed ("foreground-gdk",
276                                                        P_("Foreground color"),
277                                                        P_("Foreground color as a GdkColor"),
278                                                        GDK_TYPE_COLOR,
279                                                        GTK_PARAM_READWRITE));
280
281
282   g_object_class_install_property (object_class,
283                                    PROP_EDITABLE,
284                                    g_param_spec_boolean ("editable",
285                                                          P_("Editable"),
286                                                          P_("Whether the text can be modified by the user"),
287                                                          FALSE,
288                                                          GTK_PARAM_READWRITE));
289
290   g_object_class_install_property (object_class,
291                                    PROP_FONT,
292                                    g_param_spec_string ("font",
293                                                         P_("Font"),
294                                                         P_("Font description as a string"),
295                                                         NULL,
296                                                         GTK_PARAM_READWRITE));
297
298   g_object_class_install_property (object_class,
299                                    PROP_FONT_DESC,
300                                    g_param_spec_boxed ("font-desc",
301                                                        P_("Font"),
302                                                        P_("Font description as a PangoFontDescription struct"),
303                                                        PANGO_TYPE_FONT_DESCRIPTION,
304                                                        GTK_PARAM_READWRITE));
305
306   
307   g_object_class_install_property (object_class,
308                                    PROP_FAMILY,
309                                    g_param_spec_string ("family",
310                                                         P_("Font family"),
311                                                         P_("Name of the font family, e.g. Sans, Helvetica, Times, Monospace"),
312                                                         NULL,
313                                                         GTK_PARAM_READWRITE));
314
315   g_object_class_install_property (object_class,
316                                    PROP_STYLE,
317                                    g_param_spec_enum ("style",
318                                                       P_("Font style"),
319                                                       P_("Font style"),
320                                                       PANGO_TYPE_STYLE,
321                                                       PANGO_STYLE_NORMAL,
322                                                       GTK_PARAM_READWRITE));
323
324   g_object_class_install_property (object_class,
325                                    PROP_VARIANT,
326                                    g_param_spec_enum ("variant",
327                                                      P_("Font variant"),
328                                                      P_("Font variant"),
329                                                       PANGO_TYPE_VARIANT,
330                                                       PANGO_VARIANT_NORMAL,
331                                                       GTK_PARAM_READWRITE));
332   
333   g_object_class_install_property (object_class,
334                                    PROP_WEIGHT,
335                                    g_param_spec_int ("weight",
336                                                      P_("Font weight"),
337                                                      P_("Font weight"),
338                                                      0,
339                                                      G_MAXINT,
340                                                      PANGO_WEIGHT_NORMAL,
341                                                      GTK_PARAM_READWRITE));
342
343    g_object_class_install_property (object_class,
344                                    PROP_STRETCH,
345                                    g_param_spec_enum ("stretch",
346                                                       P_("Font stretch"),
347                                                       P_("Font stretch"),
348                                                       PANGO_TYPE_STRETCH,
349                                                       PANGO_STRETCH_NORMAL,
350                                                       GTK_PARAM_READWRITE));
351   
352   g_object_class_install_property (object_class,
353                                    PROP_SIZE,
354                                    g_param_spec_int ("size",
355                                                      P_("Font size"),
356                                                      P_("Font size"),
357                                                      0,
358                                                      G_MAXINT,
359                                                      0,
360                                                      GTK_PARAM_READWRITE));
361
362   g_object_class_install_property (object_class,
363                                    PROP_SIZE_POINTS,
364                                    g_param_spec_double ("size-points",
365                                                         P_("Font points"),
366                                                         P_("Font size in points"),
367                                                         0.0,
368                                                         G_MAXDOUBLE,
369                                                         0.0,
370                                                         GTK_PARAM_READWRITE));  
371
372   g_object_class_install_property (object_class,
373                                    PROP_SCALE,
374                                    g_param_spec_double ("scale",
375                                                         P_("Font scale"),
376                                                         P_("Font scaling factor"),
377                                                         0.0,
378                                                         G_MAXDOUBLE,
379                                                         1.0,
380                                                         GTK_PARAM_READWRITE));
381   
382   g_object_class_install_property (object_class,
383                                    PROP_RISE,
384                                    g_param_spec_int ("rise",
385                                                      P_("Rise"),
386                                                      P_("Offset of text above the baseline "
387                                                         "(below the baseline if rise is negative)"),
388                                                      -G_MAXINT,
389                                                      G_MAXINT,
390                                                      0,
391                                                      GTK_PARAM_READWRITE));
392
393
394   g_object_class_install_property (object_class,
395                                    PROP_STRIKETHROUGH,
396                                    g_param_spec_boolean ("strikethrough",
397                                                          P_("Strikethrough"),
398                                                          P_("Whether to strike through the text"),
399                                                          FALSE,
400                                                          GTK_PARAM_READWRITE));
401   
402   g_object_class_install_property (object_class,
403                                    PROP_UNDERLINE,
404                                    g_param_spec_enum ("underline",
405                                                       P_("Underline"),
406                                                       P_("Style of underline for this text"),
407                                                       PANGO_TYPE_UNDERLINE,
408                                                       PANGO_UNDERLINE_NONE,
409                                                       GTK_PARAM_READWRITE));
410
411   g_object_class_install_property (object_class,
412                                    PROP_LANGUAGE,
413                                    g_param_spec_string ("language",
414                                                         P_("Language"),
415                                                         P_("The language this text is in, as an ISO code. "
416                                                            "Pango can use this as a hint when rendering the text. "
417                                                            "If you don't understand this parameter, you probably don't need it"),
418                                                         NULL,
419                                                         GTK_PARAM_READWRITE));
420
421
422   /**
423    * GtkCellRendererText:ellipsize:
424    *
425    * Specifies the preferred place to ellipsize the string, if the cell renderer 
426    * does not have enough room to display the entire string. Setting it to 
427    * %PANGO_ELLIPSIZE_NONE turns off ellipsizing. See the wrap-width property
428    * for another way of making the text fit into a given width.
429    *
430    * Since: 2.6
431    */
432   g_object_class_install_property (object_class,
433                                    PROP_ELLIPSIZE,
434                                    g_param_spec_enum ("ellipsize",
435                                                       P_("Ellipsize"),
436                                                       P_("The preferred place to ellipsize the string, "
437                                                          "if the cell renderer does not have enough room "
438                                                          "to display the entire string, if at all"),
439                                                       PANGO_TYPE_ELLIPSIZE_MODE,
440                                                       PANGO_ELLIPSIZE_NONE,
441                                                       GTK_PARAM_READWRITE));
442
443   /**
444    * GtkCellRendererText:width-chars:
445    * 
446    * The desired width of the cell, in characters. If this property is set to
447    * -1, the width will be calculated automatically, otherwise the cell will
448    * request either 3 characters or the property value, whichever is greater.
449    * 
450    * Since: 2.6
451    **/
452   g_object_class_install_property (object_class,
453                                    PROP_WIDTH_CHARS,
454                                    g_param_spec_int ("width-chars",
455                                                      P_("Width In Characters"),
456                                                      P_("The desired width of the label, in characters"),
457                                                      -1,
458                                                      G_MAXINT,
459                                                      -1,
460                                                      GTK_PARAM_READWRITE));
461   
462   /**
463    * GtkCellRendererText:wrap-mode:
464    *
465    * Specifies how to break the string into multiple lines, if the cell 
466    * renderer does not have enough room to display the entire string. 
467    * This property has no effect unless the wrap-width property is set.
468    *
469    * Since: 2.8
470    */
471   g_object_class_install_property (object_class,
472                                    PROP_WRAP_MODE,
473                                    g_param_spec_enum ("wrap-mode",
474                                                       P_("Wrap mode"),
475                                                       P_("How to break the string into multiple lines, "
476                                                          "if the cell renderer does not have enough room "
477                                                          "to display the entire string"),
478                                                       PANGO_TYPE_WRAP_MODE,
479                                                       PANGO_WRAP_CHAR,
480                                                       GTK_PARAM_READWRITE));
481
482   /**
483    * GtkCellRendererText:wrap-width:
484    *
485    * Specifies the width at which the text is wrapped. The wrap-mode property can 
486    * be used to influence at what character positions the line breaks can be placed.
487    * Setting wrap-width to -1 turns wrapping off.
488    *
489    * Since: 2.8
490    */
491   g_object_class_install_property (object_class,
492                                    PROP_WRAP_WIDTH,
493                                    g_param_spec_int ("wrap-width",
494                                                      P_("Wrap width"),
495                                                      P_("The width at which the text is wrapped"),
496                                                      -1,
497                                                      G_MAXINT,
498                                                      -1,
499                                                      GTK_PARAM_READWRITE));
500
501   
502   /* Style props are set or not */
503
504 #define ADD_SET_PROP(propname, propval, nick, blurb) g_object_class_install_property (object_class, propval, g_param_spec_boolean (propname, nick, blurb, FALSE, GTK_PARAM_READWRITE))
505
506   ADD_SET_PROP ("background-set", PROP_BACKGROUND_SET,
507                 P_("Background set"),
508                 P_("Whether this tag affects the background color"));
509
510   ADD_SET_PROP ("foreground-set", PROP_FOREGROUND_SET,
511                 P_("Foreground set"),
512                 P_("Whether this tag affects the foreground color"));
513   
514   ADD_SET_PROP ("editable-set", PROP_EDITABLE_SET,
515                 P_("Editability set"),
516                 P_("Whether this tag affects text editability"));
517
518   ADD_SET_PROP ("family-set", PROP_FAMILY_SET,
519                 P_("Font family set"),
520                 P_("Whether this tag affects the font family"));  
521
522   ADD_SET_PROP ("style-set", PROP_STYLE_SET,
523                 P_("Font style set"),
524                 P_("Whether this tag affects the font style"));
525
526   ADD_SET_PROP ("variant-set", PROP_VARIANT_SET,
527                 P_("Font variant set"),
528                 P_("Whether this tag affects the font variant"));
529
530   ADD_SET_PROP ("weight-set", PROP_WEIGHT_SET,
531                 P_("Font weight set"),
532                 P_("Whether this tag affects the font weight"));
533
534   ADD_SET_PROP ("stretch-set", PROP_STRETCH_SET,
535                 P_("Font stretch set"),
536                 P_("Whether this tag affects the font stretch"));
537
538   ADD_SET_PROP ("size-set", PROP_SIZE_SET,
539                 P_("Font size set"),
540                 P_("Whether this tag affects the font size"));
541
542   ADD_SET_PROP ("scale-set", PROP_SCALE_SET,
543                 P_("Font scale set"),
544                 P_("Whether this tag scales the font size by a factor"));
545   
546   ADD_SET_PROP ("rise-set", PROP_RISE_SET,
547                 P_("Rise set"),
548                 P_("Whether this tag affects the rise"));
549
550   ADD_SET_PROP ("strikethrough-set", PROP_STRIKETHROUGH_SET,
551                 P_("Strikethrough set"),
552                 P_("Whether this tag affects strikethrough"));
553
554   ADD_SET_PROP ("underline-set", PROP_UNDERLINE_SET,
555                 P_("Underline set"),
556                 P_("Whether this tag affects underlining"));
557
558   ADD_SET_PROP ("language-set", PROP_LANGUAGE_SET,
559                 P_("Language set"),
560                 P_("Whether this tag affects the language the text is rendered as"));
561
562   ADD_SET_PROP ("ellipsize-set", PROP_ELLIPSIZE_SET,
563                 P_("Ellipsize set"),
564                 P_("Whether this tag affects the ellipsize mode"));
565
566   text_cell_renderer_signals [EDITED] =
567     g_signal_new (I_("edited"),
568                   G_OBJECT_CLASS_TYPE (object_class),
569                   G_SIGNAL_RUN_LAST,
570                   G_STRUCT_OFFSET (GtkCellRendererTextClass, edited),
571                   NULL, NULL,
572                   _gtk_marshal_VOID__STRING_STRING,
573                   G_TYPE_NONE, 2,
574                   G_TYPE_STRING,
575                   G_TYPE_STRING);
576
577   g_type_class_add_private (object_class, sizeof (GtkCellRendererTextPrivate));
578 }
579
580 static void
581 gtk_cell_renderer_text_finalize (GObject *object)
582 {
583   GtkCellRendererText *celltext = GTK_CELL_RENDERER_TEXT (object);
584   GtkCellRendererTextPrivate *priv;
585
586   priv = GTK_CELL_RENDERER_TEXT_GET_PRIVATE (object);
587
588   pango_font_description_free (celltext->font);
589
590   if (celltext->text)
591     g_free (celltext->text);
592
593   if (celltext->extra_attrs)
594     pango_attr_list_unref (celltext->extra_attrs);
595
596   if (priv->language)
597     g_object_unref (priv->language);
598
599   (* G_OBJECT_CLASS (parent_class)->finalize) (object);
600 }
601
602 static PangoFontMask
603 get_property_font_set_mask (guint prop_id)
604 {
605   switch (prop_id)
606     {
607     case PROP_FAMILY_SET:
608       return PANGO_FONT_MASK_FAMILY;
609     case PROP_STYLE_SET:
610       return PANGO_FONT_MASK_STYLE;
611     case PROP_VARIANT_SET:
612       return PANGO_FONT_MASK_VARIANT;
613     case PROP_WEIGHT_SET:
614       return PANGO_FONT_MASK_WEIGHT;
615     case PROP_STRETCH_SET:
616       return PANGO_FONT_MASK_STRETCH;
617     case PROP_SIZE_SET:
618       return PANGO_FONT_MASK_SIZE;
619     }
620
621   return 0;
622 }
623
624 static void
625 gtk_cell_renderer_text_get_property (GObject        *object,
626                                      guint           param_id,
627                                      GValue         *value,
628                                      GParamSpec     *pspec)
629 {
630   GtkCellRendererText *celltext = GTK_CELL_RENDERER_TEXT (object);
631   GtkCellRendererTextPrivate *priv;
632
633   priv = GTK_CELL_RENDERER_TEXT_GET_PRIVATE (object);
634
635   switch (param_id)
636     {
637     case PROP_TEXT:
638       g_value_set_string (value, celltext->text);
639       break;
640
641     case PROP_ATTRIBUTES:
642       g_value_set_boxed (value, celltext->extra_attrs);
643       break;
644
645     case PROP_SINGLE_PARAGRAPH_MODE:
646       g_value_set_boolean (value, priv->single_paragraph);
647       break;
648
649     case PROP_BACKGROUND_GDK:
650       {
651         GdkColor color;
652         
653         color.red = celltext->background.red;
654         color.green = celltext->background.green;
655         color.blue = celltext->background.blue;
656         
657         g_value_set_boxed (value, &color);
658       }
659       break;
660
661     case PROP_FOREGROUND_GDK:
662       {
663         GdkColor color;
664         
665         color.red = celltext->foreground.red;
666         color.green = celltext->foreground.green;
667         color.blue = celltext->foreground.blue;
668         
669         g_value_set_boxed (value, &color);
670       }
671       break;
672
673     case PROP_FONT:
674       {
675         /* FIXME GValue imposes a totally gratuitous string copy
676          * here, we could just hand off string ownership
677          */
678         gchar *str = pango_font_description_to_string (celltext->font);
679         g_value_set_string (value, str);
680         g_free (str);
681       }
682       break;
683       
684     case PROP_FONT_DESC:
685       g_value_set_boxed (value, celltext->font);
686       break;
687
688     case PROP_FAMILY:
689       g_value_set_string (value, pango_font_description_get_family (celltext->font));
690       break;
691
692     case PROP_STYLE:
693       g_value_set_enum (value, pango_font_description_get_style (celltext->font));
694       break;
695
696     case PROP_VARIANT:
697       g_value_set_enum (value, pango_font_description_get_variant (celltext->font));
698       break;
699
700     case PROP_WEIGHT:
701       g_value_set_int (value, pango_font_description_get_weight (celltext->font));
702       break;
703
704     case PROP_STRETCH:
705       g_value_set_enum (value, pango_font_description_get_stretch (celltext->font));
706       break;
707
708     case PROP_SIZE:
709       g_value_set_int (value, pango_font_description_get_size (celltext->font));
710       break;
711
712     case PROP_SIZE_POINTS:
713       g_value_set_double (value, ((double)pango_font_description_get_size (celltext->font)) / (double)PANGO_SCALE);
714       break;
715
716     case PROP_SCALE:
717       g_value_set_double (value, celltext->font_scale);
718       break;
719       
720     case PROP_EDITABLE:
721       g_value_set_boolean (value, celltext->editable);
722       break;
723
724     case PROP_STRIKETHROUGH:
725       g_value_set_boolean (value, celltext->strikethrough);
726       break;
727
728     case PROP_UNDERLINE:
729       g_value_set_enum (value, celltext->underline_style);
730       break;
731
732     case PROP_RISE:
733       g_value_set_int (value, celltext->rise);
734       break;  
735
736     case PROP_LANGUAGE:
737       g_value_set_string (value, pango_language_to_string (priv->language));
738       break;
739
740     case PROP_ELLIPSIZE:
741       g_value_set_enum (value, priv->ellipsize);
742       break;
743       
744     case PROP_WRAP_MODE:
745       g_value_set_enum (value, priv->wrap_mode);
746       break;
747
748     case PROP_WRAP_WIDTH:
749       g_value_set_int (value, priv->wrap_width);
750       break;
751       
752     case PROP_BACKGROUND_SET:
753       g_value_set_boolean (value, celltext->background_set);
754       break;
755
756     case PROP_FOREGROUND_SET:
757       g_value_set_boolean (value, celltext->foreground_set);
758       break;
759
760     case PROP_FAMILY_SET:
761     case PROP_STYLE_SET:
762     case PROP_VARIANT_SET:
763     case PROP_WEIGHT_SET:
764     case PROP_STRETCH_SET:
765     case PROP_SIZE_SET:
766       {
767         PangoFontMask mask = get_property_font_set_mask (param_id);
768         g_value_set_boolean (value, (pango_font_description_get_set_fields (celltext->font) & mask) != 0);
769         
770         break;
771       }
772
773     case PROP_SCALE_SET:
774       g_value_set_boolean (value, celltext->scale_set);
775       break;
776       
777     case PROP_EDITABLE_SET:
778       g_value_set_boolean (value, celltext->editable_set);
779       break;
780
781     case PROP_STRIKETHROUGH_SET:
782       g_value_set_boolean (value, celltext->strikethrough_set);
783       break;
784
785     case PROP_UNDERLINE_SET:
786       g_value_set_boolean (value, celltext->underline_set);
787       break;
788
789     case  PROP_RISE_SET:
790       g_value_set_boolean (value, celltext->rise_set);
791       break;
792
793     case PROP_LANGUAGE_SET:
794       g_value_set_boolean (value, priv->language_set);
795       break;
796
797     case PROP_ELLIPSIZE_SET:
798       g_value_set_boolean (value, priv->ellipsize_set);
799       break;
800       
801     case PROP_WIDTH_CHARS:
802       g_value_set_int (value, priv->width_chars);
803       break;  
804
805     case PROP_BACKGROUND:
806     case PROP_FOREGROUND:
807     case PROP_MARKUP:
808     default:
809       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
810       break;
811     }
812 }
813
814
815 static void
816 set_bg_color (GtkCellRendererText *celltext,
817               GdkColor            *color)
818 {
819   if (color)
820     {
821       if (!celltext->background_set)
822         {
823           celltext->background_set = TRUE;
824           g_object_notify (G_OBJECT (celltext), "background-set");
825         }
826       
827       celltext->background.red = color->red;
828       celltext->background.green = color->green;
829       celltext->background.blue = color->blue;
830     }
831   else
832     {
833       if (celltext->background_set)
834         {
835           celltext->background_set = FALSE;
836           g_object_notify (G_OBJECT (celltext), "background-set");
837         }
838     }
839 }
840
841
842 static void
843 set_fg_color (GtkCellRendererText *celltext,
844               GdkColor            *color)
845 {
846   if (color)
847     {
848       if (!celltext->foreground_set)
849         {
850           celltext->foreground_set = TRUE;
851           g_object_notify (G_OBJECT (celltext), "foreground-set");
852         }
853       
854       celltext->foreground.red = color->red;
855       celltext->foreground.green = color->green;
856       celltext->foreground.blue = color->blue;
857     }
858   else
859     {
860       if (celltext->foreground_set)
861         {
862           celltext->foreground_set = FALSE;
863           g_object_notify (G_OBJECT (celltext), "foreground-set");
864         }
865     }
866 }
867
868 static PangoFontMask
869 set_font_desc_fields (PangoFontDescription *desc,
870                       PangoFontMask         to_set)
871 {
872   PangoFontMask changed_mask = 0;
873   
874   if (to_set & PANGO_FONT_MASK_FAMILY)
875     {
876       const char *family = pango_font_description_get_family (desc);
877       if (!family)
878         {
879           family = "sans";
880           changed_mask |= PANGO_FONT_MASK_FAMILY;
881         }
882
883       pango_font_description_set_family (desc, family);
884     }
885   if (to_set & PANGO_FONT_MASK_STYLE)
886     pango_font_description_set_style (desc, pango_font_description_get_style (desc));
887   if (to_set & PANGO_FONT_MASK_VARIANT)
888     pango_font_description_set_variant (desc, pango_font_description_get_variant (desc));
889   if (to_set & PANGO_FONT_MASK_WEIGHT)
890     pango_font_description_set_weight (desc, pango_font_description_get_weight (desc));
891   if (to_set & PANGO_FONT_MASK_STRETCH)
892     pango_font_description_set_stretch (desc, pango_font_description_get_stretch (desc));
893   if (to_set & PANGO_FONT_MASK_SIZE)
894     {
895       gint size = pango_font_description_get_size (desc);
896       if (size <= 0)
897         {
898           size = 10 * PANGO_SCALE;
899           changed_mask |= PANGO_FONT_MASK_SIZE;
900         }
901       
902       pango_font_description_set_size (desc, size);
903     }
904
905   return changed_mask;
906 }
907
908 static void
909 notify_set_changed (GObject       *object,
910                     PangoFontMask  changed_mask)
911 {
912   if (changed_mask & PANGO_FONT_MASK_FAMILY)
913     g_object_notify (object, "family-set");
914   if (changed_mask & PANGO_FONT_MASK_STYLE)
915     g_object_notify (object, "style-set");
916   if (changed_mask & PANGO_FONT_MASK_VARIANT)
917     g_object_notify (object, "variant-set");
918   if (changed_mask & PANGO_FONT_MASK_WEIGHT)
919     g_object_notify (object, "weight-set");
920   if (changed_mask & PANGO_FONT_MASK_STRETCH)
921     g_object_notify (object, "stretch-set");
922   if (changed_mask & PANGO_FONT_MASK_SIZE)
923     g_object_notify (object, "size-set");
924 }
925
926 static void
927 notify_fields_changed (GObject       *object,
928                        PangoFontMask  changed_mask)
929 {
930   if (changed_mask & PANGO_FONT_MASK_FAMILY)
931     g_object_notify (object, "family");
932   if (changed_mask & PANGO_FONT_MASK_STYLE)
933     g_object_notify (object, "style");
934   if (changed_mask & PANGO_FONT_MASK_VARIANT)
935     g_object_notify (object, "variant");
936   if (changed_mask & PANGO_FONT_MASK_WEIGHT)
937     g_object_notify (object, "weight");
938   if (changed_mask & PANGO_FONT_MASK_STRETCH)
939     g_object_notify (object, "stretch");
940   if (changed_mask & PANGO_FONT_MASK_SIZE)
941     g_object_notify (object, "size");
942 }
943
944 static void
945 set_font_description (GtkCellRendererText  *celltext,
946                       PangoFontDescription *font_desc)
947 {
948   GObject *object = G_OBJECT (celltext);
949   PangoFontDescription *new_font_desc;
950   PangoFontMask old_mask, new_mask, changed_mask, set_changed_mask;
951   
952   if (font_desc)
953     new_font_desc = pango_font_description_copy (font_desc);
954   else
955     new_font_desc = pango_font_description_new ();
956
957   old_mask = pango_font_description_get_set_fields (celltext->font);
958   new_mask = pango_font_description_get_set_fields (new_font_desc);
959
960   changed_mask = old_mask | new_mask;
961   set_changed_mask = old_mask ^ new_mask;
962
963   pango_font_description_free (celltext->font);
964   celltext->font = new_font_desc;
965   
966   g_object_freeze_notify (object);
967
968   g_object_notify (object, "font-desc");
969   g_object_notify (object, "font");
970   
971   if (changed_mask & PANGO_FONT_MASK_FAMILY)
972     g_object_notify (object, "family");
973   if (changed_mask & PANGO_FONT_MASK_STYLE)
974     g_object_notify (object, "style");
975   if (changed_mask & PANGO_FONT_MASK_VARIANT)
976     g_object_notify (object, "variant");
977   if (changed_mask & PANGO_FONT_MASK_WEIGHT)
978     g_object_notify (object, "weight");
979   if (changed_mask & PANGO_FONT_MASK_STRETCH)
980     g_object_notify (object, "stretch");
981   if (changed_mask & PANGO_FONT_MASK_SIZE)
982     {
983       g_object_notify (object, "size");
984       g_object_notify (object, "size-points");
985     }
986
987   notify_set_changed (object, set_changed_mask);
988   
989   g_object_thaw_notify (object);
990 }
991
992 static void
993 gtk_cell_renderer_text_set_property (GObject      *object,
994                                      guint         param_id,
995                                      const GValue *value,
996                                      GParamSpec   *pspec)
997 {
998   GtkCellRendererText *celltext = GTK_CELL_RENDERER_TEXT (object);
999   GtkCellRendererTextPrivate *priv;
1000
1001   priv = GTK_CELL_RENDERER_TEXT_GET_PRIVATE (object);
1002
1003   switch (param_id)
1004     {
1005     case PROP_TEXT:
1006       if (celltext->text)
1007         g_free (celltext->text);
1008
1009       if (priv->markup_set)
1010         {
1011           if (celltext->extra_attrs)
1012             pango_attr_list_unref (celltext->extra_attrs);
1013           celltext->extra_attrs = NULL;
1014           priv->markup_set = FALSE;
1015         }
1016
1017       celltext->text = g_strdup (g_value_get_string (value));
1018       g_object_notify (object, "text");
1019       break;
1020
1021     case PROP_ATTRIBUTES:
1022       if (celltext->extra_attrs)
1023         pango_attr_list_unref (celltext->extra_attrs);
1024
1025       celltext->extra_attrs = g_value_get_boxed (value);
1026       if (celltext->extra_attrs)
1027         pango_attr_list_ref (celltext->extra_attrs);
1028       break;
1029     case PROP_MARKUP:
1030       {
1031         const gchar *str;
1032         gchar *text = NULL;
1033         GError *error = NULL;
1034         PangoAttrList *attrs = NULL;
1035
1036         str = g_value_get_string (value);
1037         if (str && !pango_parse_markup (str,
1038                                         -1,
1039                                         0,
1040                                         &attrs,
1041                                         &text,
1042                                         NULL,
1043                                         &error))
1044           {
1045             g_warning ("Failed to set cell text from markup due to error parsing markup: %s",
1046                        error->message);
1047             g_error_free (error);
1048             return;
1049           }
1050
1051         if (celltext->text)
1052           g_free (celltext->text);
1053
1054         if (celltext->extra_attrs)
1055           pango_attr_list_unref (celltext->extra_attrs);
1056
1057         celltext->text = text;
1058         celltext->extra_attrs = attrs;
1059         priv->markup_set = TRUE;
1060       }
1061       break;
1062
1063     case PROP_SINGLE_PARAGRAPH_MODE:
1064       priv->single_paragraph = g_value_get_boolean (value);
1065       break;
1066       
1067     case PROP_BACKGROUND:
1068       {
1069         GdkColor color;
1070
1071         if (!g_value_get_string (value))
1072           set_bg_color (celltext, NULL);       /* reset to backgrounmd_set to FALSE */
1073         else if (gdk_color_parse (g_value_get_string (value), &color))
1074           set_bg_color (celltext, &color);
1075         else
1076           g_warning ("Don't know color `%s'", g_value_get_string (value));
1077
1078         g_object_notify (object, "background-gdk");
1079       }
1080       break;
1081       
1082     case PROP_FOREGROUND:
1083       {
1084         GdkColor color;
1085
1086         if (!g_value_get_string (value))
1087           set_fg_color (celltext, NULL);       /* reset to foreground_set to FALSE */
1088         else if (gdk_color_parse (g_value_get_string (value), &color))
1089           set_fg_color (celltext, &color);
1090         else
1091           g_warning ("Don't know color `%s'", g_value_get_string (value));
1092
1093         g_object_notify (object, "foreground-gdk");
1094       }
1095       break;
1096
1097     case PROP_BACKGROUND_GDK:
1098       /* This notifies the GObject itself. */
1099       set_bg_color (celltext, g_value_get_boxed (value));
1100       break;
1101
1102     case PROP_FOREGROUND_GDK:
1103       /* This notifies the GObject itself. */
1104       set_fg_color (celltext, g_value_get_boxed (value));
1105       break;
1106
1107     case PROP_FONT:
1108       {
1109         PangoFontDescription *font_desc = NULL;
1110         const gchar *name;
1111
1112         name = g_value_get_string (value);
1113
1114         if (name)
1115           font_desc = pango_font_description_from_string (name);
1116
1117         set_font_description (celltext, font_desc);
1118
1119         pango_font_description_free (font_desc);
1120         
1121         if (celltext->fixed_height_rows != -1)
1122           celltext->calc_fixed_height = TRUE;
1123       }
1124       break;
1125
1126     case PROP_FONT_DESC:
1127       set_font_description (celltext, g_value_get_boxed (value));
1128       
1129       if (celltext->fixed_height_rows != -1)
1130         celltext->calc_fixed_height = TRUE;
1131       break;
1132
1133     case PROP_FAMILY:
1134     case PROP_STYLE:
1135     case PROP_VARIANT:
1136     case PROP_WEIGHT:
1137     case PROP_STRETCH:
1138     case PROP_SIZE:
1139     case PROP_SIZE_POINTS:
1140       {
1141         PangoFontMask old_set_mask = pango_font_description_get_set_fields (celltext->font);
1142         
1143         switch (param_id)
1144           {
1145           case PROP_FAMILY:
1146             pango_font_description_set_family (celltext->font,
1147                                                g_value_get_string (value));
1148             break;
1149           case PROP_STYLE:
1150             pango_font_description_set_style (celltext->font,
1151                                               g_value_get_enum (value));
1152             break;
1153           case PROP_VARIANT:
1154             pango_font_description_set_variant (celltext->font,
1155                                                 g_value_get_enum (value));
1156             break;
1157           case PROP_WEIGHT:
1158             pango_font_description_set_weight (celltext->font,
1159                                                g_value_get_int (value));
1160             break;
1161           case PROP_STRETCH:
1162             pango_font_description_set_stretch (celltext->font,
1163                                                 g_value_get_enum (value));
1164             break;
1165           case PROP_SIZE:
1166             pango_font_description_set_size (celltext->font,
1167                                              g_value_get_int (value));
1168             g_object_notify (object, "size-points");
1169             break;
1170           case PROP_SIZE_POINTS:
1171             pango_font_description_set_size (celltext->font,
1172                                              g_value_get_double (value) * PANGO_SCALE);
1173             g_object_notify (object, "size");
1174             break;
1175           }
1176         
1177         if (celltext->fixed_height_rows != -1)
1178           celltext->calc_fixed_height = TRUE;
1179         
1180         notify_set_changed (object, old_set_mask & pango_font_description_get_set_fields (celltext->font));
1181         g_object_notify (object, "font-desc");
1182         g_object_notify (object, "font");
1183
1184         break;
1185       }
1186       
1187     case PROP_SCALE:
1188       celltext->font_scale = g_value_get_double (value);
1189       celltext->scale_set = TRUE;
1190       if (celltext->fixed_height_rows != -1)
1191         celltext->calc_fixed_height = TRUE;
1192       g_object_notify (object, "scale-set");
1193       break;
1194       
1195     case PROP_EDITABLE:
1196       celltext->editable = g_value_get_boolean (value);
1197       celltext->editable_set = TRUE;
1198       if (celltext->editable)
1199         GTK_CELL_RENDERER (celltext)->mode = GTK_CELL_RENDERER_MODE_EDITABLE;
1200       else
1201         GTK_CELL_RENDERER (celltext)->mode = GTK_CELL_RENDERER_MODE_INERT;
1202       g_object_notify (object, "editable-set");
1203       break;
1204
1205     case PROP_STRIKETHROUGH:
1206       celltext->strikethrough = g_value_get_boolean (value);
1207       celltext->strikethrough_set = TRUE;
1208       g_object_notify (object, "strikethrough-set");
1209       break;
1210
1211     case PROP_UNDERLINE:
1212       celltext->underline_style = g_value_get_enum (value);
1213       celltext->underline_set = TRUE;
1214       g_object_notify (object, "underline-set");
1215             
1216       break;
1217
1218     case PROP_RISE:
1219       celltext->rise = g_value_get_int (value);
1220       celltext->rise_set = TRUE;
1221       g_object_notify (object, "rise-set");
1222       if (celltext->fixed_height_rows != -1)
1223         celltext->calc_fixed_height = TRUE;
1224       break;  
1225
1226     case PROP_LANGUAGE:
1227       priv->language_set = TRUE;
1228       if (priv->language)
1229         g_object_unref (priv->language);
1230       priv->language = pango_language_from_string (g_value_get_string (value));
1231       g_object_notify (object, "language-set");
1232       break;
1233
1234     case PROP_ELLIPSIZE:
1235       priv->ellipsize = g_value_get_enum (value);
1236       priv->ellipsize_set = TRUE;
1237       g_object_notify (object, "ellipsize-set");
1238       break;
1239       
1240     case PROP_WRAP_MODE:
1241       priv->wrap_mode = g_value_get_enum (value);
1242       break;
1243       
1244     case PROP_WRAP_WIDTH:
1245       priv->wrap_width = g_value_get_int (value);
1246       break;
1247             
1248     case PROP_WIDTH_CHARS:
1249       priv->width_chars = g_value_get_int (value);
1250       break;  
1251
1252     case PROP_BACKGROUND_SET:
1253       celltext->background_set = g_value_get_boolean (value);
1254       break;
1255
1256     case PROP_FOREGROUND_SET:
1257       celltext->foreground_set = g_value_get_boolean (value);
1258       break;
1259
1260     case PROP_FAMILY_SET:
1261     case PROP_STYLE_SET:
1262     case PROP_VARIANT_SET:
1263     case PROP_WEIGHT_SET:
1264     case PROP_STRETCH_SET:
1265     case PROP_SIZE_SET:
1266       if (!g_value_get_boolean (value))
1267         {
1268           pango_font_description_unset_fields (celltext->font,
1269                                                get_property_font_set_mask (param_id));
1270         }
1271       else
1272         {
1273           PangoFontMask changed_mask;
1274           
1275           changed_mask = set_font_desc_fields (celltext->font,
1276                                                get_property_font_set_mask (param_id));
1277           notify_fields_changed (G_OBJECT (celltext), changed_mask);
1278         }
1279       break;
1280
1281     case PROP_SCALE_SET:
1282       celltext->scale_set = g_value_get_boolean (value);
1283       break;
1284       
1285     case PROP_EDITABLE_SET:
1286       celltext->editable_set = g_value_get_boolean (value);
1287       break;
1288
1289     case PROP_STRIKETHROUGH_SET:
1290       celltext->strikethrough_set = g_value_get_boolean (value);
1291       break;
1292
1293     case PROP_UNDERLINE_SET:
1294       celltext->underline_set = g_value_get_boolean (value);
1295       break;
1296
1297     case PROP_RISE_SET:
1298       celltext->rise_set = g_value_get_boolean (value);
1299       break;
1300
1301     case PROP_LANGUAGE_SET:
1302       priv->language_set = g_value_get_boolean (value);
1303       break;
1304
1305     case PROP_ELLIPSIZE_SET:
1306       priv->ellipsize_set = g_value_get_boolean (value);
1307       break;
1308       
1309     default:
1310       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
1311       break;
1312     }
1313 }
1314
1315 /**
1316  * gtk_cell_renderer_text_new:
1317  * 
1318  * Creates a new #GtkCellRendererText. Adjust how text is drawn using
1319  * object properties. Object properties can be
1320  * set globally (with g_object_set()). Also, with #GtkTreeViewColumn,
1321  * you can bind a property to a value in a #GtkTreeModel. For example,
1322  * you can bind the "text" property on the cell renderer to a string
1323  * value in the model, thus rendering a different string in each row
1324  * of the #GtkTreeView
1325  * 
1326  * Return value: the new cell renderer
1327  **/
1328 GtkCellRenderer *
1329 gtk_cell_renderer_text_new (void)
1330 {
1331   return g_object_new (GTK_TYPE_CELL_RENDERER_TEXT, NULL);
1332 }
1333
1334 static void
1335 add_attr (PangoAttrList  *attr_list,
1336           PangoAttribute *attr)
1337 {
1338   attr->start_index = 0;
1339   attr->end_index = G_MAXINT;
1340   
1341   pango_attr_list_insert (attr_list, attr);
1342 }
1343
1344 static PangoLayout*
1345 get_layout (GtkCellRendererText *celltext,
1346             GtkWidget           *widget,
1347             gboolean             will_render,
1348             GtkCellRendererState flags)
1349 {
1350   PangoAttrList *attr_list;
1351   PangoLayout *layout;
1352   PangoUnderline uline;
1353   GtkCellRendererTextPrivate *priv;
1354
1355   priv = GTK_CELL_RENDERER_TEXT_GET_PRIVATE (celltext);
1356   
1357   layout = gtk_widget_create_pango_layout (widget, celltext->text);
1358
1359   if (celltext->extra_attrs)
1360     attr_list = pango_attr_list_copy (celltext->extra_attrs);
1361   else
1362     attr_list = pango_attr_list_new ();
1363
1364   pango_layout_set_single_paragraph_mode (layout, priv->single_paragraph);
1365
1366   if (will_render)
1367     {
1368       /* Add options that affect appearance but not size */
1369       
1370       /* note that background doesn't go here, since it affects
1371        * background_area not the PangoLayout area
1372        */
1373       
1374       if (celltext->foreground_set
1375           && (flags & GTK_CELL_RENDERER_SELECTED) == 0)
1376         {
1377           PangoColor color;
1378
1379           color = celltext->foreground;
1380           
1381           add_attr (attr_list,
1382                     pango_attr_foreground_new (color.red, color.green, color.blue));
1383         }
1384
1385       if (celltext->strikethrough_set)
1386         add_attr (attr_list,
1387                   pango_attr_strikethrough_new (celltext->strikethrough));
1388     }
1389
1390   add_attr (attr_list, pango_attr_font_desc_new (celltext->font));
1391
1392   if (celltext->scale_set &&
1393       celltext->font_scale != 1.0)
1394     add_attr (attr_list, pango_attr_scale_new (celltext->font_scale));
1395   
1396   if (celltext->underline_set)
1397     uline = celltext->underline_style;
1398   else
1399     uline = PANGO_UNDERLINE_NONE;
1400
1401   if (priv->language_set)
1402     add_attr (attr_list, pango_attr_language_new (priv->language));
1403   
1404   if ((flags & GTK_CELL_RENDERER_PRELIT) == GTK_CELL_RENDERER_PRELIT)
1405     {
1406       switch (uline)
1407         {
1408         case PANGO_UNDERLINE_NONE:
1409           uline = PANGO_UNDERLINE_SINGLE;
1410           break;
1411
1412         case PANGO_UNDERLINE_SINGLE:
1413           uline = PANGO_UNDERLINE_DOUBLE;
1414           break;
1415
1416         default:
1417           break;
1418         }
1419     }
1420
1421   if (uline != PANGO_UNDERLINE_NONE)
1422     add_attr (attr_list, pango_attr_underline_new (celltext->underline_style));
1423
1424   if (celltext->rise_set)
1425     add_attr (attr_list, pango_attr_rise_new (celltext->rise));
1426
1427   if (priv->ellipsize_set)
1428     pango_layout_set_ellipsize (layout, priv->ellipsize);
1429   else
1430     pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_NONE);
1431
1432   if (priv->wrap_width != -1)
1433     {
1434       pango_layout_set_width (layout, priv->wrap_width * PANGO_SCALE);
1435       pango_layout_set_wrap (layout, priv->wrap_mode);
1436
1437       if (pango_layout_get_line_count (layout) == 1)
1438         {
1439           pango_layout_set_width (layout, -1);
1440           pango_layout_set_wrap (layout, PANGO_WRAP_CHAR);
1441         }
1442     }
1443   else
1444     {
1445       pango_layout_set_width (layout, -1);
1446       pango_layout_set_wrap (layout, PANGO_WRAP_CHAR);
1447     }
1448
1449   pango_layout_set_attributes (layout, attr_list);
1450
1451   pango_attr_list_unref (attr_list);
1452   
1453   return layout;
1454 }
1455
1456 static void
1457 get_size (GtkCellRenderer *cell,
1458           GtkWidget       *widget,
1459           GdkRectangle    *cell_area,
1460           PangoLayout     *layout,
1461           gint            *x_offset,
1462           gint            *y_offset,
1463           gint            *width,
1464           gint            *height)
1465 {
1466   GtkCellRendererText *celltext = (GtkCellRendererText *) cell;
1467   PangoRectangle rect;
1468   GtkCellRendererTextPrivate *priv;
1469
1470   priv = GTK_CELL_RENDERER_TEXT_GET_PRIVATE (cell);
1471
1472   if (celltext->calc_fixed_height)
1473     {
1474       PangoContext *context;
1475       PangoFontMetrics *metrics;
1476       PangoFontDescription *font_desc;
1477       gint row_height;
1478
1479       font_desc = pango_font_description_copy (widget->style->font_desc);
1480       pango_font_description_merge (font_desc, celltext->font, TRUE);
1481
1482       if (celltext->scale_set)
1483         pango_font_description_set_size (font_desc,
1484                                          celltext->font_scale * pango_font_description_get_size (font_desc));
1485
1486       context = gtk_widget_get_pango_context (widget);
1487
1488       metrics = pango_context_get_metrics (context,
1489                                            font_desc,
1490                                            pango_context_get_language (context));
1491       row_height = (pango_font_metrics_get_ascent (metrics) +
1492                     pango_font_metrics_get_descent (metrics));
1493       pango_font_metrics_unref (metrics);
1494
1495       pango_font_description_free (font_desc);
1496
1497       gtk_cell_renderer_set_fixed_size (cell,
1498                                         cell->width, 2*cell->ypad +
1499                                         celltext->fixed_height_rows * PANGO_PIXELS (row_height));
1500       
1501       if (height)
1502         {
1503           *height = cell->height;
1504           height = NULL;
1505         }
1506       celltext->calc_fixed_height = FALSE;
1507       if (width == NULL)
1508         return;
1509     }
1510   
1511   if (layout)
1512     g_object_ref (layout);
1513   else
1514     layout = get_layout (celltext, widget, FALSE, 0);
1515
1516   pango_layout_get_pixel_extents (layout, NULL, &rect);
1517
1518   if (height)
1519     *height = cell->ypad * 2 + rect.height;
1520
1521   /* The minimum size for ellipsized labels is ~ 3 chars */
1522   if (width)
1523     {
1524       if (priv->ellipsize || priv->width_chars > 0)
1525         {
1526           PangoContext *context;
1527           PangoFontMetrics *metrics;
1528           gint char_width;
1529
1530           context = pango_layout_get_context (layout);
1531           metrics = pango_context_get_metrics (context, widget->style->font_desc, pango_context_get_language (context));
1532
1533           char_width = pango_font_metrics_get_approximate_char_width (metrics);
1534           pango_font_metrics_unref (metrics);
1535           
1536           *width = cell->xpad * 2 + (PANGO_PIXELS (char_width) * MAX (priv->width_chars, 3));
1537         }
1538       else
1539         {
1540           *width = cell->xpad * 2 + rect.x + rect.width;
1541         }         
1542     }
1543
1544   if (cell_area)
1545     {
1546       if (x_offset)
1547         {
1548           if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
1549             *x_offset = (1.0 - cell->xalign) * (cell_area->width - (rect.x + rect.width + (2 * cell->xpad)));
1550           else 
1551             *x_offset = cell->xalign * (cell_area->width - (rect.x + rect.width + (2 * cell->xpad)));
1552
1553           if (priv->ellipsize_set || priv->wrap_width != -1)
1554             *x_offset = MAX(*x_offset, 0);
1555         }
1556       if (y_offset)
1557         {
1558           *y_offset = cell->yalign * (cell_area->height - (rect.height + (2 * cell->ypad)));
1559           *y_offset = MAX (*y_offset, 0);
1560         }
1561     }
1562
1563   g_object_unref (layout);
1564 }
1565
1566
1567 static void
1568 gtk_cell_renderer_text_get_size (GtkCellRenderer *cell,
1569                                  GtkWidget       *widget,
1570                                  GdkRectangle    *cell_area,
1571                                  gint            *x_offset,
1572                                  gint            *y_offset,
1573                                  gint            *width,
1574                                  gint            *height)
1575 {
1576   get_size (cell, widget, cell_area, NULL,
1577             x_offset, y_offset, width, height);
1578 }
1579
1580 static void
1581 gtk_cell_renderer_text_render (GtkCellRenderer      *cell,
1582                                GdkDrawable          *window,
1583                                GtkWidget            *widget,
1584                                GdkRectangle         *background_area,
1585                                GdkRectangle         *cell_area,
1586                                GdkRectangle         *expose_area,
1587                                GtkCellRendererState  flags)
1588
1589 {
1590   GtkCellRendererText *celltext = (GtkCellRendererText *) cell;
1591   PangoLayout *layout;
1592   GtkStateType state;
1593   gint x_offset;
1594   gint y_offset;
1595   GtkCellRendererTextPrivate *priv;
1596
1597   priv = GTK_CELL_RENDERER_TEXT_GET_PRIVATE (cell);
1598
1599   layout = get_layout (celltext, widget, TRUE, flags);
1600   get_size (cell, widget, cell_area, layout, &x_offset, &y_offset, NULL, NULL);
1601
1602   if (!cell->sensitive) 
1603     {
1604       state = GTK_STATE_INSENSITIVE;
1605     }
1606   else if ((flags & GTK_CELL_RENDERER_SELECTED) == GTK_CELL_RENDERER_SELECTED)
1607     {
1608       if (GTK_WIDGET_HAS_FOCUS (widget))
1609         state = GTK_STATE_SELECTED;
1610       else
1611         state = GTK_STATE_ACTIVE;
1612     }
1613   else if ((flags & GTK_CELL_RENDERER_PRELIT) == GTK_CELL_RENDERER_PRELIT &&
1614            GTK_WIDGET_STATE (widget) == GTK_STATE_PRELIGHT)
1615     {
1616       state = GTK_STATE_PRELIGHT;
1617     }
1618   else
1619     {
1620       if (GTK_WIDGET_STATE (widget) == GTK_STATE_INSENSITIVE)
1621         state = GTK_STATE_INSENSITIVE;
1622       else
1623         state = GTK_STATE_NORMAL;
1624     }
1625
1626   if (celltext->background_set && 
1627       (flags & GTK_CELL_RENDERER_SELECTED) == 0)
1628     {
1629       cairo_t *cr = gdk_cairo_create (window);
1630
1631       if (expose_area)
1632         {
1633           gdk_cairo_rectangle (cr, expose_area);
1634           cairo_clip (cr);
1635         }
1636
1637       gdk_cairo_rectangle (cr, background_area);
1638       cairo_set_source_rgb (cr,
1639                             celltext->background.red / 65535.,
1640                             celltext->background.green / 65535.,
1641                             celltext->background.blue / 65535.);
1642       cairo_fill (cr);
1643       
1644       cairo_destroy (cr);
1645     }
1646
1647   if (priv->ellipsize_set)
1648     pango_layout_set_width (layout, 
1649                             (cell_area->width - x_offset - 2 * cell->xpad) * PANGO_SCALE);
1650   else if (priv->wrap_width == -1)
1651     pango_layout_set_width (layout, -1);
1652
1653   gtk_paint_layout (widget->style,
1654                     window,
1655                     state,
1656                     TRUE,
1657                     expose_area,
1658                     widget,
1659                     "cellrenderertext",
1660                     cell_area->x + x_offset + cell->xpad,
1661                     cell_area->y + y_offset + cell->ypad,
1662                     layout);
1663
1664   g_object_unref (layout);
1665 }
1666
1667 static void
1668 gtk_cell_renderer_text_editing_done (GtkCellEditable *entry,
1669                                      gpointer         data)
1670 {
1671   const gchar *path;
1672   const gchar *new_text;
1673   GtkCellRendererTextPrivate *priv;
1674
1675   priv = GTK_CELL_RENDERER_TEXT_GET_PRIVATE (data);
1676
1677   priv->entry = NULL;
1678
1679   if (priv->focus_out_id > 0)
1680     {
1681       g_signal_handler_disconnect (entry, priv->focus_out_id);
1682       priv->focus_out_id = 0;
1683     }
1684
1685   if (priv->populate_popup_id > 0)
1686     {
1687       g_signal_handler_disconnect (entry, priv->populate_popup_id);
1688       priv->populate_popup_id = 0;
1689     }
1690
1691   if (priv->entry_menu_popdown_timeout)
1692     {
1693       g_source_remove (priv->entry_menu_popdown_timeout);
1694       priv->entry_menu_popdown_timeout = 0;
1695     }
1696
1697   gtk_cell_renderer_stop_editing (GTK_CELL_RENDERER (data), 
1698                                   GTK_ENTRY (entry)->editing_canceled);
1699   if (GTK_ENTRY (entry)->editing_canceled)
1700     return;
1701
1702   path = g_object_get_data (G_OBJECT (entry), GTK_CELL_RENDERER_TEXT_PATH);
1703   new_text = gtk_entry_get_text (GTK_ENTRY (entry));
1704
1705   g_signal_emit (data, text_cell_renderer_signals[EDITED], 0, path, new_text);
1706 }
1707
1708 static gboolean
1709 popdown_timeout (gpointer data)
1710 {
1711   GtkCellRendererTextPrivate *priv;
1712
1713   GDK_THREADS_ENTER ();
1714
1715   priv = GTK_CELL_RENDERER_TEXT_GET_PRIVATE (data);
1716
1717   priv->entry_menu_popdown_timeout = 0;
1718
1719   if (!GTK_WIDGET_HAS_FOCUS (priv->entry))
1720     gtk_cell_renderer_text_editing_done (GTK_CELL_EDITABLE (priv->entry), data);
1721
1722   GDK_THREADS_LEAVE ();
1723
1724   return FALSE;
1725 }
1726
1727 static void
1728 gtk_cell_renderer_text_popup_unmap (GtkMenu *menu,
1729                                     gpointer data)
1730 {
1731   GtkCellRendererTextPrivate *priv;
1732
1733   priv = GTK_CELL_RENDERER_TEXT_GET_PRIVATE (data);
1734
1735   priv->in_entry_menu = FALSE;
1736
1737   if (priv->entry_menu_popdown_timeout)
1738     return;
1739
1740   priv->entry_menu_popdown_timeout = g_timeout_add (500, popdown_timeout,
1741                                                     data);
1742 }
1743
1744 static void
1745 gtk_cell_renderer_text_populate_popup (GtkEntry *entry,
1746                                        GtkMenu  *menu,
1747                                        gpointer  data)
1748 {
1749   GtkCellRendererTextPrivate *priv;
1750
1751   priv = GTK_CELL_RENDERER_TEXT_GET_PRIVATE (data);
1752
1753   if (priv->entry_menu_popdown_timeout)
1754     {
1755       g_source_remove (priv->entry_menu_popdown_timeout);
1756       priv->entry_menu_popdown_timeout = 0;
1757     }
1758
1759   priv->in_entry_menu = TRUE;
1760
1761   g_signal_connect (menu, "unmap",
1762                     G_CALLBACK (gtk_cell_renderer_text_popup_unmap), data);
1763 }
1764
1765 static gboolean
1766 gtk_cell_renderer_text_focus_out_event (GtkWidget *entry,
1767                                         GdkEvent  *event,
1768                                         gpointer   data)
1769 {
1770   GtkCellRendererTextPrivate *priv;
1771
1772   priv = GTK_CELL_RENDERER_TEXT_GET_PRIVATE (data);
1773
1774   if (priv->in_entry_menu)
1775     return FALSE;
1776
1777   gtk_cell_renderer_text_editing_done (GTK_CELL_EDITABLE (entry), data);
1778
1779   /* entry needs focus-out-event */
1780   return FALSE;
1781 }
1782
1783 static GtkCellEditable *
1784 gtk_cell_renderer_text_start_editing (GtkCellRenderer      *cell,
1785                                       GdkEvent             *event,
1786                                       GtkWidget            *widget,
1787                                       const gchar          *path,
1788                                       GdkRectangle         *background_area,
1789                                       GdkRectangle         *cell_area,
1790                                       GtkCellRendererState  flags)
1791 {
1792   GtkCellRendererText *celltext;
1793   GtkCellRendererTextPrivate *priv;
1794
1795   celltext = GTK_CELL_RENDERER_TEXT (cell);
1796   priv = GTK_CELL_RENDERER_TEXT_GET_PRIVATE (cell);
1797
1798   /* If the cell isn't editable we return NULL. */
1799   if (celltext->editable == FALSE)
1800     return NULL;
1801
1802   priv->entry = g_object_new (GTK_TYPE_ENTRY,
1803                               "has-frame", FALSE,
1804                               "xalign", cell->xalign,
1805                               NULL);
1806
1807   if (celltext->text)
1808     gtk_entry_set_text (GTK_ENTRY (priv->entry), celltext->text);
1809   g_object_set_data_full (G_OBJECT (priv->entry), I_(GTK_CELL_RENDERER_TEXT_PATH), g_strdup (path), g_free);
1810   
1811   gtk_editable_select_region (GTK_EDITABLE (priv->entry), 0, -1);
1812   
1813
1814   priv->in_entry_menu = FALSE;
1815   if (priv->entry_menu_popdown_timeout)
1816     {
1817       g_source_remove (priv->entry_menu_popdown_timeout);
1818       priv->entry_menu_popdown_timeout = 0;
1819     }
1820
1821   g_signal_connect (priv->entry,
1822                     "editing_done",
1823                     G_CALLBACK (gtk_cell_renderer_text_editing_done),
1824                     celltext);
1825   priv->focus_out_id = g_signal_connect (priv->entry, "focus_out_event",
1826                          G_CALLBACK (gtk_cell_renderer_text_focus_out_event),
1827                          celltext);
1828   priv->populate_popup_id =
1829     g_signal_connect (priv->entry, "populate_popup",
1830                       G_CALLBACK (gtk_cell_renderer_text_populate_popup),
1831                       celltext);
1832  
1833   gtk_widget_show (priv->entry);
1834
1835   return GTK_CELL_EDITABLE (priv->entry);
1836 }
1837
1838 /**
1839  * gtk_cell_renderer_text_set_fixed_height_from_font:
1840  * @renderer: A #GtkCellRendererText
1841  * @number_of_rows: Number of rows of text each cell renderer is allocated, or -1
1842  * 
1843  * Sets the height of a renderer to explicitly be determined by the "font" and
1844  * "y_pad" property set on it.  Further changes in these properties do not
1845  * affect the height, so they must be accompanied by a subsequent call to this
1846  * function.  Using this function is unflexible, and should really only be used
1847  * if calculating the size of a cell is too slow (ie, a massive number of cells
1848  * displayed).  If @number_of_rows is -1, then the fixed height is unset, and
1849  * the height is determined by the properties again.
1850  **/
1851 void
1852 gtk_cell_renderer_text_set_fixed_height_from_font (GtkCellRendererText *renderer,
1853                                                    gint                 number_of_rows)
1854 {
1855   g_return_if_fail (GTK_IS_CELL_RENDERER_TEXT (renderer));
1856   g_return_if_fail (number_of_rows == -1 || number_of_rows > 0);
1857
1858   if (number_of_rows == -1)
1859     {
1860       gtk_cell_renderer_set_fixed_size (GTK_CELL_RENDERER (renderer),
1861                                         GTK_CELL_RENDERER (renderer)->width,
1862                                         -1);
1863     }
1864   else
1865     {
1866       renderer->fixed_height_rows = number_of_rows;
1867       renderer->calc_fixed_height = TRUE;
1868     }
1869 }
1870
1871 #define __GTK_CELL_RENDERER_TEXT_C__
1872 #include "gtkaliasdef.c"