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