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