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