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