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