]> Pileus Git - ~andy/gtk/blob - gtk/gtkcellrenderertext.c
docs: Move documentation to inline comments: GtkCellRendererText
[~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
22 #include "gtkcellrenderertext.h"
23
24 #include <stdlib.h>
25
26 #include "gtkeditable.h"
27 #include "gtkentry.h"
28 #include "gtksizerequest.h"
29 #include "gtkmarshalers.h"
30 #include "gtkintl.h"
31 #include "gtkprivate.h"
32 #include "gtktreeprivate.h"
33
34
35 /**
36  * SECTION:gtkcellrenderertext
37  * @Short_description: Renders text in a cell
38  * @Title: GtkCellRendererText
39  *
40  * A #GtkCellRendererText renders a given text in its cell, using the font, color and
41  * style information provided by its properties. The text will be ellipsized if it is
42  * too long and the #GtkCellRendererText:ellipsize property allows it.
43  *
44  * If the #GtkCellRenderer:mode is %GTK_CELL_RENDERER_MODE_EDITABLE,
45  * the #GtkCellRendererText allows to edit its text using an entry.
46  */
47
48
49 static void gtk_cell_renderer_text_finalize   (GObject                  *object);
50
51 static void gtk_cell_renderer_text_get_property  (GObject                  *object,
52                                                   guint                     param_id,
53                                                   GValue                   *value,
54                                                   GParamSpec               *pspec);
55 static void gtk_cell_renderer_text_set_property  (GObject                  *object,
56                                                   guint                     param_id,
57                                                   const GValue             *value,
58                                                   GParamSpec               *pspec);
59 static void gtk_cell_renderer_text_render     (GtkCellRenderer          *cell,
60                                                cairo_t                  *cr,
61                                                GtkWidget                *widget,
62                                                const GdkRectangle       *background_area,
63                                                const GdkRectangle       *cell_area,
64                                                GtkCellRendererState      flags);
65
66 static GtkCellEditable *gtk_cell_renderer_text_start_editing (GtkCellRenderer      *cell,
67                                                               GdkEvent             *event,
68                                                               GtkWidget            *widget,
69                                                               const gchar          *path,
70                                                               const GdkRectangle   *background_area,
71                                                               const GdkRectangle   *cell_area,
72                                                               GtkCellRendererState  flags);
73
74 static void       gtk_cell_renderer_text_get_preferred_width            (GtkCellRenderer       *cell,
75                                                                          GtkWidget             *widget,
76                                                                          gint                  *minimal_size,
77                                                                          gint                  *natural_size);
78 static void       gtk_cell_renderer_text_get_preferred_height           (GtkCellRenderer       *cell,
79                                                                          GtkWidget             *widget,
80                                                                          gint                  *minimal_size,
81                                                                          gint                  *natural_size);
82 static void       gtk_cell_renderer_text_get_preferred_height_for_width (GtkCellRenderer       *cell,
83                                                                          GtkWidget             *widget,
84                                                                          gint                   width,
85                                                                          gint                  *minimum_height,
86                                                                          gint                  *natural_height);
87
88 enum {
89   EDITED,
90   LAST_SIGNAL
91 };
92
93 enum {
94   PROP_0,
95
96   PROP_TEXT,
97   PROP_MARKUP,
98   PROP_ATTRIBUTES,
99   PROP_SINGLE_PARAGRAPH_MODE,
100   PROP_WIDTH_CHARS,
101   PROP_MAX_WIDTH_CHARS,
102   PROP_WRAP_WIDTH,
103   PROP_ALIGN,
104   
105   /* Style args */
106   PROP_BACKGROUND,
107   PROP_FOREGROUND,
108   PROP_BACKGROUND_GDK,
109   PROP_FOREGROUND_GDK,
110   PROP_BACKGROUND_RGBA,
111   PROP_FOREGROUND_RGBA,
112   PROP_FONT,
113   PROP_FONT_DESC,
114   PROP_FAMILY,
115   PROP_STYLE,
116   PROP_VARIANT,
117   PROP_WEIGHT,
118   PROP_STRETCH,
119   PROP_SIZE,
120   PROP_SIZE_POINTS,
121   PROP_SCALE,
122   PROP_EDITABLE,
123   PROP_STRIKETHROUGH,
124   PROP_UNDERLINE,
125   PROP_RISE,
126   PROP_LANGUAGE,
127   PROP_ELLIPSIZE,
128   PROP_WRAP_MODE,
129   
130   /* Whether-a-style-arg-is-set args */
131   PROP_BACKGROUND_SET,
132   PROP_FOREGROUND_SET,
133   PROP_FAMILY_SET,
134   PROP_STYLE_SET,
135   PROP_VARIANT_SET,
136   PROP_WEIGHT_SET,
137   PROP_STRETCH_SET,
138   PROP_SIZE_SET,
139   PROP_SCALE_SET,
140   PROP_EDITABLE_SET,
141   PROP_STRIKETHROUGH_SET,
142   PROP_UNDERLINE_SET,
143   PROP_RISE_SET,
144   PROP_LANGUAGE_SET,
145   PROP_ELLIPSIZE_SET,
146   PROP_ALIGN_SET
147 };
148
149 static guint text_cell_renderer_signals [LAST_SIGNAL];
150
151 #define GTK_CELL_RENDERER_TEXT_PATH "gtk-cell-renderer-text-path"
152
153 struct _GtkCellRendererTextPrivate
154 {
155   GtkWidget *entry;
156
157   PangoAlignment        align;
158   PangoAttrList        *extra_attrs;
159   GdkRGBA               foreground;
160   GdkRGBA               background;
161   PangoEllipsizeMode    ellipsize;
162   PangoFontDescription *font;
163   PangoLanguage        *language;
164   PangoUnderline        underline_style;
165   PangoWrapMode         wrap_mode;
166
167   gboolean in_entry_menu;
168
169   gchar *text;
170
171   gdouble font_scale;
172
173   gint rise;
174   gint fixed_height_rows;
175   gint width_chars;
176   gint max_width_chars;
177   gint wrap_width;
178
179   guint strikethrough     : 1;
180   guint editable          : 1;
181   guint scale_set         : 1;
182   guint foreground_set    : 1;
183   guint background_set    : 1;
184   guint underline_set     : 1;
185   guint rise_set          : 1;
186   guint strikethrough_set : 1;
187   guint editable_set      : 1;
188   guint calc_fixed_height : 1;
189   guint single_paragraph  : 1;
190   guint language_set      : 1;
191   guint markup_set        : 1;
192   guint ellipsize_set     : 1;
193   guint align_set         : 1;
194
195   gulong focus_out_id;
196   gulong populate_popup_id;
197   gulong entry_menu_popdown_timeout;
198 };
199
200 G_DEFINE_TYPE (GtkCellRendererText, gtk_cell_renderer_text, GTK_TYPE_CELL_RENDERER)
201
202 static void
203 gtk_cell_renderer_text_init (GtkCellRendererText *celltext)
204 {
205   GtkCellRendererTextPrivate *priv;
206   GtkCellRenderer *cell = GTK_CELL_RENDERER (celltext);
207
208   celltext->priv = G_TYPE_INSTANCE_GET_PRIVATE (celltext,
209                                                 GTK_TYPE_CELL_RENDERER_TEXT,
210                                                 GtkCellRendererTextPrivate);
211   priv = celltext->priv;
212
213   gtk_cell_renderer_set_alignment (cell, 0.0, 0.5);
214   gtk_cell_renderer_set_padding (cell, 2, 2);
215   priv->font_scale = 1.0;
216   priv->fixed_height_rows = -1;
217   priv->font = pango_font_description_new ();
218
219   priv->width_chars = -1;
220   priv->max_width_chars = -1;
221   priv->wrap_width = -1;
222   priv->wrap_mode = PANGO_WRAP_CHAR;
223   priv->align = PANGO_ALIGN_LEFT;
224   priv->align_set = FALSE;
225 }
226
227 static void
228 gtk_cell_renderer_text_class_init (GtkCellRendererTextClass *class)
229 {
230   GObjectClass *object_class = G_OBJECT_CLASS (class);
231   GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (class);
232
233   object_class->finalize = gtk_cell_renderer_text_finalize;
234   
235   object_class->get_property = gtk_cell_renderer_text_get_property;
236   object_class->set_property = gtk_cell_renderer_text_set_property;
237
238   cell_class->render = gtk_cell_renderer_text_render;
239   cell_class->start_editing = gtk_cell_renderer_text_start_editing;
240   cell_class->get_preferred_width = gtk_cell_renderer_text_get_preferred_width;
241   cell_class->get_preferred_height = gtk_cell_renderer_text_get_preferred_height;
242   cell_class->get_preferred_height_for_width = gtk_cell_renderer_text_get_preferred_height_for_width;
243
244   g_object_class_install_property (object_class,
245                                    PROP_TEXT,
246                                    g_param_spec_string ("text",
247                                                         P_("Text"),
248                                                         P_("Text to render"),
249                                                         NULL,
250                                                         GTK_PARAM_READWRITE));
251   
252   g_object_class_install_property (object_class,
253                                    PROP_MARKUP,
254                                    g_param_spec_string ("markup",
255                                                         P_("Markup"),
256                                                         P_("Marked up text to render"),
257                                                         NULL,
258                                                         GTK_PARAM_WRITABLE));
259
260   g_object_class_install_property (object_class,
261                                    PROP_ATTRIBUTES,
262                                    g_param_spec_boxed ("attributes",
263                                                        P_("Attributes"),
264                                                        P_("A list of style attributes to apply to the text of the renderer"),
265                                                        PANGO_TYPE_ATTR_LIST,
266                                                        GTK_PARAM_READWRITE));
267
268   g_object_class_install_property (object_class,
269                                    PROP_SINGLE_PARAGRAPH_MODE,
270                                    g_param_spec_boolean ("single-paragraph-mode",
271                                                          P_("Single Paragraph Mode"),
272                                                          P_("Whether to keep all text in a single paragraph"),
273                                                          FALSE,
274                                                          GTK_PARAM_READWRITE));
275
276   
277   g_object_class_install_property (object_class,
278                                    PROP_BACKGROUND,
279                                    g_param_spec_string ("background",
280                                                         P_("Background color name"),
281                                                         P_("Background color as a string"),
282                                                         NULL,
283                                                         GTK_PARAM_WRITABLE));
284
285   g_object_class_install_property (object_class,
286                                    PROP_BACKGROUND_GDK,
287                                    g_param_spec_boxed ("background-gdk",
288                                                        P_("Background color"),
289                                                        P_("Background color as a GdkColor"),
290                                                        GDK_TYPE_COLOR,
291                                                        GTK_PARAM_READWRITE));  
292
293   /**
294    * GtkCellRendererText:background-rgba:
295    *
296    * Background color as a #GdkRGBA
297    *
298    * Since: 3.0
299    */
300   g_object_class_install_property (object_class,
301                                    PROP_BACKGROUND_RGBA,
302                                    g_param_spec_boxed ("background-rgba",
303                                                        P_("Background color as RGBA"),
304                                                        P_("Background color as a GdkRGBA"),
305                                                        GDK_TYPE_RGBA,
306                                                        GTK_PARAM_READWRITE));
307   g_object_class_install_property (object_class,
308                                    PROP_FOREGROUND,
309                                    g_param_spec_string ("foreground",
310                                                         P_("Foreground color name"),
311                                                         P_("Foreground color as a string"),
312                                                         NULL,
313                                                         GTK_PARAM_WRITABLE));
314
315   g_object_class_install_property (object_class,
316                                    PROP_FOREGROUND_GDK,
317                                    g_param_spec_boxed ("foreground-gdk",
318                                                        P_("Foreground color"),
319                                                        P_("Foreground color as a GdkColor"),
320                                                        GDK_TYPE_COLOR,
321                                                        GTK_PARAM_READWRITE));
322
323   /**
324    * GtkCellRendererText:foreground-rgba:
325    *
326    * Foreground color as a #GdkRGBA
327    *
328    * Since: 3.0
329    */
330   g_object_class_install_property (object_class,
331                                    PROP_FOREGROUND_RGBA,
332                                    g_param_spec_boxed ("foreground-rgba",
333                                                        P_("Foreground color as RGBA"),
334                                                        P_("Foreground color as a GdkRGBA"),
335                                                        GDK_TYPE_RGBA,
336                                                        GTK_PARAM_READWRITE));
337
338
339   g_object_class_install_property (object_class,
340                                    PROP_EDITABLE,
341                                    g_param_spec_boolean ("editable",
342                                                          P_("Editable"),
343                                                          P_("Whether the text can be modified by the user"),
344                                                          FALSE,
345                                                          GTK_PARAM_READWRITE));
346
347   g_object_class_install_property (object_class,
348                                    PROP_FONT,
349                                    g_param_spec_string ("font",
350                                                         P_("Font"),
351                                                         P_("Font description as a string, e.g. \"Sans Italic 12\""),
352                                                         NULL,
353                                                         GTK_PARAM_READWRITE));
354
355   g_object_class_install_property (object_class,
356                                    PROP_FONT_DESC,
357                                    g_param_spec_boxed ("font-desc",
358                                                        P_("Font"),
359                                                        P_("Font description as a PangoFontDescription struct"),
360                                                        PANGO_TYPE_FONT_DESCRIPTION,
361                                                        GTK_PARAM_READWRITE));
362
363   
364   g_object_class_install_property (object_class,
365                                    PROP_FAMILY,
366                                    g_param_spec_string ("family",
367                                                         P_("Font family"),
368                                                         P_("Name of the font family, e.g. Sans, Helvetica, Times, Monospace"),
369                                                         NULL,
370                                                         GTK_PARAM_READWRITE));
371
372   g_object_class_install_property (object_class,
373                                    PROP_STYLE,
374                                    g_param_spec_enum ("style",
375                                                       P_("Font style"),
376                                                       P_("Font style"),
377                                                       PANGO_TYPE_STYLE,
378                                                       PANGO_STYLE_NORMAL,
379                                                       GTK_PARAM_READWRITE));
380
381   g_object_class_install_property (object_class,
382                                    PROP_VARIANT,
383                                    g_param_spec_enum ("variant",
384                                                      P_("Font variant"),
385                                                      P_("Font variant"),
386                                                       PANGO_TYPE_VARIANT,
387                                                       PANGO_VARIANT_NORMAL,
388                                                       GTK_PARAM_READWRITE));
389   
390   g_object_class_install_property (object_class,
391                                    PROP_WEIGHT,
392                                    g_param_spec_int ("weight",
393                                                      P_("Font weight"),
394                                                      P_("Font weight"),
395                                                      0,
396                                                      G_MAXINT,
397                                                      PANGO_WEIGHT_NORMAL,
398                                                      GTK_PARAM_READWRITE));
399
400    g_object_class_install_property (object_class,
401                                    PROP_STRETCH,
402                                    g_param_spec_enum ("stretch",
403                                                       P_("Font stretch"),
404                                                       P_("Font stretch"),
405                                                       PANGO_TYPE_STRETCH,
406                                                       PANGO_STRETCH_NORMAL,
407                                                       GTK_PARAM_READWRITE));
408   
409   g_object_class_install_property (object_class,
410                                    PROP_SIZE,
411                                    g_param_spec_int ("size",
412                                                      P_("Font size"),
413                                                      P_("Font size"),
414                                                      0,
415                                                      G_MAXINT,
416                                                      0,
417                                                      GTK_PARAM_READWRITE));
418
419   g_object_class_install_property (object_class,
420                                    PROP_SIZE_POINTS,
421                                    g_param_spec_double ("size-points",
422                                                         P_("Font points"),
423                                                         P_("Font size in points"),
424                                                         0.0,
425                                                         G_MAXDOUBLE,
426                                                         0.0,
427                                                         GTK_PARAM_READWRITE));  
428
429   g_object_class_install_property (object_class,
430                                    PROP_SCALE,
431                                    g_param_spec_double ("scale",
432                                                         P_("Font scale"),
433                                                         P_("Font scaling factor"),
434                                                         0.0,
435                                                         G_MAXDOUBLE,
436                                                         1.0,
437                                                         GTK_PARAM_READWRITE));
438   
439   g_object_class_install_property (object_class,
440                                    PROP_RISE,
441                                    g_param_spec_int ("rise",
442                                                      P_("Rise"),
443                                                      P_("Offset of text above the baseline "
444                                                         "(below the baseline if rise is negative)"),
445                                                      -G_MAXINT,
446                                                      G_MAXINT,
447                                                      0,
448                                                      GTK_PARAM_READWRITE));
449
450
451   g_object_class_install_property (object_class,
452                                    PROP_STRIKETHROUGH,
453                                    g_param_spec_boolean ("strikethrough",
454                                                          P_("Strikethrough"),
455                                                          P_("Whether to strike through the text"),
456                                                          FALSE,
457                                                          GTK_PARAM_READWRITE));
458   
459   g_object_class_install_property (object_class,
460                                    PROP_UNDERLINE,
461                                    g_param_spec_enum ("underline",
462                                                       P_("Underline"),
463                                                       P_("Style of underline for this text"),
464                                                       PANGO_TYPE_UNDERLINE,
465                                                       PANGO_UNDERLINE_NONE,
466                                                       GTK_PARAM_READWRITE));
467
468   g_object_class_install_property (object_class,
469                                    PROP_LANGUAGE,
470                                    g_param_spec_string ("language",
471                                                         P_("Language"),
472                                                         P_("The language this text is in, as an ISO code. "
473                                                            "Pango can use this as a hint when rendering the text. "
474                                                            "If you don't understand this parameter, you probably don't need it"),
475                                                         NULL,
476                                                         GTK_PARAM_READWRITE));
477
478
479   /**
480    * GtkCellRendererText:ellipsize:
481    *
482    * Specifies the preferred place to ellipsize the string, if the cell renderer 
483    * does not have enough room to display the entire string. Setting it to 
484    * %PANGO_ELLIPSIZE_NONE turns off ellipsizing. See the wrap-width property
485    * for another way of making the text fit into a given width.
486    *
487    * Since: 2.6
488    */
489   g_object_class_install_property (object_class,
490                                    PROP_ELLIPSIZE,
491                                    g_param_spec_enum ("ellipsize",
492                                                       P_("Ellipsize"),
493                                                       P_("The preferred place to ellipsize the string, "
494                                                          "if the cell renderer does not have enough room "
495                                                          "to display the entire string"),
496                                                       PANGO_TYPE_ELLIPSIZE_MODE,
497                                                       PANGO_ELLIPSIZE_NONE,
498                                                       GTK_PARAM_READWRITE));
499
500   /**
501    * GtkCellRendererText:width-chars:
502    * 
503    * The desired width of the cell, in characters. If this property is set to
504    * -1, the width will be calculated automatically, otherwise the cell will
505    * request either 3 characters or the property value, whichever is greater.
506    * 
507    * Since: 2.6
508    **/
509   g_object_class_install_property (object_class,
510                                    PROP_WIDTH_CHARS,
511                                    g_param_spec_int ("width-chars",
512                                                      P_("Width In Characters"),
513                                                      P_("The desired width of the label, in characters"),
514                                                      -1,
515                                                      G_MAXINT,
516                                                      -1,
517                                                      GTK_PARAM_READWRITE));
518   
519
520   /**
521    * GtkCellRendererText:max-width-chars:
522    * 
523    * The desired maximum width of the cell, in characters. If this property 
524    * is set to -1, the width will be calculated automatically.
525    *
526    * For cell renderers that ellipsize or wrap text; this property
527    * controls the maximum reported width of the cell. The
528    * cell should not receive any greater allocation unless it is
529    * set to expand in its #GtkCellLayout and all of the cell's siblings
530    * have received their natural width.
531    *
532    * Since: 3.0
533    **/
534   g_object_class_install_property (object_class,
535                                    PROP_MAX_WIDTH_CHARS,
536                                    g_param_spec_int ("max-width-chars",
537                                                      P_("Maximum Width In Characters"),
538                                                      P_("The maximum width of the cell, in characters"),
539                                                      -1,
540                                                      G_MAXINT,
541                                                      -1,
542                                                      GTK_PARAM_READWRITE));
543   
544   /**
545    * GtkCellRendererText:wrap-mode:
546    *
547    * Specifies how to break the string into multiple lines, if the cell 
548    * renderer does not have enough room to display the entire string. 
549    * This property has no effect unless the wrap-width property is set.
550    *
551    * Since: 2.8
552    */
553   g_object_class_install_property (object_class,
554                                    PROP_WRAP_MODE,
555                                    g_param_spec_enum ("wrap-mode",
556                                                       P_("Wrap mode"),
557                                                       P_("How to break the string into multiple lines, "
558                                                          "if the cell renderer does not have enough room "
559                                                          "to display the entire string"),
560                                                       PANGO_TYPE_WRAP_MODE,
561                                                       PANGO_WRAP_CHAR,
562                                                       GTK_PARAM_READWRITE));
563
564   /**
565    * GtkCellRendererText:wrap-width:
566    *
567    * Specifies the minimum width at which the text is wrapped. The wrap-mode property can 
568    * be used to influence at what character positions the line breaks can be placed.
569    * Setting wrap-width to -1 turns wrapping off.
570    *
571    * Since: 2.8
572    */
573   g_object_class_install_property (object_class,
574                                    PROP_WRAP_WIDTH,
575                                    g_param_spec_int ("wrap-width",
576                                                      P_("Wrap width"),
577                                                      P_("The width at which the text is wrapped"),
578                                                      -1,
579                                                      G_MAXINT,
580                                                      -1,
581                                                      GTK_PARAM_READWRITE));
582
583   /**
584    * GtkCellRendererText:alignment:
585    *
586    * Specifies how to align the lines of text with respect to each other. 
587    *
588    * Note that this property describes how to align the lines of text in 
589    * case there are several of them. The "xalign" property of #GtkCellRenderer, 
590    * on the other hand, sets the horizontal alignment of the whole text.
591    *
592    * Since: 2.10
593    */
594   g_object_class_install_property (object_class,
595                                    PROP_ALIGN,
596                                    g_param_spec_enum ("alignment",
597                                                       P_("Alignment"),
598                                                       P_("How to align the lines"),
599                                                       PANGO_TYPE_ALIGNMENT,
600                                                       PANGO_ALIGN_LEFT,
601                                                       GTK_PARAM_READWRITE));
602   
603
604
605   /* Style props are set or not */
606
607 #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))
608
609   ADD_SET_PROP ("background-set", PROP_BACKGROUND_SET,
610                 P_("Background set"),
611                 P_("Whether this tag affects the background color"));
612
613   ADD_SET_PROP ("foreground-set", PROP_FOREGROUND_SET,
614                 P_("Foreground set"),
615                 P_("Whether this tag affects the foreground color"));
616   
617   ADD_SET_PROP ("editable-set", PROP_EDITABLE_SET,
618                 P_("Editability set"),
619                 P_("Whether this tag affects text editability"));
620
621   ADD_SET_PROP ("family-set", PROP_FAMILY_SET,
622                 P_("Font family set"),
623                 P_("Whether this tag affects the font family"));  
624
625   ADD_SET_PROP ("style-set", PROP_STYLE_SET,
626                 P_("Font style set"),
627                 P_("Whether this tag affects the font style"));
628
629   ADD_SET_PROP ("variant-set", PROP_VARIANT_SET,
630                 P_("Font variant set"),
631                 P_("Whether this tag affects the font variant"));
632
633   ADD_SET_PROP ("weight-set", PROP_WEIGHT_SET,
634                 P_("Font weight set"),
635                 P_("Whether this tag affects the font weight"));
636
637   ADD_SET_PROP ("stretch-set", PROP_STRETCH_SET,
638                 P_("Font stretch set"),
639                 P_("Whether this tag affects the font stretch"));
640
641   ADD_SET_PROP ("size-set", PROP_SIZE_SET,
642                 P_("Font size set"),
643                 P_("Whether this tag affects the font size"));
644
645   ADD_SET_PROP ("scale-set", PROP_SCALE_SET,
646                 P_("Font scale set"),
647                 P_("Whether this tag scales the font size by a factor"));
648   
649   ADD_SET_PROP ("rise-set", PROP_RISE_SET,
650                 P_("Rise set"),
651                 P_("Whether this tag affects the rise"));
652
653   ADD_SET_PROP ("strikethrough-set", PROP_STRIKETHROUGH_SET,
654                 P_("Strikethrough set"),
655                 P_("Whether this tag affects strikethrough"));
656
657   ADD_SET_PROP ("underline-set", PROP_UNDERLINE_SET,
658                 P_("Underline set"),
659                 P_("Whether this tag affects underlining"));
660
661   ADD_SET_PROP ("language-set", PROP_LANGUAGE_SET,
662                 P_("Language set"),
663                 P_("Whether this tag affects the language the text is rendered as"));
664
665   ADD_SET_PROP ("ellipsize-set", PROP_ELLIPSIZE_SET,
666                 P_("Ellipsize set"),
667                 P_("Whether this tag affects the ellipsize mode"));
668
669   ADD_SET_PROP ("align-set", PROP_ALIGN_SET,
670                 P_("Align set"),
671                 P_("Whether this tag affects the alignment mode"));
672
673   /**
674    * GtkCellRendererText::edited
675    * @renderer: the object which received the signal
676    * @path: the path identifying the edited cell
677    * @new_text: the new text
678    *
679    * This signal is emitted after @renderer has been edited.
680    *
681    * It is the responsibility of the application to update the model
682    * and store @new_text at the position indicated by @path.
683    */
684   text_cell_renderer_signals [EDITED] =
685     g_signal_new (I_("edited"),
686                   G_OBJECT_CLASS_TYPE (object_class),
687                   G_SIGNAL_RUN_LAST,
688                   G_STRUCT_OFFSET (GtkCellRendererTextClass, edited),
689                   NULL, NULL,
690                   _gtk_marshal_VOID__STRING_STRING,
691                   G_TYPE_NONE, 2,
692                   G_TYPE_STRING,
693                   G_TYPE_STRING);
694
695   g_type_class_add_private (object_class, sizeof (GtkCellRendererTextPrivate));
696 }
697
698 static void
699 gtk_cell_renderer_text_finalize (GObject *object)
700 {
701   GtkCellRendererText *celltext = GTK_CELL_RENDERER_TEXT (object);
702   GtkCellRendererTextPrivate *priv = celltext->priv;
703
704   pango_font_description_free (priv->font);
705
706   g_free (priv->text);
707
708   if (priv->extra_attrs)
709     pango_attr_list_unref (priv->extra_attrs);
710
711   if (priv->language)
712     g_object_unref (priv->language);
713
714   G_OBJECT_CLASS (gtk_cell_renderer_text_parent_class)->finalize (object);
715 }
716
717 static PangoFontMask
718 get_property_font_set_mask (guint prop_id)
719 {
720   switch (prop_id)
721     {
722     case PROP_FAMILY_SET:
723       return PANGO_FONT_MASK_FAMILY;
724     case PROP_STYLE_SET:
725       return PANGO_FONT_MASK_STYLE;
726     case PROP_VARIANT_SET:
727       return PANGO_FONT_MASK_VARIANT;
728     case PROP_WEIGHT_SET:
729       return PANGO_FONT_MASK_WEIGHT;
730     case PROP_STRETCH_SET:
731       return PANGO_FONT_MASK_STRETCH;
732     case PROP_SIZE_SET:
733       return PANGO_FONT_MASK_SIZE;
734     }
735
736   return 0;
737 }
738
739 static void
740 gtk_cell_renderer_text_get_property (GObject        *object,
741                                      guint           param_id,
742                                      GValue         *value,
743                                      GParamSpec     *pspec)
744 {
745   GtkCellRendererText *celltext = GTK_CELL_RENDERER_TEXT (object);
746   GtkCellRendererTextPrivate *priv = celltext->priv;
747
748   switch (param_id)
749     {
750     case PROP_TEXT:
751       g_value_set_string (value, priv->text);
752       break;
753
754     case PROP_ATTRIBUTES:
755       g_value_set_boxed (value, priv->extra_attrs);
756       break;
757
758     case PROP_SINGLE_PARAGRAPH_MODE:
759       g_value_set_boolean (value, priv->single_paragraph);
760       break;
761
762     case PROP_BACKGROUND_GDK:
763       {
764         GdkColor color;
765
766         color.red = (guint16) (priv->background.red * 65535);
767         color.green = (guint16) (priv->background.green * 65535);
768         color.blue = (guint16) (priv->background.blue * 65535);
769
770         g_value_set_boxed (value, &color);
771       }
772       break;
773
774     case PROP_FOREGROUND_GDK:
775       {
776         GdkColor color;
777
778         color.red = (guint16) (priv->foreground.red * 65535);
779         color.green = (guint16) (priv->foreground.green * 65535);
780         color.blue = (guint16) (priv->foreground.blue * 65535);
781
782         g_value_set_boxed (value, &color);
783       }
784       break;
785
786     case PROP_BACKGROUND_RGBA:
787       g_value_set_boxed (value, &priv->background);
788       break;
789
790     case PROP_FOREGROUND_RGBA:
791       g_value_set_boxed (value, &priv->foreground);
792       break;
793
794     case PROP_FONT:
795         g_value_take_string (value, pango_font_description_to_string (priv->font));
796       break;
797       
798     case PROP_FONT_DESC:
799       g_value_set_boxed (value, priv->font);
800       break;
801
802     case PROP_FAMILY:
803       g_value_set_string (value, pango_font_description_get_family (priv->font));
804       break;
805
806     case PROP_STYLE:
807       g_value_set_enum (value, pango_font_description_get_style (priv->font));
808       break;
809
810     case PROP_VARIANT:
811       g_value_set_enum (value, pango_font_description_get_variant (priv->font));
812       break;
813
814     case PROP_WEIGHT:
815       g_value_set_int (value, pango_font_description_get_weight (priv->font));
816       break;
817
818     case PROP_STRETCH:
819       g_value_set_enum (value, pango_font_description_get_stretch (priv->font));
820       break;
821
822     case PROP_SIZE:
823       g_value_set_int (value, pango_font_description_get_size (priv->font));
824       break;
825
826     case PROP_SIZE_POINTS:
827       g_value_set_double (value, ((double)pango_font_description_get_size (priv->font)) / (double)PANGO_SCALE);
828       break;
829
830     case PROP_SCALE:
831       g_value_set_double (value, priv->font_scale);
832       break;
833       
834     case PROP_EDITABLE:
835       g_value_set_boolean (value, priv->editable);
836       break;
837
838     case PROP_STRIKETHROUGH:
839       g_value_set_boolean (value, priv->strikethrough);
840       break;
841
842     case PROP_UNDERLINE:
843       g_value_set_enum (value, priv->underline_style);
844       break;
845
846     case PROP_RISE:
847       g_value_set_int (value, priv->rise);
848       break;  
849
850     case PROP_LANGUAGE:
851       g_value_set_static_string (value, pango_language_to_string (priv->language));
852       break;
853
854     case PROP_ELLIPSIZE:
855       g_value_set_enum (value, priv->ellipsize);
856       break;
857       
858     case PROP_WRAP_MODE:
859       g_value_set_enum (value, priv->wrap_mode);
860       break;
861
862     case PROP_WRAP_WIDTH:
863       g_value_set_int (value, priv->wrap_width);
864       break;
865       
866     case PROP_ALIGN:
867       g_value_set_enum (value, priv->align);
868       break;
869
870     case PROP_BACKGROUND_SET:
871       g_value_set_boolean (value, priv->background_set);
872       break;
873
874     case PROP_FOREGROUND_SET:
875       g_value_set_boolean (value, priv->foreground_set);
876       break;
877
878     case PROP_FAMILY_SET:
879     case PROP_STYLE_SET:
880     case PROP_VARIANT_SET:
881     case PROP_WEIGHT_SET:
882     case PROP_STRETCH_SET:
883     case PROP_SIZE_SET:
884       {
885         PangoFontMask mask = get_property_font_set_mask (param_id);
886         g_value_set_boolean (value, (pango_font_description_get_set_fields (priv->font) & mask) != 0);
887         
888         break;
889       }
890
891     case PROP_SCALE_SET:
892       g_value_set_boolean (value, priv->scale_set);
893       break;
894       
895     case PROP_EDITABLE_SET:
896       g_value_set_boolean (value, priv->editable_set);
897       break;
898
899     case PROP_STRIKETHROUGH_SET:
900       g_value_set_boolean (value, priv->strikethrough_set);
901       break;
902
903     case PROP_UNDERLINE_SET:
904       g_value_set_boolean (value, priv->underline_set);
905       break;
906
907     case  PROP_RISE_SET:
908       g_value_set_boolean (value, priv->rise_set);
909       break;
910
911     case PROP_LANGUAGE_SET:
912       g_value_set_boolean (value, priv->language_set);
913       break;
914
915     case PROP_ELLIPSIZE_SET:
916       g_value_set_boolean (value, priv->ellipsize_set);
917       break;
918
919     case PROP_ALIGN_SET:
920       g_value_set_boolean (value, priv->align_set);
921       break;
922       
923     case PROP_WIDTH_CHARS:
924       g_value_set_int (value, priv->width_chars);
925       break;  
926
927     case PROP_MAX_WIDTH_CHARS:
928       g_value_set_int (value, priv->max_width_chars);
929       break;  
930
931     case PROP_BACKGROUND:
932     case PROP_FOREGROUND:
933     case PROP_MARKUP:
934     default:
935       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
936       break;
937     }
938 }
939
940
941 static void
942 set_bg_color (GtkCellRendererText *celltext,
943               GdkRGBA             *rgba)
944 {
945   GtkCellRendererTextPrivate *priv = celltext->priv;
946
947   if (rgba)
948     {
949       if (!priv->background_set)
950         {
951           priv->background_set = TRUE;
952           g_object_notify (G_OBJECT (celltext), "background-set");
953         }
954
955       priv->background = *rgba;
956     }
957   else
958     {
959       if (priv->background_set)
960         {
961           priv->background_set = FALSE;
962           g_object_notify (G_OBJECT (celltext), "background-set");
963         }
964     }
965 }
966
967
968 static void
969 set_fg_color (GtkCellRendererText *celltext,
970               GdkRGBA             *rgba)
971 {
972   GtkCellRendererTextPrivate *priv = celltext->priv;
973
974   if (rgba)
975     {
976       if (!priv->foreground_set)
977         {
978           priv->foreground_set = TRUE;
979           g_object_notify (G_OBJECT (celltext), "foreground-set");
980         }
981
982       priv->foreground = *rgba;
983     }
984   else
985     {
986       if (priv->foreground_set)
987         {
988           priv->foreground_set = FALSE;
989           g_object_notify (G_OBJECT (celltext), "foreground-set");
990         }
991     }
992 }
993
994 static PangoFontMask
995 set_font_desc_fields (PangoFontDescription *desc,
996                       PangoFontMask         to_set)
997 {
998   PangoFontMask changed_mask = 0;
999   
1000   if (to_set & PANGO_FONT_MASK_FAMILY)
1001     {
1002       const char *family = pango_font_description_get_family (desc);
1003       if (!family)
1004         {
1005           family = "sans";
1006           changed_mask |= PANGO_FONT_MASK_FAMILY;
1007         }
1008
1009       pango_font_description_set_family (desc, family);
1010     }
1011   if (to_set & PANGO_FONT_MASK_STYLE)
1012     pango_font_description_set_style (desc, pango_font_description_get_style (desc));
1013   if (to_set & PANGO_FONT_MASK_VARIANT)
1014     pango_font_description_set_variant (desc, pango_font_description_get_variant (desc));
1015   if (to_set & PANGO_FONT_MASK_WEIGHT)
1016     pango_font_description_set_weight (desc, pango_font_description_get_weight (desc));
1017   if (to_set & PANGO_FONT_MASK_STRETCH)
1018     pango_font_description_set_stretch (desc, pango_font_description_get_stretch (desc));
1019   if (to_set & PANGO_FONT_MASK_SIZE)
1020     {
1021       gint size = pango_font_description_get_size (desc);
1022       if (size <= 0)
1023         {
1024           size = 10 * PANGO_SCALE;
1025           changed_mask |= PANGO_FONT_MASK_SIZE;
1026         }
1027       
1028       pango_font_description_set_size (desc, size);
1029     }
1030
1031   return changed_mask;
1032 }
1033
1034 static void
1035 notify_set_changed (GObject       *object,
1036                     PangoFontMask  changed_mask)
1037 {
1038   if (changed_mask & PANGO_FONT_MASK_FAMILY)
1039     g_object_notify (object, "family-set");
1040   if (changed_mask & PANGO_FONT_MASK_STYLE)
1041     g_object_notify (object, "style-set");
1042   if (changed_mask & PANGO_FONT_MASK_VARIANT)
1043     g_object_notify (object, "variant-set");
1044   if (changed_mask & PANGO_FONT_MASK_WEIGHT)
1045     g_object_notify (object, "weight-set");
1046   if (changed_mask & PANGO_FONT_MASK_STRETCH)
1047     g_object_notify (object, "stretch-set");
1048   if (changed_mask & PANGO_FONT_MASK_SIZE)
1049     g_object_notify (object, "size-set");
1050 }
1051
1052 static void
1053 notify_fields_changed (GObject       *object,
1054                        PangoFontMask  changed_mask)
1055 {
1056   if (changed_mask & PANGO_FONT_MASK_FAMILY)
1057     g_object_notify (object, "family");
1058   if (changed_mask & PANGO_FONT_MASK_STYLE)
1059     g_object_notify (object, "style");
1060   if (changed_mask & PANGO_FONT_MASK_VARIANT)
1061     g_object_notify (object, "variant");
1062   if (changed_mask & PANGO_FONT_MASK_WEIGHT)
1063     g_object_notify (object, "weight");
1064   if (changed_mask & PANGO_FONT_MASK_STRETCH)
1065     g_object_notify (object, "stretch");
1066   if (changed_mask & PANGO_FONT_MASK_SIZE)
1067     g_object_notify (object, "size");
1068 }
1069
1070 static void
1071 set_font_description (GtkCellRendererText  *celltext,
1072                       PangoFontDescription *font_desc)
1073 {
1074   GtkCellRendererTextPrivate *priv = celltext->priv;
1075   GObject *object = G_OBJECT (celltext);
1076   PangoFontDescription *new_font_desc;
1077   PangoFontMask old_mask, new_mask, changed_mask, set_changed_mask;
1078   
1079   if (font_desc)
1080     new_font_desc = pango_font_description_copy (font_desc);
1081   else
1082     new_font_desc = pango_font_description_new ();
1083
1084   old_mask = pango_font_description_get_set_fields (priv->font);
1085   new_mask = pango_font_description_get_set_fields (new_font_desc);
1086
1087   changed_mask = old_mask | new_mask;
1088   set_changed_mask = old_mask ^ new_mask;
1089
1090   pango_font_description_free (priv->font);
1091   priv->font = new_font_desc;
1092   
1093   g_object_freeze_notify (object);
1094
1095   g_object_notify (object, "font-desc");
1096   g_object_notify (object, "font");
1097   
1098   if (changed_mask & PANGO_FONT_MASK_FAMILY)
1099     g_object_notify (object, "family");
1100   if (changed_mask & PANGO_FONT_MASK_STYLE)
1101     g_object_notify (object, "style");
1102   if (changed_mask & PANGO_FONT_MASK_VARIANT)
1103     g_object_notify (object, "variant");
1104   if (changed_mask & PANGO_FONT_MASK_WEIGHT)
1105     g_object_notify (object, "weight");
1106   if (changed_mask & PANGO_FONT_MASK_STRETCH)
1107     g_object_notify (object, "stretch");
1108   if (changed_mask & PANGO_FONT_MASK_SIZE)
1109     {
1110       g_object_notify (object, "size");
1111       g_object_notify (object, "size-points");
1112     }
1113
1114   notify_set_changed (object, set_changed_mask);
1115   
1116   g_object_thaw_notify (object);
1117 }
1118
1119 static void
1120 gtk_cell_renderer_text_set_property (GObject      *object,
1121                                      guint         param_id,
1122                                      const GValue *value,
1123                                      GParamSpec   *pspec)
1124 {
1125   GtkCellRendererText *celltext = GTK_CELL_RENDERER_TEXT (object);
1126   GtkCellRendererTextPrivate *priv = celltext->priv;
1127
1128   switch (param_id)
1129     {
1130     case PROP_TEXT:
1131       g_free (priv->text);
1132
1133       if (priv->markup_set)
1134         {
1135           if (priv->extra_attrs)
1136             pango_attr_list_unref (priv->extra_attrs);
1137           priv->extra_attrs = NULL;
1138           priv->markup_set = FALSE;
1139         }
1140
1141       priv->text = g_value_dup_string (value);
1142       g_object_notify (object, "text");
1143       break;
1144
1145     case PROP_ATTRIBUTES:
1146       if (priv->extra_attrs)
1147         pango_attr_list_unref (priv->extra_attrs);
1148
1149       priv->extra_attrs = g_value_get_boxed (value);
1150       if (priv->extra_attrs)
1151         pango_attr_list_ref (priv->extra_attrs);
1152       break;
1153     case PROP_MARKUP:
1154       {
1155         const gchar *str;
1156         gchar *text = NULL;
1157         GError *error = NULL;
1158         PangoAttrList *attrs = NULL;
1159
1160         str = g_value_get_string (value);
1161         if (str && !pango_parse_markup (str,
1162                                         -1,
1163                                         0,
1164                                         &attrs,
1165                                         &text,
1166                                         NULL,
1167                                         &error))
1168           {
1169             g_warning ("Failed to set text from markup due to error parsing markup: %s",
1170                        error->message);
1171             g_error_free (error);
1172             return;
1173           }
1174
1175         g_free (priv->text);
1176
1177         if (priv->extra_attrs)
1178           pango_attr_list_unref (priv->extra_attrs);
1179
1180         priv->text = text;
1181         priv->extra_attrs = attrs;
1182         priv->markup_set = TRUE;
1183       }
1184       break;
1185
1186     case PROP_SINGLE_PARAGRAPH_MODE:
1187       priv->single_paragraph = g_value_get_boolean (value);
1188       break;
1189       
1190     case PROP_BACKGROUND:
1191       {
1192         GdkRGBA rgba;
1193
1194         if (!g_value_get_string (value))
1195           set_bg_color (celltext, NULL);       /* reset to background_set to FALSE */
1196         else if (gdk_rgba_parse (g_value_get_string (value), &rgba))
1197           set_bg_color (celltext, &rgba);
1198         else
1199           g_warning ("Don't know color `%s'", g_value_get_string (value));
1200
1201         g_object_notify (object, "background-gdk");
1202       }
1203       break;
1204       
1205     case PROP_FOREGROUND:
1206       {
1207         GdkRGBA rgba;
1208
1209         if (!g_value_get_string (value))
1210           set_fg_color (celltext, NULL);       /* reset to foreground_set to FALSE */
1211         else if (gdk_rgba_parse (g_value_get_string (value), &rgba))
1212           set_fg_color (celltext, &rgba);
1213         else
1214           g_warning ("Don't know color `%s'", g_value_get_string (value));
1215
1216         g_object_notify (object, "foreground-gdk");
1217       }
1218       break;
1219
1220     case PROP_BACKGROUND_GDK:
1221       {
1222         GdkColor *color;
1223
1224         color = g_value_get_boxed (value);
1225         if (color)
1226           {
1227             GdkRGBA rgba;
1228
1229             rgba.red = color->red / 65535.;
1230             rgba.green = color->green / 65535.;
1231             rgba.blue = color->blue / 65535.;
1232             rgba.alpha = 1;
1233
1234             set_bg_color (celltext, &rgba);
1235           }
1236         else
1237           {
1238             set_bg_color (celltext, NULL);
1239           }
1240       }
1241       break;
1242
1243     case PROP_FOREGROUND_GDK:
1244       {
1245         GdkColor *color;
1246
1247         color = g_value_get_boxed (value);
1248         if (color)
1249           {
1250             GdkRGBA rgba;
1251
1252             rgba.red = color->red / 65535.;
1253             rgba.green = color->green / 65535.;
1254             rgba.blue = color->blue / 65535.;
1255             rgba.alpha = 1;
1256
1257             set_fg_color (celltext, &rgba);
1258           }
1259         else
1260           {
1261             set_fg_color (celltext, NULL);
1262           }
1263       }
1264       break;
1265
1266     case PROP_BACKGROUND_RGBA:
1267       /* This notifies the GObject itself. */
1268       set_bg_color (celltext, g_value_get_boxed (value));
1269       break;
1270
1271     case PROP_FOREGROUND_RGBA:
1272       /* This notifies the GObject itself. */
1273       set_fg_color (celltext, g_value_get_boxed (value));
1274       break;
1275
1276     case PROP_FONT:
1277       {
1278         PangoFontDescription *font_desc = NULL;
1279         const gchar *name;
1280
1281         name = g_value_get_string (value);
1282
1283         if (name)
1284           font_desc = pango_font_description_from_string (name);
1285
1286         set_font_description (celltext, font_desc);
1287
1288         pango_font_description_free (font_desc);
1289         
1290         if (priv->fixed_height_rows != -1)
1291           priv->calc_fixed_height = TRUE;
1292       }
1293       break;
1294
1295     case PROP_FONT_DESC:
1296       set_font_description (celltext, g_value_get_boxed (value));
1297       
1298       if (priv->fixed_height_rows != -1)
1299         priv->calc_fixed_height = TRUE;
1300       break;
1301
1302     case PROP_FAMILY:
1303     case PROP_STYLE:
1304     case PROP_VARIANT:
1305     case PROP_WEIGHT:
1306     case PROP_STRETCH:
1307     case PROP_SIZE:
1308     case PROP_SIZE_POINTS:
1309       {
1310         PangoFontMask old_set_mask = pango_font_description_get_set_fields (priv->font);
1311         
1312         switch (param_id)
1313           {
1314           case PROP_FAMILY:
1315             pango_font_description_set_family (priv->font,
1316                                                g_value_get_string (value));
1317             break;
1318           case PROP_STYLE:
1319             pango_font_description_set_style (priv->font,
1320                                               g_value_get_enum (value));
1321             break;
1322           case PROP_VARIANT:
1323             pango_font_description_set_variant (priv->font,
1324                                                 g_value_get_enum (value));
1325             break;
1326           case PROP_WEIGHT:
1327             pango_font_description_set_weight (priv->font,
1328                                                g_value_get_int (value));
1329             break;
1330           case PROP_STRETCH:
1331             pango_font_description_set_stretch (priv->font,
1332                                                 g_value_get_enum (value));
1333             break;
1334           case PROP_SIZE:
1335             pango_font_description_set_size (priv->font,
1336                                              g_value_get_int (value));
1337             g_object_notify (object, "size-points");
1338             break;
1339           case PROP_SIZE_POINTS:
1340             pango_font_description_set_size (priv->font,
1341                                              g_value_get_double (value) * PANGO_SCALE);
1342             g_object_notify (object, "size");
1343             break;
1344           }
1345         
1346         if (priv->fixed_height_rows != -1)
1347           priv->calc_fixed_height = TRUE;
1348         
1349         notify_set_changed (object, old_set_mask & pango_font_description_get_set_fields (priv->font));
1350         g_object_notify (object, "font-desc");
1351         g_object_notify (object, "font");
1352
1353         break;
1354       }
1355       
1356     case PROP_SCALE:
1357       priv->font_scale = g_value_get_double (value);
1358       priv->scale_set = TRUE;
1359       if (priv->fixed_height_rows != -1)
1360         priv->calc_fixed_height = TRUE;
1361       g_object_notify (object, "scale-set");
1362       break;
1363       
1364     case PROP_EDITABLE:
1365       priv->editable = g_value_get_boolean (value);
1366       priv->editable_set = TRUE;
1367       if (priv->editable)
1368         g_object_set (celltext, "mode", GTK_CELL_RENDERER_MODE_EDITABLE, NULL);
1369       else
1370         g_object_set (celltext, "mode", GTK_CELL_RENDERER_MODE_INERT, NULL);
1371       g_object_notify (object, "editable-set");
1372       break;
1373
1374     case PROP_STRIKETHROUGH:
1375       priv->strikethrough = g_value_get_boolean (value);
1376       priv->strikethrough_set = TRUE;
1377       g_object_notify (object, "strikethrough-set");
1378       break;
1379
1380     case PROP_UNDERLINE:
1381       priv->underline_style = g_value_get_enum (value);
1382       priv->underline_set = TRUE;
1383       g_object_notify (object, "underline-set");
1384             
1385       break;
1386
1387     case PROP_RISE:
1388       priv->rise = g_value_get_int (value);
1389       priv->rise_set = TRUE;
1390       g_object_notify (object, "rise-set");
1391       if (priv->fixed_height_rows != -1)
1392         priv->calc_fixed_height = TRUE;
1393       break;  
1394
1395     case PROP_LANGUAGE:
1396       priv->language_set = TRUE;
1397       if (priv->language)
1398         g_object_unref (priv->language);
1399       priv->language = pango_language_from_string (g_value_get_string (value));
1400       g_object_notify (object, "language-set");
1401       break;
1402
1403     case PROP_ELLIPSIZE:
1404       priv->ellipsize = g_value_get_enum (value);
1405       priv->ellipsize_set = TRUE;
1406       g_object_notify (object, "ellipsize-set");
1407       break;
1408       
1409     case PROP_WRAP_MODE:
1410       priv->wrap_mode = g_value_get_enum (value);
1411       break;
1412       
1413     case PROP_WRAP_WIDTH:
1414       priv->wrap_width = g_value_get_int (value);
1415       break;
1416             
1417     case PROP_WIDTH_CHARS:
1418       priv->width_chars = g_value_get_int (value);
1419       break;  
1420
1421     case PROP_MAX_WIDTH_CHARS:
1422       priv->max_width_chars = g_value_get_int (value);
1423       break;  
1424
1425     case PROP_ALIGN:
1426       priv->align = g_value_get_enum (value);
1427       priv->align_set = TRUE;
1428       g_object_notify (object, "align-set");
1429       break;
1430
1431     case PROP_BACKGROUND_SET:
1432       priv->background_set = g_value_get_boolean (value);
1433       break;
1434
1435     case PROP_FOREGROUND_SET:
1436       priv->foreground_set = g_value_get_boolean (value);
1437       break;
1438
1439     case PROP_FAMILY_SET:
1440     case PROP_STYLE_SET:
1441     case PROP_VARIANT_SET:
1442     case PROP_WEIGHT_SET:
1443     case PROP_STRETCH_SET:
1444     case PROP_SIZE_SET:
1445       if (!g_value_get_boolean (value))
1446         {
1447           pango_font_description_unset_fields (priv->font,
1448                                                get_property_font_set_mask (param_id));
1449         }
1450       else
1451         {
1452           PangoFontMask changed_mask;
1453           
1454           changed_mask = set_font_desc_fields (priv->font,
1455                                                get_property_font_set_mask (param_id));
1456           notify_fields_changed (G_OBJECT (celltext), changed_mask);
1457         }
1458       break;
1459
1460     case PROP_SCALE_SET:
1461       priv->scale_set = g_value_get_boolean (value);
1462       break;
1463       
1464     case PROP_EDITABLE_SET:
1465       priv->editable_set = g_value_get_boolean (value);
1466       break;
1467
1468     case PROP_STRIKETHROUGH_SET:
1469       priv->strikethrough_set = g_value_get_boolean (value);
1470       break;
1471
1472     case PROP_UNDERLINE_SET:
1473       priv->underline_set = g_value_get_boolean (value);
1474       break;
1475
1476     case PROP_RISE_SET:
1477       priv->rise_set = g_value_get_boolean (value);
1478       break;
1479
1480     case PROP_LANGUAGE_SET:
1481       priv->language_set = g_value_get_boolean (value);
1482       break;
1483
1484     case PROP_ELLIPSIZE_SET:
1485       priv->ellipsize_set = g_value_get_boolean (value);
1486       break;
1487
1488     case PROP_ALIGN_SET:
1489       priv->align_set = g_value_get_boolean (value);
1490       break;
1491       
1492     default:
1493       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
1494       break;
1495     }
1496 }
1497
1498 /**
1499  * gtk_cell_renderer_text_new:
1500  * 
1501  * Creates a new #GtkCellRendererText. Adjust how text is drawn using
1502  * object properties. Object properties can be
1503  * set globally (with g_object_set()). Also, with #GtkTreeViewColumn,
1504  * you can bind a property to a value in a #GtkTreeModel. For example,
1505  * you can bind the "text" property on the cell renderer to a string
1506  * value in the model, thus rendering a different string in each row
1507  * of the #GtkTreeView
1508  * 
1509  * Return value: the new cell renderer
1510  **/
1511 GtkCellRenderer *
1512 gtk_cell_renderer_text_new (void)
1513 {
1514   return g_object_new (GTK_TYPE_CELL_RENDERER_TEXT, NULL);
1515 }
1516
1517 static void
1518 add_attr (PangoAttrList  *attr_list,
1519           PangoAttribute *attr)
1520 {
1521   attr->start_index = 0;
1522   attr->end_index = G_MAXINT;
1523   
1524   pango_attr_list_insert (attr_list, attr);
1525 }
1526
1527 static PangoLayout*
1528 get_layout (GtkCellRendererText *celltext,
1529             GtkWidget           *widget,
1530             const GdkRectangle  *cell_area,
1531             GtkCellRendererState flags)
1532 {
1533   GtkCellRendererTextPrivate *priv = celltext->priv;
1534   PangoAttrList *attr_list;
1535   PangoLayout *layout;
1536   PangoUnderline uline;
1537   gint xpad;
1538
1539   layout = gtk_widget_create_pango_layout (widget, priv->text);
1540
1541   gtk_cell_renderer_get_padding (GTK_CELL_RENDERER (celltext), &xpad, NULL);
1542
1543   if (priv->extra_attrs)
1544     attr_list = pango_attr_list_copy (priv->extra_attrs);
1545   else
1546     attr_list = pango_attr_list_new ();
1547
1548   pango_layout_set_single_paragraph_mode (layout, priv->single_paragraph);
1549
1550   if (cell_area)
1551     {
1552       /* Add options that affect appearance but not size */
1553       
1554       /* note that background doesn't go here, since it affects
1555        * background_area not the PangoLayout area
1556        */
1557       
1558       if (priv->foreground_set
1559           && (flags & GTK_CELL_RENDERER_SELECTED) == 0)
1560         {
1561           PangoColor color;
1562
1563           color.red = (guint16) (priv->foreground.red * 65535);
1564           color.green = (guint16) (priv->foreground.green * 65535);
1565           color.blue = (guint16) (priv->foreground.blue * 65535);
1566
1567           add_attr (attr_list,
1568                     pango_attr_foreground_new (color.red, color.green, color.blue));
1569         }
1570
1571       if (priv->strikethrough_set)
1572         add_attr (attr_list,
1573                   pango_attr_strikethrough_new (priv->strikethrough));
1574     }
1575
1576   add_attr (attr_list, pango_attr_font_desc_new (priv->font));
1577
1578   if (priv->scale_set &&
1579       priv->font_scale != 1.0)
1580     add_attr (attr_list, pango_attr_scale_new (priv->font_scale));
1581   
1582   if (priv->underline_set)
1583     uline = priv->underline_style;
1584   else
1585     uline = PANGO_UNDERLINE_NONE;
1586
1587   if (priv->language_set)
1588     add_attr (attr_list, pango_attr_language_new (priv->language));
1589   
1590   if ((flags & GTK_CELL_RENDERER_PRELIT) == GTK_CELL_RENDERER_PRELIT)
1591     {
1592       switch (uline)
1593         {
1594         case PANGO_UNDERLINE_NONE:
1595           uline = PANGO_UNDERLINE_SINGLE;
1596           break;
1597
1598         case PANGO_UNDERLINE_SINGLE:
1599           uline = PANGO_UNDERLINE_DOUBLE;
1600           break;
1601
1602         default:
1603           break;
1604         }
1605     }
1606
1607   if (uline != PANGO_UNDERLINE_NONE)
1608     add_attr (attr_list, pango_attr_underline_new (priv->underline_style));
1609
1610   if (priv->rise_set)
1611     add_attr (attr_list, pango_attr_rise_new (priv->rise));
1612
1613   /* Now apply the attributes as they will effect the outcome
1614    * of pango_layout_get_extents() */
1615   pango_layout_set_attributes (layout, attr_list);
1616   pango_attr_list_unref (attr_list);
1617
1618   if (priv->ellipsize_set)
1619     pango_layout_set_ellipsize (layout, priv->ellipsize);
1620   else
1621     pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_NONE);
1622
1623   if (priv->wrap_width != -1)
1624     {
1625       PangoRectangle rect;
1626       gint           width, text_width;
1627
1628       pango_layout_get_extents (layout, NULL, &rect);
1629       text_width = rect.width;
1630
1631       if (cell_area)
1632         width = (cell_area->width - xpad * 2) * PANGO_SCALE;
1633       else
1634         width = priv->wrap_width * PANGO_SCALE;
1635
1636       width = MIN (width, text_width);
1637
1638       pango_layout_set_width (layout, width);
1639       pango_layout_set_wrap (layout, priv->wrap_mode);
1640     }
1641   else
1642     {
1643       pango_layout_set_width (layout, -1);
1644       pango_layout_set_wrap (layout, PANGO_WRAP_CHAR);
1645     }
1646
1647   if (priv->align_set)
1648     pango_layout_set_alignment (layout, priv->align);
1649   else
1650     {
1651       PangoAlignment align;
1652
1653       if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
1654         align = PANGO_ALIGN_RIGHT;
1655       else
1656         align = PANGO_ALIGN_LEFT;
1657
1658       pango_layout_set_alignment (layout, align);
1659     }
1660   
1661   return layout;
1662 }
1663
1664
1665 static void
1666 get_size (GtkCellRenderer    *cell,
1667           GtkWidget          *widget,
1668           const GdkRectangle *cell_area,
1669           PangoLayout        *layout,
1670           gint               *x_offset,
1671           gint               *y_offset,
1672           gint               *width,
1673           gint               *height)
1674 {
1675   GtkCellRendererText *celltext = GTK_CELL_RENDERER_TEXT (cell);
1676   GtkCellRendererTextPrivate *priv = celltext->priv;
1677   PangoRectangle rect;
1678   gint xpad, ypad;
1679   gint cell_width, cell_height;
1680
1681   gtk_cell_renderer_get_padding (cell, &xpad, &ypad);
1682
1683   if (priv->calc_fixed_height)
1684     {
1685       PangoContext *context;
1686       PangoFontMetrics *metrics;
1687       PangoFontDescription *font_desc;
1688       gint row_height;
1689
1690       font_desc = pango_font_description_copy_static (gtk_widget_get_style (widget)->font_desc);
1691       pango_font_description_merge_static (font_desc, priv->font, TRUE);
1692
1693       if (priv->scale_set)
1694         pango_font_description_set_size (font_desc,
1695                                          priv->font_scale * pango_font_description_get_size (font_desc));
1696
1697       context = gtk_widget_get_pango_context (widget);
1698
1699       metrics = pango_context_get_metrics (context,
1700                                            font_desc,
1701                                            pango_context_get_language (context));
1702       row_height = (pango_font_metrics_get_ascent (metrics) +
1703                     pango_font_metrics_get_descent (metrics));
1704       pango_font_metrics_unref (metrics);
1705
1706       pango_font_description_free (font_desc);
1707
1708       gtk_cell_renderer_get_fixed_size (cell, &cell_width, &cell_height);
1709
1710       gtk_cell_renderer_set_fixed_size (cell,
1711                                         cell_width, 2 * ypad +
1712                                         priv->fixed_height_rows * PANGO_PIXELS (row_height));
1713       
1714       if (height)
1715         {
1716           *height = cell_height;
1717           height = NULL;
1718         }
1719       priv->calc_fixed_height = FALSE;
1720       if (width == NULL)
1721         return;
1722     }
1723   
1724   if (layout)
1725     g_object_ref (layout);
1726   else
1727     layout = get_layout (celltext, widget, NULL, 0);
1728
1729   pango_layout_get_pixel_extents (layout, NULL, &rect);
1730
1731   if (height)
1732     *height = ypad * 2 + rect.height;
1733
1734   /* The minimum size for ellipsized labels is ~ 3 chars */
1735   if (width)
1736     {
1737       if (priv->ellipsize || priv->width_chars > 0)
1738         {
1739           PangoContext *context;
1740           PangoFontMetrics *metrics;
1741           gint char_width;
1742
1743           context = pango_layout_get_context (layout);
1744           metrics = pango_context_get_metrics (context,
1745                                                gtk_widget_get_style (widget)->font_desc,
1746                                                pango_context_get_language (context));
1747
1748           char_width = pango_font_metrics_get_approximate_char_width (metrics);
1749           pango_font_metrics_unref (metrics);
1750           
1751           *width = xpad * 2 + (PANGO_PIXELS (char_width) * MAX (priv->width_chars, 3));
1752         }
1753       else
1754         {
1755           *width = xpad * 2 + rect.x + rect.width;
1756         }         
1757     }
1758
1759   if (cell_area)
1760     {
1761       gfloat xalign, yalign;
1762
1763       gtk_cell_renderer_get_alignment (cell, &xalign, &yalign);
1764
1765       if (x_offset)
1766         {
1767           if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
1768             *x_offset = (1.0 - xalign) * (cell_area->width - (rect.x + rect.width + (2 * xpad)));
1769           else 
1770             *x_offset = xalign * (cell_area->width - (rect.x + rect.width + (2 * xpad)));
1771
1772           if ((priv->ellipsize_set && priv->ellipsize != PANGO_ELLIPSIZE_NONE) || priv->wrap_width != -1)
1773             *x_offset = MAX(*x_offset, 0);
1774         }
1775       if (y_offset)
1776         {
1777           *y_offset = yalign * (cell_area->height - (rect.height + (2 * ypad)));
1778           *y_offset = MAX (*y_offset, 0);
1779         }
1780     }
1781   else
1782     {
1783       if (x_offset) *x_offset = 0;
1784       if (y_offset) *y_offset = 0;
1785     }
1786
1787   g_object_unref (layout);
1788 }
1789
1790 static void
1791 gtk_cell_renderer_text_render (GtkCellRenderer      *cell,
1792                                cairo_t              *cr,
1793                                GtkWidget            *widget,
1794                                const GdkRectangle   *background_area,
1795                                const GdkRectangle   *cell_area,
1796                                GtkCellRendererState  flags)
1797
1798 {
1799   GtkCellRendererText *celltext = GTK_CELL_RENDERER_TEXT (cell);
1800   GtkCellRendererTextPrivate *priv = celltext->priv;
1801   PangoLayout *layout;
1802   GtkStateType state;
1803   gint x_offset = 0;
1804   gint y_offset = 0;
1805   gint xpad, ypad;
1806
1807   layout = get_layout (celltext, widget, cell_area, flags);
1808   get_size (cell, widget, cell_area, layout, &x_offset, &y_offset, NULL, NULL);
1809
1810   if (!gtk_cell_renderer_get_sensitive (cell))
1811     {
1812       state = GTK_STATE_INSENSITIVE;
1813     }
1814   else if ((flags & GTK_CELL_RENDERER_SELECTED) == GTK_CELL_RENDERER_SELECTED)
1815     {
1816       if (gtk_widget_has_focus (widget))
1817         state = GTK_STATE_SELECTED;
1818       else
1819         state = GTK_STATE_ACTIVE;
1820     }
1821   else if ((flags & GTK_CELL_RENDERER_PRELIT) == GTK_CELL_RENDERER_PRELIT &&
1822            gtk_widget_get_state (widget) == GTK_STATE_PRELIGHT)
1823     {
1824       state = GTK_STATE_PRELIGHT;
1825     }
1826   else
1827     {
1828       if (gtk_widget_get_state (widget) == GTK_STATE_INSENSITIVE)
1829         state = GTK_STATE_INSENSITIVE;
1830       else
1831         state = GTK_STATE_NORMAL;
1832     }
1833
1834   if (priv->background_set && 
1835       (flags & GTK_CELL_RENDERER_SELECTED) == 0)
1836     {
1837       gdk_cairo_rectangle (cr, background_area);
1838       gdk_cairo_set_source_rgba (cr, &priv->background);
1839       cairo_fill (cr);
1840     }
1841
1842   gtk_cell_renderer_get_padding (cell, &xpad, &ypad);
1843
1844   if (priv->ellipsize_set && priv->ellipsize != PANGO_ELLIPSIZE_NONE)
1845     pango_layout_set_width (layout, 
1846                             (cell_area->width - x_offset - 2 * xpad) * PANGO_SCALE);
1847   else if (priv->wrap_width == -1)
1848     pango_layout_set_width (layout, -1);
1849
1850   gtk_paint_layout (gtk_widget_get_style (widget),
1851                           cr,
1852                           state,
1853                           TRUE,
1854                           widget,
1855                           "cellrenderertext",
1856                           cell_area->x + x_offset + xpad,
1857                           cell_area->y + y_offset + ypad,
1858                           layout);
1859
1860   g_object_unref (layout);
1861 }
1862
1863 static void
1864 gtk_cell_renderer_text_editing_done (GtkCellEditable *entry,
1865                                      gpointer         data)
1866 {
1867   GtkCellRendererTextPrivate *priv;
1868   const gchar *path;
1869   const gchar *new_text;
1870   gboolean canceled;
1871
1872   priv = GTK_CELL_RENDERER_TEXT (data)->priv;
1873
1874   priv->entry = NULL;
1875
1876   if (priv->focus_out_id > 0)
1877     {
1878       g_signal_handler_disconnect (entry, priv->focus_out_id);
1879       priv->focus_out_id = 0;
1880     }
1881
1882   if (priv->populate_popup_id > 0)
1883     {
1884       g_signal_handler_disconnect (entry, priv->populate_popup_id);
1885       priv->populate_popup_id = 0;
1886     }
1887
1888   if (priv->entry_menu_popdown_timeout)
1889     {
1890       g_source_remove (priv->entry_menu_popdown_timeout);
1891       priv->entry_menu_popdown_timeout = 0;
1892     }
1893
1894   g_object_get (entry,
1895                 "editing-canceled", &canceled,
1896                 NULL);
1897   gtk_cell_renderer_stop_editing (GTK_CELL_RENDERER (data), canceled);
1898
1899   if (canceled)
1900     return;
1901
1902   path = g_object_get_data (G_OBJECT (entry), GTK_CELL_RENDERER_TEXT_PATH);
1903   new_text = gtk_entry_get_text (GTK_ENTRY (entry));
1904
1905   g_signal_emit (data, text_cell_renderer_signals[EDITED], 0, path, new_text);
1906 }
1907
1908 static gboolean
1909 popdown_timeout (gpointer data)
1910 {
1911   GtkCellRendererTextPrivate *priv;
1912
1913   priv = GTK_CELL_RENDERER_TEXT (data)->priv;
1914
1915   priv->entry_menu_popdown_timeout = 0;
1916
1917   if (!gtk_widget_has_focus (priv->entry))
1918     gtk_cell_renderer_text_editing_done (GTK_CELL_EDITABLE (priv->entry), data);
1919
1920   return FALSE;
1921 }
1922
1923 static void
1924 gtk_cell_renderer_text_popup_unmap (GtkMenu *menu,
1925                                     gpointer data)
1926 {
1927   GtkCellRendererTextPrivate *priv;
1928
1929   priv = GTK_CELL_RENDERER_TEXT (data)->priv;
1930
1931   priv->in_entry_menu = FALSE;
1932
1933   if (priv->entry_menu_popdown_timeout)
1934     return;
1935
1936   priv->entry_menu_popdown_timeout = gdk_threads_add_timeout (500, popdown_timeout,
1937                                                     data);
1938 }
1939
1940 static void
1941 gtk_cell_renderer_text_populate_popup (GtkEntry *entry,
1942                                        GtkMenu  *menu,
1943                                        gpointer  data)
1944 {
1945   GtkCellRendererTextPrivate *priv;
1946
1947   priv = GTK_CELL_RENDERER_TEXT (data)->priv;
1948
1949   if (priv->entry_menu_popdown_timeout)
1950     {
1951       g_source_remove (priv->entry_menu_popdown_timeout);
1952       priv->entry_menu_popdown_timeout = 0;
1953     }
1954
1955   priv->in_entry_menu = TRUE;
1956
1957   g_signal_connect (menu, "unmap",
1958                     G_CALLBACK (gtk_cell_renderer_text_popup_unmap), data);
1959 }
1960
1961 static gboolean
1962 gtk_cell_renderer_text_focus_out_event (GtkWidget *entry,
1963                                         GdkEvent  *event,
1964                                         gpointer   data)
1965 {
1966   GtkCellRendererTextPrivate *priv;
1967
1968   priv = GTK_CELL_RENDERER_TEXT (data)->priv;
1969
1970   if (priv->in_entry_menu)
1971     return FALSE;
1972
1973   g_object_set (entry,
1974                 "editing-canceled", TRUE,
1975                 NULL);
1976   gtk_cell_editable_editing_done (GTK_CELL_EDITABLE (entry));
1977   gtk_cell_editable_remove_widget (GTK_CELL_EDITABLE (entry));
1978
1979   /* entry needs focus-out-event */
1980   return FALSE;
1981 }
1982
1983 static GtkCellEditable *
1984 gtk_cell_renderer_text_start_editing (GtkCellRenderer      *cell,
1985                                       GdkEvent             *event,
1986                                       GtkWidget            *widget,
1987                                       const gchar          *path,
1988                                       const GdkRectangle   *background_area,
1989                                       const GdkRectangle   *cell_area,
1990                                       GtkCellRendererState  flags)
1991 {
1992   GtkRequisition requisition;
1993   GtkCellRendererText *celltext;
1994   GtkCellRendererTextPrivate *priv;
1995   gfloat xalign, yalign;
1996
1997   celltext = GTK_CELL_RENDERER_TEXT (cell);
1998   priv = celltext->priv;
1999
2000   /* If the cell isn't editable we return NULL. */
2001   if (priv->editable == FALSE)
2002     return NULL;
2003
2004   gtk_cell_renderer_get_alignment (cell, &xalign, &yalign);
2005
2006   priv->entry = gtk_entry_new ();
2007   gtk_entry_set_has_frame (GTK_ENTRY (priv->entry), FALSE);
2008   gtk_entry_set_alignment (GTK_ENTRY (priv->entry), xalign);
2009
2010   if (priv->text)
2011     gtk_entry_set_text (GTK_ENTRY (priv->entry), priv->text);
2012   g_object_set_data_full (G_OBJECT (priv->entry), I_(GTK_CELL_RENDERER_TEXT_PATH), g_strdup (path), g_free);
2013   
2014   gtk_editable_select_region (GTK_EDITABLE (priv->entry), 0, -1);
2015
2016   gtk_widget_get_preferred_size (priv->entry, &requisition, NULL);
2017   if (requisition.height < cell_area->height)
2018     {
2019       GtkBorder *style_border;
2020       GtkBorder border;
2021
2022       gtk_widget_style_get (priv->entry,
2023                             "inner-border", &style_border,
2024                             NULL);
2025
2026       if (style_border)
2027         {
2028           border = *style_border;
2029           g_boxed_free (GTK_TYPE_BORDER, style_border);
2030         }
2031       else
2032         {
2033           /* Since boxed style properties can't have default values ... */
2034           border.left = 2;
2035           border.right = 2;
2036         }
2037
2038       border.top = (cell_area->height - requisition.height) / 2;
2039       border.bottom = (cell_area->height - requisition.height) / 2;
2040       gtk_entry_set_inner_border (GTK_ENTRY (priv->entry), &border);
2041     }
2042
2043   priv->in_entry_menu = FALSE;
2044   if (priv->entry_menu_popdown_timeout)
2045     {
2046       g_source_remove (priv->entry_menu_popdown_timeout);
2047       priv->entry_menu_popdown_timeout = 0;
2048     }
2049
2050   g_signal_connect (priv->entry,
2051                     "editing-done",
2052                     G_CALLBACK (gtk_cell_renderer_text_editing_done),
2053                     celltext);
2054   priv->focus_out_id = g_signal_connect_after (priv->entry, "focus-out-event",
2055                                                G_CALLBACK (gtk_cell_renderer_text_focus_out_event),
2056                                                celltext);
2057   priv->populate_popup_id =
2058     g_signal_connect (priv->entry, "populate-popup",
2059                       G_CALLBACK (gtk_cell_renderer_text_populate_popup),
2060                       celltext);
2061  
2062   gtk_widget_show (priv->entry);
2063
2064   return GTK_CELL_EDITABLE (priv->entry);
2065 }
2066
2067 /**
2068  * gtk_cell_renderer_text_set_fixed_height_from_font:
2069  * @renderer: A #GtkCellRendererText
2070  * @number_of_rows: Number of rows of text each cell renderer is allocated, or -1
2071  * 
2072  * Sets the height of a renderer to explicitly be determined by the "font" and
2073  * "y_pad" property set on it.  Further changes in these properties do not
2074  * affect the height, so they must be accompanied by a subsequent call to this
2075  * function.  Using this function is unflexible, and should really only be used
2076  * if calculating the size of a cell is too slow (ie, a massive number of cells
2077  * displayed).  If @number_of_rows is -1, then the fixed height is unset, and
2078  * the height is determined by the properties again.
2079  **/
2080 void
2081 gtk_cell_renderer_text_set_fixed_height_from_font (GtkCellRendererText *renderer,
2082                                                    gint                 number_of_rows)
2083 {
2084   GtkCellRendererTextPrivate *priv;
2085   GtkCellRenderer *cell;
2086
2087   g_return_if_fail (GTK_IS_CELL_RENDERER_TEXT (renderer));
2088   g_return_if_fail (number_of_rows == -1 || number_of_rows > 0);
2089
2090   cell = GTK_CELL_RENDERER (renderer);
2091   priv = renderer->priv;
2092
2093   if (number_of_rows == -1)
2094     {
2095       gint width, height;
2096
2097       gtk_cell_renderer_get_fixed_size (cell, &width, &height);
2098       gtk_cell_renderer_set_fixed_size (cell, width, -1);
2099     }
2100   else
2101     {
2102       priv->fixed_height_rows = number_of_rows;
2103       priv->calc_fixed_height = TRUE;
2104     }
2105 }
2106
2107 static void
2108 gtk_cell_renderer_text_get_preferred_width (GtkCellRenderer *cell,
2109                                             GtkWidget       *widget,
2110                                             gint            *minimum_size,
2111                                             gint            *natural_size)
2112 {
2113   GtkCellRendererTextPrivate    *priv;
2114   GtkCellRendererText        *celltext;
2115   GtkStyle                   *style;
2116   PangoLayout                *layout;
2117   PangoContext               *context;
2118   PangoFontMetrics           *metrics;
2119   PangoRectangle              rect;
2120   gint char_width, digit_width, char_pixels, text_width, ellipsize_chars, guess_width, xpad;
2121   gint min_width, nat_width;
2122
2123   /* "width-chars" Hard-coded minimum width:
2124    *    - minimum size should be MAX (width-chars, strlen ("..."));
2125    *    - natural size should be MAX (width-chars, strlen (label->text));
2126    *
2127    * "wrap-width" User specified natural wrap width
2128    *    - minimum size should be MAX (width-chars, 0)
2129    *    - natural size should be MIN (wrap-width, strlen (label->text))
2130    */
2131
2132   celltext = GTK_CELL_RENDERER_TEXT (cell);
2133   priv = celltext->priv;
2134
2135   style = gtk_widget_get_style (widget);
2136
2137   gtk_cell_renderer_get_padding (cell, &xpad, NULL);
2138
2139   layout = get_layout (celltext, widget, NULL, 0);
2140
2141   /* Get the layout with the text possibly wrapping at wrap_width */
2142   pango_layout_get_pixel_extents (layout, NULL, &rect);
2143   guess_width = rect.width;
2144
2145   /* Fetch the length of the complete unwrapped text */
2146   pango_layout_set_width (layout, -1);
2147   pango_layout_get_extents (layout, NULL, &rect);
2148   text_width = rect.width;
2149
2150   /* Fetch the average size of a charachter */
2151   context = pango_layout_get_context (layout);
2152   metrics = pango_context_get_metrics (context, style->font_desc,
2153                                        pango_context_get_language (context));
2154   
2155   char_width = pango_font_metrics_get_approximate_char_width (metrics);
2156   digit_width = pango_font_metrics_get_approximate_digit_width (metrics);
2157   char_pixels = MAX (char_width, digit_width);
2158
2159   pango_font_metrics_unref (metrics);
2160   g_object_unref (layout);
2161
2162   /* enforce minimum width for ellipsized labels at ~3 chars */
2163   if (priv->ellipsize_set && priv->ellipsize != PANGO_ELLIPSIZE_NONE)
2164     ellipsize_chars = 3;
2165   else
2166     ellipsize_chars = 0;
2167   
2168   if ((priv->ellipsize_set && priv->ellipsize != PANGO_ELLIPSIZE_NONE) || priv->width_chars > 0)
2169     min_width = 
2170       xpad * 2 + (PANGO_PIXELS (char_width) * MAX (priv->width_chars, ellipsize_chars));
2171   /* If no width-chars set, minimum for wrapping text will be the wrap-width */
2172   else if (priv->wrap_width > -1)
2173     min_width = xpad * 2 + rect.x + priv->wrap_width;
2174   else
2175     min_width = xpad * 2 + rect.x + guess_width;
2176
2177   if (priv->width_chars > 0)
2178     nat_width = xpad * 2 + 
2179       MAX ((PANGO_PIXELS (char_width) * priv->width_chars), PANGO_PIXELS (text_width));
2180   else
2181     nat_width = xpad * 2 + PANGO_PIXELS (text_width);
2182
2183   nat_width = MAX (nat_width, min_width);
2184   
2185   if (priv->max_width_chars > 0)
2186     {
2187       gint max_width = xpad * 2 + PANGO_PIXELS (char_width) * priv->max_width_chars;
2188       
2189       min_width = MIN (min_width, max_width);
2190       nat_width = MIN (nat_width, max_width);
2191     }
2192
2193   if (minimum_size)
2194     *minimum_size = min_width;
2195
2196   if (natural_size)
2197     *natural_size = nat_width;
2198
2199 }
2200
2201 static void
2202 gtk_cell_renderer_text_get_preferred_height_for_width (GtkCellRenderer *cell,
2203                                                        GtkWidget       *widget,
2204                                                        gint             width,
2205                                                        gint            *minimum_height,
2206                                                        gint            *natural_height)
2207 {
2208   GtkCellRendererTextPrivate    *priv;
2209   GtkCellRendererText        *celltext;
2210   PangoLayout                *layout;
2211   gint                        text_height, xpad, ypad;
2212
2213
2214   celltext = GTK_CELL_RENDERER_TEXT (cell);
2215   priv = celltext->priv;
2216
2217   gtk_cell_renderer_get_padding (cell, &xpad, &ypad);
2218
2219   layout = get_layout (celltext, widget, NULL, 0);
2220
2221   pango_layout_set_width (layout, (width - xpad * 2) * PANGO_SCALE);
2222   pango_layout_get_pixel_size (layout, NULL, &text_height);
2223
2224   if (minimum_height)
2225     *minimum_height = text_height + ypad * 2;
2226
2227   if (natural_height)
2228     *natural_height = text_height + ypad * 2;
2229
2230   g_object_unref (layout);
2231 }
2232
2233 static void
2234 gtk_cell_renderer_text_get_preferred_height (GtkCellRenderer *cell,
2235                                              GtkWidget       *widget,
2236                                              gint            *minimum_size,
2237                                              gint            *natural_size)
2238 {
2239   gint min_width;
2240
2241   /* Thankfully cell renderers dont rotate, so they only have to do
2242    * height-for-width and not the opposite. Here we have only to return
2243    * the height for the base minimum width of the renderer.
2244    *
2245    * Note this code path wont be followed by GtkTreeView which is
2246    * height-for-width specifically.
2247    */
2248   gtk_cell_renderer_get_preferred_width (cell, widget, &min_width, NULL);
2249   gtk_cell_renderer_text_get_preferred_height_for_width (cell, widget, min_width,
2250                                                          minimum_size, natural_size);
2251 }
2252