]> Pileus Git - ~andy/gtk/blob - gtk/gtktexttag.c
Fixes #136082 and #135265, patch by Morten Welinder.
[~andy/gtk] / gtk / gtktexttag.c
1 /* gtktexttag.c - text tag object
2  *
3  * Copyright (c) 1992-1994 The Regents of the University of California.
4  * Copyright (c) 1994-1997 Sun Microsystems, Inc.
5  * Copyright (c) 2000      Red Hat, Inc.
6  * Tk -> Gtk port by Havoc Pennington <hp@redhat.com>
7  *
8  * This software is copyrighted by the Regents of the University of
9  * California, Sun Microsystems, Inc., and other parties.  The
10  * following terms apply to all files associated with the software
11  * unless explicitly disclaimed in individual files.
12  *
13  * The authors hereby grant permission to use, copy, modify,
14  * distribute, and license this software and its documentation for any
15  * purpose, provided that existing copyright notices are retained in
16  * all copies and that this notice is included verbatim in any
17  * distributions. No written agreement, license, or royalty fee is
18  * required for any of the authorized uses.  Modifications to this
19  * software may be copyrighted by their authors and need not follow
20  * the licensing terms described here, provided that the new terms are
21  * clearly indicated on the first page of each file where they apply.
22  *
23  * IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY
24  * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
25  * DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION,
26  * OR ANY DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED
27  * OF THE POSSIBILITY OF SUCH DAMAGE.
28  *
29  * THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
30  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
31  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
32  * NON-INFRINGEMENT.  THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
33  * AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
34  * MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
35  *
36  * GOVERNMENT USE: If you are acquiring this software on behalf of the
37  * U.S. government, the Government shall have only "Restricted Rights"
38  * in the software and related documentation as defined in the Federal
39  * Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2).  If you
40  * are acquiring the software on behalf of the Department of Defense,
41  * the software shall be classified as "Commercial Computer Software"
42  * and the Government shall have only "Restricted Rights" as defined
43  * in Clause 252.227-7013 (c) (1) of DFARs.  Notwithstanding the
44  * foregoing, the authors grant the U.S. Government and others acting
45  * in its behalf permission to use and distribute the software in
46  * accordance with the terms specified in this license.
47  *
48  */
49
50 #include <config.h>
51 #include "gtkmain.h"
52 #include "gtktexttag.h"
53 #include "gtktexttypes.h"
54 #include "gtktexttagtable.h"
55 #include "gtkmain.h"
56 #include "gtkintl.h"
57 #include "gtkmarshalers.h"
58
59 #include <stdlib.h>
60 #include <string.h>
61
62 enum {
63   EVENT,
64   LAST_SIGNAL
65 };
66
67 enum {
68   PROP_0,
69   /* Construct args */
70   PROP_NAME,
71
72   /* Style args */
73   PROP_BACKGROUND,
74   PROP_FOREGROUND,
75   PROP_BACKGROUND_GDK,
76   PROP_FOREGROUND_GDK,
77   PROP_BACKGROUND_STIPPLE,
78   PROP_FOREGROUND_STIPPLE,
79   PROP_FONT,
80   PROP_FONT_DESC,
81   PROP_FAMILY,
82   PROP_STYLE,
83   PROP_VARIANT,
84   PROP_WEIGHT,
85   PROP_STRETCH,
86   PROP_SIZE,
87   PROP_SIZE_POINTS,
88   PROP_SCALE,
89   PROP_PIXELS_ABOVE_LINES,
90   PROP_PIXELS_BELOW_LINES,
91   PROP_PIXELS_INSIDE_WRAP,
92   PROP_EDITABLE,
93   PROP_WRAP_MODE,
94   PROP_JUSTIFICATION,
95   PROP_DIRECTION,
96   PROP_LEFT_MARGIN,
97   PROP_INDENT,
98   PROP_STRIKETHROUGH,
99   PROP_RIGHT_MARGIN,
100   PROP_UNDERLINE,
101   PROP_RISE,
102   PROP_BG_FULL_HEIGHT,
103   PROP_LANGUAGE,
104   PROP_TABS,
105   PROP_INVISIBLE,
106   
107   /* Whether-a-style-arg-is-set args */
108   PROP_BACKGROUND_SET,
109   PROP_FOREGROUND_SET,
110   PROP_BACKGROUND_STIPPLE_SET,
111   PROP_FOREGROUND_STIPPLE_SET,
112   PROP_FAMILY_SET,
113   PROP_STYLE_SET,
114   PROP_VARIANT_SET,
115   PROP_WEIGHT_SET,
116   PROP_STRETCH_SET,
117   PROP_SIZE_SET,
118   PROP_SCALE_SET,
119   PROP_PIXELS_ABOVE_LINES_SET,
120   PROP_PIXELS_BELOW_LINES_SET,
121   PROP_PIXELS_INSIDE_WRAP_SET,
122   PROP_EDITABLE_SET,
123   PROP_WRAP_MODE_SET,
124   PROP_JUSTIFICATION_SET,
125   PROP_LEFT_MARGIN_SET,
126   PROP_INDENT_SET,
127   PROP_STRIKETHROUGH_SET,
128   PROP_RIGHT_MARGIN_SET,
129   PROP_UNDERLINE_SET,
130   PROP_RISE_SET,
131   PROP_BG_FULL_HEIGHT_SET,
132   PROP_LANGUAGE_SET,
133   PROP_TABS_SET,
134   PROP_INVISIBLE_SET,
135
136   LAST_ARG
137 };
138 static void gtk_text_tag_init         (GtkTextTag      *text_tag);
139 static void gtk_text_tag_class_init   (GtkTextTagClass *klass);
140 static void gtk_text_tag_finalize     (GObject         *object);
141 static void gtk_text_tag_set_property (GObject         *object,
142                                        guint            prop_id,
143                                        const GValue    *value,
144                                        GParamSpec      *pspec);
145 static void gtk_text_tag_get_property (GObject         *object,
146                                        guint            prop_id,
147                                        GValue          *value,
148                                        GParamSpec      *pspec);
149
150 static GObjectClass *parent_class = NULL;
151 static guint signals[LAST_SIGNAL] = { 0 };
152
153 GType
154 gtk_text_tag_get_type (void)
155 {
156   static GType our_type = 0;
157
158   if (our_type == 0)
159     {
160       static const GTypeInfo our_info =
161       {
162         sizeof (GtkTextTagClass),
163         (GBaseInitFunc) NULL,
164         (GBaseFinalizeFunc) NULL,
165         (GClassInitFunc) gtk_text_tag_class_init,
166         NULL,           /* class_finalize */
167         NULL,           /* class_data */
168         sizeof (GtkTextTag),
169         0,              /* n_preallocs */
170         (GInstanceInitFunc) gtk_text_tag_init
171       };
172
173       our_type = g_type_register_static (G_TYPE_OBJECT, "GtkTextTag",
174                                          &our_info, 0);
175     }
176
177   return our_type;
178 }
179
180 static void
181 gtk_text_tag_class_init (GtkTextTagClass *klass)
182 {
183   GObjectClass *object_class = G_OBJECT_CLASS (klass);
184
185   parent_class = g_type_class_peek_parent (klass);
186
187   object_class->set_property = gtk_text_tag_set_property;
188   object_class->get_property = gtk_text_tag_get_property;
189   
190   object_class->finalize = gtk_text_tag_finalize;
191
192   /* Construct */
193   g_object_class_install_property (object_class,
194                                    PROP_NAME,
195                                    g_param_spec_string ("name",
196                                                         P_("Tag name"),
197                                                         P_("Name used to refer to the text tag. NULL for anonymous tags"),
198                                                         NULL,
199                                                         G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
200
201   /* Style args */
202
203   g_object_class_install_property (object_class,
204                                    PROP_BACKGROUND,
205                                    g_param_spec_string ("background",
206                                                         P_("Background color name"),
207                                                         P_("Background color as a string"),
208                                                         NULL,
209                                                         G_PARAM_WRITABLE));
210
211   g_object_class_install_property (object_class,
212                                    PROP_BACKGROUND_GDK,
213                                    g_param_spec_boxed ("background_gdk",
214                                                        P_("Background color"),
215                                                        P_("Background color as a (possibly unallocated) GdkColor"),
216                                                        GDK_TYPE_COLOR,
217                                                        G_PARAM_READABLE | G_PARAM_WRITABLE));
218
219   g_object_class_install_property (object_class,
220                                    PROP_BG_FULL_HEIGHT,
221                                    g_param_spec_boolean ("background_full_height",
222                                                          P_("Background full height"),
223                                                          P_("Whether the background color fills the entire line height or only the height of the tagged characters"),
224                                                          FALSE,
225                                                          G_PARAM_READABLE | G_PARAM_WRITABLE));
226
227   
228   g_object_class_install_property (object_class,
229                                    PROP_BACKGROUND_STIPPLE,
230                                    g_param_spec_object ("background_stipple",
231                                                         P_("Background stipple mask"),
232                                                         P_("Bitmap to use as a mask when drawing the text background"),
233                                                         GDK_TYPE_PIXMAP,
234                                                         G_PARAM_READABLE | G_PARAM_WRITABLE));  
235
236
237   g_object_class_install_property (object_class,
238                                    PROP_FOREGROUND,
239                                    g_param_spec_string ("foreground",
240                                                         P_("Foreground color name"),
241                                                         P_("Foreground color as a string"),
242                                                         NULL,
243                                                         G_PARAM_WRITABLE));
244
245   g_object_class_install_property (object_class,
246                                    PROP_FOREGROUND_GDK,
247                                    g_param_spec_boxed ("foreground_gdk",
248                                                        P_("Foreground color"),
249                                                        P_("Foreground color as a (possibly unallocated) GdkColor"),
250                                                        GDK_TYPE_COLOR,
251                                                        G_PARAM_READABLE | G_PARAM_WRITABLE));
252
253   
254   g_object_class_install_property (object_class,
255                                    PROP_FOREGROUND_STIPPLE,
256                                    g_param_spec_object ("foreground_stipple",
257                                                         P_("Foreground stipple mask"),
258                                                         P_("Bitmap to use as a mask when drawing the text foreground"),
259                                                         GDK_TYPE_PIXMAP,
260                                                         G_PARAM_READABLE | G_PARAM_WRITABLE));  
261   
262   g_object_class_install_property (object_class,
263                                    PROP_DIRECTION,
264                                    g_param_spec_enum ("direction",
265                                                       P_("Text direction"),
266                                                       P_("Text direction, e.g. right-to-left or left-to-right"),
267                                                       GTK_TYPE_TEXT_DIRECTION,
268                                                       GTK_TEXT_DIR_LTR,
269                                                       G_PARAM_READABLE | G_PARAM_WRITABLE));
270
271   g_object_class_install_property (object_class,
272                                    PROP_EDITABLE,
273                                    g_param_spec_boolean ("editable",
274                                                          P_("Editable"),
275                                                          P_("Whether the text can be modified by the user"),
276                                                          TRUE,
277                                                          G_PARAM_READABLE | G_PARAM_WRITABLE));
278
279   g_object_class_install_property (object_class,
280                                    PROP_FONT,
281                                    g_param_spec_string ("font",
282                                                         P_("Font"),
283                                                         P_("Font description as a string, e.g. \"Sans Italic 12\""),
284                                                         NULL,
285                                                         G_PARAM_READABLE | G_PARAM_WRITABLE));
286
287   g_object_class_install_property (object_class,
288                                    PROP_FONT_DESC,
289                                    g_param_spec_boxed ("font_desc",
290                                                        P_("Font"),
291                                                        P_("Font description as a PangoFontDescription struct"),
292                                                        PANGO_TYPE_FONT_DESCRIPTION,
293                                                        G_PARAM_READABLE | G_PARAM_WRITABLE));
294
295   
296   g_object_class_install_property (object_class,
297                                    PROP_FAMILY,
298                                    g_param_spec_string ("family",
299                                                         P_("Font family"),
300                                                         P_("Name of the font family, e.g. Sans, Helvetica, Times, Monospace"),
301                                                         NULL,
302                                                         G_PARAM_READABLE | G_PARAM_WRITABLE));
303
304   g_object_class_install_property (object_class,
305                                    PROP_STYLE,
306                                    g_param_spec_enum ("style",
307                                                       P_("Font style"),
308                                                       P_("Font style as a PangoStyle, e.g. PANGO_STYLE_ITALIC"),
309                                                       PANGO_TYPE_STYLE,
310                                                       PANGO_STYLE_NORMAL,
311                                                       G_PARAM_READABLE | G_PARAM_WRITABLE));
312
313   g_object_class_install_property (object_class,
314                                    PROP_VARIANT,
315                                    g_param_spec_enum ("variant",
316                                                      P_("Font variant"),
317                                                      P_("Font variant as a PangoVariant, e.g. PANGO_VARIANT_SMALL_CAPS"),
318                                                       PANGO_TYPE_VARIANT,
319                                                       PANGO_VARIANT_NORMAL,
320                                                       G_PARAM_READABLE | G_PARAM_WRITABLE));
321   
322   g_object_class_install_property (object_class,
323                                    PROP_WEIGHT,
324                                    g_param_spec_int ("weight",
325                                                      P_("Font weight"),
326                                                      P_("Font weight as an integer, see predefined values in PangoWeight; for example, PANGO_WEIGHT_BOLD"),
327                                                      0,
328                                                      G_MAXINT,
329                                                      PANGO_WEIGHT_NORMAL,
330                                                      G_PARAM_READABLE | G_PARAM_WRITABLE));
331   
332
333   g_object_class_install_property (object_class,
334                                    PROP_STRETCH,
335                                    g_param_spec_enum ("stretch",
336                                                       P_("Font stretch"),
337                                                       P_("Font stretch as a PangoStretch, e.g. PANGO_STRETCH_CONDENSED"),
338                                                       PANGO_TYPE_STRETCH,
339                                                       PANGO_STRETCH_NORMAL,
340                                                       G_PARAM_READABLE | G_PARAM_WRITABLE));
341   
342   g_object_class_install_property (object_class,
343                                    PROP_SIZE,
344                                    g_param_spec_int ("size",
345                                                      P_("Font size"),
346                                                      P_("Font size in Pango units"),
347                                                      0,
348                                                      G_MAXINT,
349                                                      0,
350                                                      G_PARAM_READABLE | G_PARAM_WRITABLE));
351
352   g_object_class_install_property (object_class,
353                                    PROP_SCALE,
354                                    g_param_spec_double ("scale",
355                                                         P_("Font scale"),
356                                                         P_("Font size as a scale factor relative to the default font size. This properly adapts to theme changes etc. so is recommended. Pango predefines some scales such as PANGO_SCALE_X_LARGE"),
357                                                         0.0,
358                                                         G_MAXDOUBLE,
359                                                         1.0,
360                                                         G_PARAM_READABLE | G_PARAM_WRITABLE));
361   
362   g_object_class_install_property (object_class,
363                                    PROP_SIZE_POINTS,
364                                    g_param_spec_double ("size_points",
365                                                         P_("Font points"),
366                                                         P_("Font size in points"),
367                                                         0.0,
368                                                         G_MAXDOUBLE,
369                                                         0.0,
370                                                         G_PARAM_READABLE | G_PARAM_WRITABLE));  
371
372   g_object_class_install_property (object_class,
373                                    PROP_JUSTIFICATION,
374                                    g_param_spec_enum ("justification",
375                                                       P_("Justification"),
376                                                       P_("Left, right, or center justification"),
377                                                       GTK_TYPE_JUSTIFICATION,
378                                                       GTK_JUSTIFY_LEFT,
379                                                       G_PARAM_READABLE | G_PARAM_WRITABLE));
380   
381   g_object_class_install_property (object_class,
382                                    PROP_LANGUAGE,
383                                    g_param_spec_string ("language",
384                                                         P_("Language"),
385                                                         P_("The language this text is in, as an ISO code. Pango can use this as a hint when rendering the text. If you don't understand this parameter, you probably don't need it"),
386                                                         NULL,
387                                                         G_PARAM_READABLE | G_PARAM_WRITABLE));  
388
389   g_object_class_install_property (object_class,
390                                    PROP_LEFT_MARGIN,
391                                    g_param_spec_int ("left_margin",
392                                                      P_("Left margin"),
393                                                      P_("Width of the left margin in pixels"),
394                                                      0,
395                                                      G_MAXINT,
396                                                      0,
397                                                      G_PARAM_READABLE | G_PARAM_WRITABLE));
398
399   g_object_class_install_property (object_class,
400                                    PROP_RIGHT_MARGIN,
401                                    g_param_spec_int ("right_margin",
402                                                      P_("Right margin"),
403                                                      P_("Width of the right margin in pixels"),
404                                                      0,
405                                                      G_MAXINT,
406                                                      0,
407                                                      G_PARAM_READABLE | G_PARAM_WRITABLE));
408
409   
410   g_object_class_install_property (object_class,
411                                    PROP_INDENT,
412                                    g_param_spec_int ("indent",
413                                                      P_("Indent"),
414                                                      P_("Amount to indent the paragraph, in pixels"),
415                                                      G_MININT,
416                                                      G_MAXINT,
417                                                      0,
418                                                      G_PARAM_READABLE | G_PARAM_WRITABLE));
419
420   
421   g_object_class_install_property (object_class,
422                                    PROP_RISE,
423                                    g_param_spec_int ("rise",
424                                                      P_("Rise"),
425                                                      P_("Offset of text above the baseline (below the baseline if rise is negative) in pixels"),
426                                                      G_MININT,
427                                                      G_MAXINT,
428                                                      0,
429                                                      G_PARAM_READABLE | G_PARAM_WRITABLE));
430
431   g_object_class_install_property (object_class,
432                                    PROP_PIXELS_ABOVE_LINES,
433                                    g_param_spec_int ("pixels_above_lines",
434                                                      P_("Pixels above lines"),
435                                                      P_("Pixels of blank space above paragraphs"),
436                                                      0,
437                                                      G_MAXINT,
438                                                      0,
439                                                      G_PARAM_READABLE | G_PARAM_WRITABLE));
440   
441   g_object_class_install_property (object_class,
442                                    PROP_PIXELS_BELOW_LINES,
443                                    g_param_spec_int ("pixels_below_lines",
444                                                      P_("Pixels below lines"),
445                                                      P_("Pixels of blank space below paragraphs"),
446                                                      0,
447                                                      G_MAXINT,
448                                                      0,
449                                                      G_PARAM_READABLE | G_PARAM_WRITABLE));
450
451   g_object_class_install_property (object_class,
452                                    PROP_PIXELS_INSIDE_WRAP,
453                                    g_param_spec_int ("pixels_inside_wrap",
454                                                      P_("Pixels inside wrap"),
455                                                      P_("Pixels of blank space between wrapped lines in a paragraph"),
456                                                      0,
457                                                      G_MAXINT,
458                                                      0,
459                                                      G_PARAM_READABLE | G_PARAM_WRITABLE));
460
461   g_object_class_install_property (object_class,
462                                    PROP_STRIKETHROUGH,
463                                    g_param_spec_boolean ("strikethrough",
464                                                          P_("Strikethrough"),
465                                                          P_("Whether to strike through the text"),
466                                                          FALSE,
467                                                          G_PARAM_READABLE | G_PARAM_WRITABLE));
468   
469   g_object_class_install_property (object_class,
470                                    PROP_UNDERLINE,
471                                    g_param_spec_enum ("underline",
472                                                       P_("Underline"),
473                                                       P_("Style of underline for this text"),
474                                                       PANGO_TYPE_UNDERLINE,
475                                                       PANGO_UNDERLINE_NONE,
476                                                       G_PARAM_READABLE | G_PARAM_WRITABLE));
477   
478   g_object_class_install_property (object_class,
479                                    PROP_WRAP_MODE,
480                                    g_param_spec_enum ("wrap_mode",
481                                                      P_("Wrap mode"),
482                                                      P_("Whether to wrap lines never, at word boundaries, or at character boundaries"),
483                                                       GTK_TYPE_WRAP_MODE,
484                                                       GTK_WRAP_NONE,
485                                                       G_PARAM_READABLE | G_PARAM_WRITABLE));
486   
487
488   g_object_class_install_property (object_class,
489                                    PROP_TABS,
490                                    g_param_spec_boxed ("tabs",
491                                                        P_("Tabs"),
492                                                        P_("Custom tabs for this text"),
493                                                        PANGO_TYPE_TAB_ARRAY,
494                                                        G_PARAM_READABLE | G_PARAM_WRITABLE));
495   
496   g_object_class_install_property (object_class,
497                                    PROP_INVISIBLE,
498                                    g_param_spec_boolean ("invisible",
499                                                          P_("Invisible"),
500                                                          P_("Whether this text is hidden. Not implemented in GTK 2.0"),
501                                                          FALSE,
502                                                          G_PARAM_READABLE | G_PARAM_WRITABLE));
503
504   /* Style props are set or not */
505
506 #define ADD_SET_PROP(propname, propval, nick, blurb) g_object_class_install_property (object_class, propval, g_param_spec_boolean (propname, nick, blurb, FALSE, G_PARAM_READABLE | G_PARAM_WRITABLE))
507
508   ADD_SET_PROP ("background_set", PROP_BACKGROUND_SET,
509                 P_("Background set"),
510                 P_("Whether this tag affects the background color"));
511   
512   ADD_SET_PROP ("background_full_height_set", PROP_BG_FULL_HEIGHT_SET,
513                 P_("Background full height set"),
514                 P_("Whether this tag affects background height"));
515
516   ADD_SET_PROP ("background_stipple_set", PROP_BACKGROUND_STIPPLE_SET,
517                 P_("Background stipple set"),
518                 P_("Whether this tag affects the background stipple"));  
519
520   ADD_SET_PROP ("foreground_set", PROP_FOREGROUND_SET,
521                 P_("Foreground set"),
522                 P_("Whether this tag affects the foreground color"));
523
524   ADD_SET_PROP ("foreground_stipple_set", PROP_FOREGROUND_STIPPLE_SET,
525                 P_("Foreground stipple set"),
526                 P_("Whether this tag affects the foreground stipple"));
527   
528   ADD_SET_PROP ("editable_set", PROP_EDITABLE_SET,
529                 P_("Editability set"),
530                 P_("Whether this tag affects text editability"));
531
532   ADD_SET_PROP ("family_set", PROP_FAMILY_SET,
533                 P_("Font family set"),
534                 P_("Whether this tag affects the font family"));  
535
536   ADD_SET_PROP ("style_set", PROP_STYLE_SET,
537                 P_("Font style set"),
538                 P_("Whether this tag affects the font style"));
539
540   ADD_SET_PROP ("variant_set", PROP_VARIANT_SET,
541                 P_("Font variant set"),
542                 P_("Whether this tag affects the font variant"));
543
544   ADD_SET_PROP ("weight_set", PROP_WEIGHT_SET,
545                 P_("Font weight set"),
546                 P_("Whether this tag affects the font weight"));
547
548   ADD_SET_PROP ("stretch_set", PROP_STRETCH_SET,
549                 P_("Font stretch set"),
550                 P_("Whether this tag affects the font stretch"));
551
552   ADD_SET_PROP ("size_set", PROP_SIZE_SET,
553                 P_("Font size set"),
554                 P_("Whether this tag affects the font size"));
555
556   ADD_SET_PROP ("scale_set", PROP_SCALE_SET,
557                 P_("Font scale set"),
558                 P_("Whether this tag scales the font size by a factor"));
559   
560   ADD_SET_PROP ("justification_set", PROP_JUSTIFICATION_SET,
561                 P_("Justification set"),
562                 P_("Whether this tag affects paragraph justification"));
563   
564   ADD_SET_PROP ("language_set", PROP_LANGUAGE_SET,
565                 P_("Language set"),
566                 P_("Whether this tag affects the language the text is rendered as"));
567
568   ADD_SET_PROP ("left_margin_set", PROP_LEFT_MARGIN_SET,
569                 P_("Left margin set"),
570                 P_("Whether this tag affects the left margin"));
571
572   ADD_SET_PROP ("indent_set", PROP_INDENT_SET,
573                 P_("Indent set"),
574                 P_("Whether this tag affects indentation"));
575
576   ADD_SET_PROP ("rise_set", PROP_RISE_SET,
577                 P_("Rise set"),
578                 P_("Whether this tag affects the rise"));
579
580   ADD_SET_PROP ("pixels_above_lines_set", PROP_PIXELS_ABOVE_LINES_SET,
581                 P_("Pixels above lines set"),
582                 P_("Whether this tag affects the number of pixels above lines"));
583
584   ADD_SET_PROP ("pixels_below_lines_set", PROP_PIXELS_BELOW_LINES_SET,
585                 P_("Pixels below lines set"),
586                 P_("Whether this tag affects the number of pixels above lines"));
587
588   ADD_SET_PROP ("pixels_inside_wrap_set", PROP_PIXELS_INSIDE_WRAP_SET,
589                 P_("Pixels inside wrap set"),
590                 P_("Whether this tag affects the number of pixels between wrapped lines"));
591
592   ADD_SET_PROP ("strikethrough_set", PROP_STRIKETHROUGH_SET,
593                 P_("Strikethrough set"),
594                 P_("Whether this tag affects strikethrough"));
595   
596   ADD_SET_PROP ("right_margin_set", PROP_RIGHT_MARGIN_SET,
597                 P_("Right margin set"),
598                 P_("Whether this tag affects the right margin"));
599
600   ADD_SET_PROP ("underline_set", PROP_UNDERLINE_SET,
601                 P_("Underline set"),
602                 P_("Whether this tag affects underlining"));
603
604   ADD_SET_PROP ("wrap_mode_set", PROP_WRAP_MODE_SET,
605                 P_("Wrap mode set"),
606                 P_("Whether this tag affects line wrap mode"));
607
608   ADD_SET_PROP ("tabs_set", PROP_TABS_SET,
609                 P_("Tabs set"),
610                 P_("Whether this tag affects tabs"));
611
612   ADD_SET_PROP ("invisible_set", PROP_INVISIBLE_SET,
613                 P_("Invisible set"),
614                 P_("Whether this tag affects text visibility"));
615
616   signals[EVENT] =
617     g_signal_new ("event",
618                   G_OBJECT_CLASS_TYPE (object_class),
619                   G_SIGNAL_RUN_LAST,
620                   G_STRUCT_OFFSET (GtkTextTagClass, event),
621                   _gtk_boolean_handled_accumulator, NULL,
622                   _gtk_marshal_BOOLEAN__OBJECT_BOXED_BOXED,
623                   G_TYPE_BOOLEAN,
624                   3,
625                   G_TYPE_OBJECT,
626                   GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE,
627                   GTK_TYPE_TEXT_ITER);
628 }
629
630 static void
631 gtk_text_tag_init (GtkTextTag *text_tag)
632 {
633   /* 0 is basically a fine way to initialize everything in the
634      entire struct */
635   
636   text_tag->values = gtk_text_attributes_new ();
637 }
638
639 /**
640  * gtk_text_tag_new:
641  * @name: tag name, or %NULL
642  * 
643  * Creates a #GtkTextTag. Configure the tag using object arguments,
644  * i.e. using g_object_set().
645  * 
646  * Return value: a new #GtkTextTag
647  **/
648 GtkTextTag*
649 gtk_text_tag_new (const gchar *name)
650 {
651   GtkTextTag *tag;
652
653   tag = g_object_new (GTK_TYPE_TEXT_TAG, "name", name, NULL);
654
655   return tag;
656 }
657
658 static void
659 gtk_text_tag_finalize (GObject *object)
660 {
661   GtkTextTag *text_tag;
662
663   text_tag = GTK_TEXT_TAG (object);
664
665   g_assert (!text_tag->values->realized);
666
667   if (text_tag->table)
668     gtk_text_tag_table_remove (text_tag->table, text_tag);
669
670   g_assert (text_tag->table == NULL);
671
672   gtk_text_attributes_unref (text_tag->values);
673   text_tag->values = NULL;
674   
675   g_free (text_tag->name);
676   text_tag->name = NULL;
677
678   (* G_OBJECT_CLASS (parent_class)->finalize) (object);
679 }
680
681 static void
682 set_bg_color (GtkTextTag *tag, GdkColor *color)
683 {
684   if (color)
685     {
686       if (!tag->bg_color_set)
687         {
688           tag->bg_color_set = TRUE;
689           g_object_notify (G_OBJECT (tag), "background_set");
690         }
691       
692       tag->values->appearance.bg_color = *color;
693     }
694   else
695     {
696       if (tag->bg_color_set)
697         {
698           tag->bg_color_set = FALSE;
699           g_object_notify (G_OBJECT (tag), "background_set");
700         }
701     }
702 }
703
704 static void
705 set_fg_color (GtkTextTag *tag, GdkColor *color)
706 {
707   if (color)
708     {
709       if (!tag->fg_color_set)
710         {
711           tag->fg_color_set = TRUE;
712           g_object_notify (G_OBJECT (tag), "foreground_set");
713         }
714       tag->values->appearance.fg_color = *color;
715     }
716   else
717     {
718       if (tag->fg_color_set)
719         {
720           tag->fg_color_set = FALSE;
721           g_object_notify (G_OBJECT (tag), "foreground_set");
722         }
723     }
724 }
725
726 static PangoFontMask
727 get_property_font_set_mask (guint prop_id)
728 {
729   switch (prop_id)
730     {
731     case PROP_FAMILY_SET:
732       return PANGO_FONT_MASK_FAMILY;
733     case PROP_STYLE_SET:
734       return PANGO_FONT_MASK_STYLE;
735     case PROP_VARIANT_SET:
736       return PANGO_FONT_MASK_VARIANT;
737     case PROP_WEIGHT_SET:
738       return PANGO_FONT_MASK_WEIGHT;
739     case PROP_STRETCH_SET:
740       return PANGO_FONT_MASK_STRETCH;
741     case PROP_SIZE_SET:
742       return PANGO_FONT_MASK_SIZE;
743     }
744
745   return 0;
746 }
747
748 static PangoFontMask
749 set_font_desc_fields (PangoFontDescription *desc,
750                       PangoFontMask         to_set)
751 {
752   PangoFontMask changed_mask = 0;
753   
754   if (to_set & PANGO_FONT_MASK_FAMILY)
755     {
756       const char *family = pango_font_description_get_family (desc);
757       if (!family)
758         {
759           family = "sans";
760           changed_mask |= PANGO_FONT_MASK_FAMILY;
761         }
762
763       pango_font_description_set_family (desc, family);
764     }
765   if (to_set & PANGO_FONT_MASK_STYLE)
766     pango_font_description_set_style (desc, pango_font_description_get_style (desc));
767   if (to_set & PANGO_FONT_MASK_VARIANT)
768     pango_font_description_set_variant (desc, pango_font_description_get_variant (desc));
769   if (to_set & PANGO_FONT_MASK_WEIGHT)
770     pango_font_description_set_weight (desc, pango_font_description_get_weight (desc));
771   if (to_set & PANGO_FONT_MASK_STRETCH)
772     pango_font_description_set_stretch (desc, pango_font_description_get_stretch (desc));
773   if (to_set & PANGO_FONT_MASK_SIZE)
774     {
775       gint size = pango_font_description_get_size (desc);
776       if (size <= 0)
777         {
778           size = 10 * PANGO_SCALE;
779           changed_mask |= PANGO_FONT_MASK_SIZE;
780         }
781       
782       pango_font_description_set_size (desc, size);
783     }
784
785   return changed_mask;
786 }
787
788 static void
789 notify_set_changed (GObject       *object,
790                     PangoFontMask  changed_mask)
791 {
792   if (changed_mask & PANGO_FONT_MASK_FAMILY)
793     g_object_notify (object, "family_set");
794   if (changed_mask & PANGO_FONT_MASK_STYLE)
795     g_object_notify (object, "style_set");
796   if (changed_mask & PANGO_FONT_MASK_VARIANT)
797     g_object_notify (object, "variant_set");
798   if (changed_mask & PANGO_FONT_MASK_WEIGHT)
799     g_object_notify (object, "weight_set");
800   if (changed_mask & PANGO_FONT_MASK_STRETCH)
801     g_object_notify (object, "stretch_set");
802   if (changed_mask & PANGO_FONT_MASK_SIZE)
803     g_object_notify (object, "size_set");
804 }
805
806 static void
807 notify_fields_changed (GObject       *object,
808                        PangoFontMask  changed_mask)
809 {
810   if (changed_mask & PANGO_FONT_MASK_FAMILY)
811     g_object_notify (object, "family");
812   if (changed_mask & PANGO_FONT_MASK_STYLE)
813     g_object_notify (object, "style");
814   if (changed_mask & PANGO_FONT_MASK_VARIANT)
815     g_object_notify (object, "variant");
816   if (changed_mask & PANGO_FONT_MASK_WEIGHT)
817     g_object_notify (object, "weight");
818   if (changed_mask & PANGO_FONT_MASK_STRETCH)
819     g_object_notify (object, "stretch");
820   if (changed_mask & PANGO_FONT_MASK_SIZE)
821     g_object_notify (object, "size");
822 }
823
824 static void
825 set_font_description (GtkTextTag           *text_tag,
826                       PangoFontDescription *font_desc)
827 {
828   GObject *object = G_OBJECT (text_tag);
829   PangoFontDescription *new_font_desc;
830   PangoFontMask old_mask, new_mask, changed_mask, set_changed_mask;
831   
832   if (font_desc)
833     new_font_desc = pango_font_description_copy (font_desc);
834   else
835     new_font_desc = pango_font_description_new ();
836
837   if (text_tag->values->font)
838     old_mask = pango_font_description_get_set_fields (text_tag->values->font);
839   else
840     old_mask = 0;
841   
842   new_mask = pango_font_description_get_set_fields (new_font_desc);
843
844   changed_mask = old_mask | new_mask;
845   set_changed_mask = old_mask ^ new_mask;
846
847   if (text_tag->values->font)
848     pango_font_description_free (text_tag->values->font);
849   text_tag->values->font = new_font_desc;
850   
851   g_object_freeze_notify (object);
852
853   g_object_notify (object, "font_desc");
854   g_object_notify (object, "font");
855   
856   if (changed_mask & PANGO_FONT_MASK_FAMILY)
857     g_object_notify (object, "family");
858   if (changed_mask & PANGO_FONT_MASK_STYLE)
859     g_object_notify (object, "style");
860   if (changed_mask & PANGO_FONT_MASK_VARIANT)
861     g_object_notify (object, "variant");
862   if (changed_mask & PANGO_FONT_MASK_WEIGHT)
863     g_object_notify (object, "weight");
864   if (changed_mask & PANGO_FONT_MASK_STRETCH)
865     g_object_notify (object, "stretch");
866   if (changed_mask & PANGO_FONT_MASK_SIZE)
867     {
868       g_object_notify (object, "size");
869       g_object_notify (object, "size_points");
870     }
871
872   notify_set_changed (object, set_changed_mask);
873   
874   g_object_thaw_notify (object);
875 }
876
877 static void
878 gtk_text_tag_ensure_font (GtkTextTag *text_tag)
879 {
880   if (!text_tag->values->font)
881     text_tag->values->font = pango_font_description_new ();
882 }
883
884 static void
885 gtk_text_tag_set_property (GObject      *object,
886                            guint         prop_id,
887                            const GValue *value,
888                            GParamSpec   *pspec)
889 {
890   GtkTextTag *text_tag;
891   gboolean size_changed = FALSE;
892
893   text_tag = GTK_TEXT_TAG (object);
894
895   g_return_if_fail (!text_tag->values->realized);
896
897   switch (prop_id)
898     {
899     case PROP_NAME:
900       g_return_if_fail (text_tag->name == NULL);
901       text_tag->name = g_strdup (g_value_get_string (value));
902       break;
903
904     case PROP_BACKGROUND:
905       {
906         GdkColor color;
907
908         if (gdk_color_parse (g_value_get_string (value), &color))
909           set_bg_color (text_tag, &color);
910         else
911           g_warning ("Don't know color `%s'", g_value_get_string (value));
912
913         g_object_notify (object, "background_gdk");
914       }
915       break;
916
917     case PROP_FOREGROUND:
918       {
919         GdkColor color;
920
921         if (gdk_color_parse (g_value_get_string (value), &color))
922           set_fg_color (text_tag, &color);
923         else
924           g_warning ("Don't know color `%s'", g_value_get_string (value));
925
926         g_object_notify (object, "foreground_gdk");
927       }
928       break;
929
930     case PROP_BACKGROUND_GDK:
931       {
932         GdkColor *color = g_value_get_boxed (value);
933
934         set_bg_color (text_tag, color);
935       }
936       break;
937
938     case PROP_FOREGROUND_GDK:
939       {
940         GdkColor *color = g_value_get_boxed (value);
941
942         set_fg_color (text_tag, color);
943       }
944       break;
945
946     case PROP_BACKGROUND_STIPPLE:
947       {
948         GdkBitmap *bitmap = g_value_get_object (value);
949
950         text_tag->bg_stipple_set = TRUE;
951         g_object_notify (object, "background_stipple_set");
952         
953         if (text_tag->values->appearance.bg_stipple != bitmap)
954           {
955             if (bitmap != NULL)
956               g_object_ref (bitmap);
957
958             if (text_tag->values->appearance.bg_stipple)
959               g_object_unref (text_tag->values->appearance.bg_stipple);
960
961             text_tag->values->appearance.bg_stipple = bitmap;
962           }
963       }
964       break;
965
966     case PROP_FOREGROUND_STIPPLE:
967       {
968         GdkBitmap *bitmap = g_value_get_object (value);
969
970         text_tag->fg_stipple_set = TRUE;
971         g_object_notify (object, "foreground_stipple_set");
972
973         if (text_tag->values->appearance.fg_stipple != bitmap)
974           {
975             if (bitmap != NULL)
976               g_object_ref (bitmap);
977
978             if (text_tag->values->appearance.fg_stipple)
979               g_object_unref (text_tag->values->appearance.fg_stipple);
980
981             text_tag->values->appearance.fg_stipple = bitmap;
982           }
983       }
984       break;
985
986     case PROP_FONT:
987       {
988         PangoFontDescription *font_desc = NULL;
989         const gchar *name;
990
991         name = g_value_get_string (value);
992
993         if (name)
994           font_desc = pango_font_description_from_string (name);
995
996         set_font_description (text_tag, font_desc);
997         if (font_desc)
998           pango_font_description_free (font_desc);
999         
1000         size_changed = TRUE;
1001       }
1002       break;
1003
1004     case PROP_FONT_DESC:
1005       {
1006         PangoFontDescription *font_desc;
1007
1008         font_desc = g_value_get_boxed (value);
1009
1010         set_font_description (text_tag, font_desc);
1011
1012         size_changed = TRUE;
1013       }
1014       break;
1015
1016     case PROP_FAMILY:
1017     case PROP_STYLE:
1018     case PROP_VARIANT:
1019     case PROP_WEIGHT:
1020     case PROP_STRETCH:
1021     case PROP_SIZE:
1022     case PROP_SIZE_POINTS:
1023       {
1024         PangoFontMask old_set_mask;
1025
1026         gtk_text_tag_ensure_font (text_tag);
1027         old_set_mask = pango_font_description_get_set_fields (text_tag->values->font);
1028  
1029         switch (prop_id)
1030           {
1031           case PROP_FAMILY:
1032             pango_font_description_set_family (text_tag->values->font,
1033                                                g_value_get_string (value));
1034             break;
1035           case PROP_STYLE:
1036             pango_font_description_set_style (text_tag->values->font,
1037                                               g_value_get_enum (value));
1038             break;
1039           case PROP_VARIANT:
1040             pango_font_description_set_variant (text_tag->values->font,
1041                                                 g_value_get_enum (value));
1042             break;
1043           case PROP_WEIGHT:
1044             pango_font_description_set_weight (text_tag->values->font,
1045                                                g_value_get_int (value));
1046             break;
1047           case PROP_STRETCH:
1048             pango_font_description_set_stretch (text_tag->values->font,
1049                                                 g_value_get_enum (value));
1050             break;
1051           case PROP_SIZE:
1052             pango_font_description_set_size (text_tag->values->font,
1053                                              g_value_get_int (value));
1054             g_object_notify (object, "size_points");
1055             break;
1056           case PROP_SIZE_POINTS:
1057             pango_font_description_set_size (text_tag->values->font,
1058                                              g_value_get_double (value) * PANGO_SCALE);
1059             g_object_notify (object, "size");
1060             break;
1061           }
1062
1063         size_changed = TRUE;
1064         notify_set_changed (object, old_set_mask & pango_font_description_get_set_fields (text_tag->values->font));
1065         g_object_notify (object, "font_desc");
1066         g_object_notify (object, "font");
1067
1068         break;
1069       }
1070       
1071     case PROP_SCALE:
1072       text_tag->values->font_scale = g_value_get_double (value);
1073       text_tag->scale_set = TRUE;
1074       g_object_notify (object, "scale_set");
1075       size_changed = TRUE;
1076       break;
1077       
1078     case PROP_PIXELS_ABOVE_LINES:
1079       text_tag->pixels_above_lines_set = TRUE;
1080       text_tag->values->pixels_above_lines = g_value_get_int (value);
1081       g_object_notify (object, "pixels_above_lines_set");
1082       size_changed = TRUE;
1083       break;
1084
1085     case PROP_PIXELS_BELOW_LINES:
1086       text_tag->pixels_below_lines_set = TRUE;
1087       text_tag->values->pixels_below_lines = g_value_get_int (value);
1088       g_object_notify (object, "pixels_below_lines_set");
1089       size_changed = TRUE;
1090       break;
1091
1092     case PROP_PIXELS_INSIDE_WRAP:
1093       text_tag->pixels_inside_wrap_set = TRUE;
1094       text_tag->values->pixels_inside_wrap = g_value_get_int (value);
1095       g_object_notify (object, "pixels_inside_wrap_set");
1096       size_changed = TRUE;
1097       break;
1098
1099     case PROP_EDITABLE:
1100       text_tag->editable_set = TRUE;
1101       text_tag->values->editable = g_value_get_boolean (value);
1102       g_object_notify (object, "editable_set");
1103       break;
1104
1105     case PROP_WRAP_MODE:
1106       text_tag->wrap_mode_set = TRUE;
1107       text_tag->values->wrap_mode = g_value_get_enum (value);
1108       g_object_notify (object, "wrap_mode_set");
1109       size_changed = TRUE;
1110       break;
1111
1112     case PROP_JUSTIFICATION:
1113       text_tag->justification_set = TRUE;
1114       text_tag->values->justification = g_value_get_enum (value);
1115       g_object_notify (object, "justification_set");
1116       size_changed = TRUE;
1117       break;
1118
1119     case PROP_DIRECTION:
1120       text_tag->values->direction = g_value_get_enum (value);
1121       break;
1122
1123     case PROP_LEFT_MARGIN:
1124       text_tag->left_margin_set = TRUE;
1125       text_tag->values->left_margin = g_value_get_int (value);
1126       g_object_notify (object, "left_margin_set");
1127       size_changed = TRUE;
1128       break;
1129
1130     case PROP_INDENT:
1131       text_tag->indent_set = TRUE;
1132       text_tag->values->indent = g_value_get_int (value);
1133       g_object_notify (object, "indent_set");
1134       size_changed = TRUE;
1135       break;
1136
1137     case PROP_STRIKETHROUGH:
1138       text_tag->strikethrough_set = TRUE;
1139       text_tag->values->appearance.strikethrough = g_value_get_boolean (value);
1140       g_object_notify (object, "strikethrough_set");
1141       break;
1142
1143     case PROP_RIGHT_MARGIN:
1144       text_tag->right_margin_set = TRUE;
1145       text_tag->values->right_margin = g_value_get_int (value);
1146       g_object_notify (object, "right_margin_set");
1147       size_changed = TRUE;
1148       break;
1149
1150     case PROP_UNDERLINE:
1151       text_tag->underline_set = TRUE;
1152       text_tag->values->appearance.underline = g_value_get_enum (value);
1153       g_object_notify (object, "underline_set");
1154       break;
1155
1156     case PROP_RISE:
1157       text_tag->rise_set = TRUE;
1158       text_tag->values->appearance.rise = g_value_get_int (value);
1159       g_object_notify (object, "rise_set");
1160       size_changed = TRUE;      
1161       break;
1162
1163     case PROP_BG_FULL_HEIGHT:
1164       text_tag->bg_full_height_set = TRUE;
1165       text_tag->values->bg_full_height = g_value_get_boolean (value);
1166       g_object_notify (object, "background_full_height_set");
1167       break;
1168
1169     case PROP_LANGUAGE:
1170       text_tag->language_set = TRUE;
1171       text_tag->values->language = pango_language_from_string (g_value_get_string (value));
1172       g_object_notify (object, "language_set");
1173       break;
1174
1175     case PROP_TABS:
1176       text_tag->tabs_set = TRUE;
1177
1178       if (text_tag->values->tabs)
1179         pango_tab_array_free (text_tag->values->tabs);
1180
1181       /* FIXME I'm not sure if this is a memleak or not */
1182       text_tag->values->tabs =
1183         pango_tab_array_copy (g_value_get_boxed (value));
1184
1185       g_object_notify (object, "tabs_set");
1186       
1187       size_changed = TRUE;
1188       break;
1189
1190     case PROP_INVISIBLE:
1191       g_warning ("The \"invisible\" property on GtkTextTag is not supported for GTK 2.0, it will be added in a future release. see http://bugzilla.gnome.org bug #66194 for status.");
1192       text_tag->invisible_set = TRUE;
1193       text_tag->values->invisible = g_value_get_boolean (value);
1194       g_object_notify (object, "invisible_set");
1195       size_changed = TRUE;
1196       break;
1197       
1198       /* Whether the value should be used... */
1199
1200     case PROP_BACKGROUND_SET:
1201       text_tag->bg_color_set = g_value_get_boolean (value);
1202       break;
1203
1204     case PROP_FOREGROUND_SET:
1205       text_tag->fg_color_set = g_value_get_boolean (value);
1206       break;
1207
1208     case PROP_BACKGROUND_STIPPLE_SET:
1209       text_tag->bg_stipple_set = g_value_get_boolean (value);
1210       if (!text_tag->bg_stipple_set &&
1211           text_tag->values->appearance.bg_stipple)
1212         {
1213           g_object_unref (text_tag->values->appearance.bg_stipple);
1214           text_tag->values->appearance.bg_stipple = NULL;
1215         }
1216       break;
1217
1218     case PROP_FOREGROUND_STIPPLE_SET:
1219       text_tag->fg_stipple_set = g_value_get_boolean (value);
1220       if (!text_tag->fg_stipple_set &&
1221           text_tag->values->appearance.fg_stipple)
1222         {
1223           g_object_unref (text_tag->values->appearance.fg_stipple);
1224           text_tag->values->appearance.fg_stipple = NULL;
1225         }
1226       break;
1227
1228     case PROP_FAMILY_SET:
1229     case PROP_STYLE_SET:
1230     case PROP_VARIANT_SET:
1231     case PROP_WEIGHT_SET:
1232     case PROP_STRETCH_SET:
1233     case PROP_SIZE_SET:
1234       if (!g_value_get_boolean (value))
1235         {
1236           if (text_tag->values->font)
1237             pango_font_description_unset_fields (text_tag->values->font,
1238                                                  get_property_font_set_mask (prop_id));
1239         }
1240       else
1241         {
1242           PangoFontMask changed_mask;
1243           
1244           gtk_text_tag_ensure_font (text_tag);
1245           changed_mask = set_font_desc_fields (text_tag->values->font,
1246                                                get_property_font_set_mask (prop_id));
1247           notify_fields_changed (G_OBJECT (text_tag), changed_mask);
1248         }
1249       break;
1250
1251     case PROP_SCALE_SET:
1252       text_tag->scale_set = g_value_get_boolean (value);
1253       size_changed = TRUE;
1254       break;
1255       
1256     case PROP_PIXELS_ABOVE_LINES_SET:
1257       text_tag->pixels_above_lines_set = g_value_get_boolean (value);
1258       size_changed = TRUE;
1259       break;
1260
1261     case PROP_PIXELS_BELOW_LINES_SET:
1262       text_tag->pixels_below_lines_set = g_value_get_boolean (value);
1263       size_changed = TRUE;
1264       break;
1265
1266     case PROP_PIXELS_INSIDE_WRAP_SET:
1267       text_tag->pixels_inside_wrap_set = g_value_get_boolean (value);
1268       size_changed = TRUE;
1269       break;
1270
1271     case PROP_EDITABLE_SET:
1272       text_tag->editable_set = g_value_get_boolean (value);
1273       break;
1274
1275     case PROP_WRAP_MODE_SET:
1276       text_tag->wrap_mode_set = g_value_get_boolean (value);
1277       size_changed = TRUE;
1278       break;
1279
1280     case PROP_JUSTIFICATION_SET:
1281       text_tag->justification_set = g_value_get_boolean (value);
1282       size_changed = TRUE;
1283       break;
1284       
1285     case PROP_LEFT_MARGIN_SET:
1286       text_tag->left_margin_set = g_value_get_boolean (value);
1287       size_changed = TRUE;
1288       break;
1289
1290     case PROP_INDENT_SET:
1291       text_tag->indent_set = g_value_get_boolean (value);
1292       size_changed = TRUE;
1293       break;
1294
1295     case PROP_STRIKETHROUGH_SET:
1296       text_tag->strikethrough_set = g_value_get_boolean (value);
1297       break;
1298
1299     case PROP_RIGHT_MARGIN_SET:
1300       text_tag->right_margin_set = g_value_get_boolean (value);
1301       size_changed = TRUE;
1302       break;
1303
1304     case PROP_UNDERLINE_SET:
1305       text_tag->underline_set = g_value_get_boolean (value);
1306       break;
1307
1308     case PROP_RISE_SET:
1309       text_tag->rise_set = g_value_get_boolean (value);
1310       size_changed = TRUE;
1311       break;
1312
1313     case PROP_BG_FULL_HEIGHT_SET:
1314       text_tag->bg_full_height_set = g_value_get_boolean (value);
1315       break;
1316
1317     case PROP_LANGUAGE_SET:
1318       text_tag->language_set = g_value_get_boolean (value);
1319       size_changed = TRUE;
1320       break;
1321
1322     case PROP_TABS_SET:
1323       text_tag->tabs_set = g_value_get_boolean (value);
1324       size_changed = TRUE;
1325       break;
1326
1327     case PROP_INVISIBLE_SET:
1328       text_tag->invisible_set = g_value_get_boolean (value);
1329       size_changed = TRUE;
1330       break;
1331       
1332     default:
1333       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1334       break;
1335     }
1336
1337   /* FIXME I would like to do this after all set_property in a single
1338    * g_object_set () have been called. But an idle function won't
1339    * work; we need to emit when the tag is changed, not when we get
1340    * around to the event loop. So blah, we eat some inefficiency.
1341    */
1342
1343   /* This is also somewhat weird since we emit another object's
1344    * signal here, but the two objects are already tightly bound.
1345    */
1346
1347   if (text_tag->table)
1348     g_signal_emit_by_name (text_tag->table,
1349                            "tag_changed",
1350                            text_tag, size_changed);
1351 }
1352
1353 static void
1354 gtk_text_tag_get_property (GObject      *object,
1355                            guint         prop_id,
1356                            GValue       *value,
1357                            GParamSpec   *pspec)
1358 {
1359   GtkTextTag *tag;
1360
1361   tag = GTK_TEXT_TAG (object);
1362
1363   switch (prop_id)
1364     {
1365     case PROP_NAME:
1366       g_value_set_string (value, tag->name);
1367       break;
1368
1369     case PROP_BACKGROUND_GDK:
1370       g_value_set_boxed (value, &tag->values->appearance.bg_color);
1371       break;
1372
1373     case PROP_FOREGROUND_GDK:
1374       g_value_set_boxed (value, &tag->values->appearance.fg_color);
1375       break;
1376
1377     case PROP_BACKGROUND_STIPPLE:
1378       if (tag->bg_stipple_set)
1379         g_value_set_boxed (value, tag->values->appearance.bg_stipple);
1380       break;
1381
1382     case PROP_FOREGROUND_STIPPLE:
1383       if (tag->fg_stipple_set)
1384         g_value_set_boxed (value, tag->values->appearance.fg_stipple);
1385       break;
1386
1387     case PROP_FONT:
1388         {
1389           /* FIXME GValue imposes a totally gratuitous string copy
1390            * here, we could just hand off string ownership
1391            */
1392           gchar *str;
1393
1394           gtk_text_tag_ensure_font (tag);
1395           
1396           str = pango_font_description_to_string (tag->values->font);
1397           g_value_set_string (value, str);
1398           g_free (str);
1399         }
1400       break;
1401
1402     case PROP_FONT_DESC:
1403       gtk_text_tag_ensure_font (tag);
1404       g_value_set_boxed (value, tag->values->font);
1405       break;
1406
1407     case PROP_FAMILY:
1408     case PROP_STYLE:
1409     case PROP_VARIANT:
1410     case PROP_WEIGHT:
1411     case PROP_STRETCH:
1412     case PROP_SIZE:
1413     case PROP_SIZE_POINTS:
1414       gtk_text_tag_ensure_font (tag);
1415       switch (prop_id)
1416         {
1417         case PROP_FAMILY:
1418           g_value_set_string (value, pango_font_description_get_family (tag->values->font));
1419           break;
1420           
1421         case PROP_STYLE:
1422           g_value_set_enum (value, pango_font_description_get_style (tag->values->font));
1423           break;
1424           
1425         case PROP_VARIANT:
1426           g_value_set_enum (value, pango_font_description_get_variant (tag->values->font));
1427           break;
1428           
1429         case PROP_WEIGHT:
1430           g_value_set_int (value, pango_font_description_get_weight (tag->values->font));
1431           break;
1432           
1433         case PROP_STRETCH:
1434           g_value_set_enum (value, pango_font_description_get_stretch (tag->values->font));
1435           break;
1436           
1437         case PROP_SIZE:
1438           g_value_set_int (value, pango_font_description_get_size (tag->values->font));
1439           break;
1440           
1441         case PROP_SIZE_POINTS:
1442           g_value_set_double (value, ((double)pango_font_description_get_size (tag->values->font)) / (double)PANGO_SCALE);
1443           break;
1444         }
1445       break;
1446       
1447     case PROP_SCALE:
1448       g_value_set_double (value, tag->values->font_scale);
1449       break;
1450       
1451     case PROP_PIXELS_ABOVE_LINES:
1452       g_value_set_int (value,  tag->values->pixels_above_lines);
1453       break;
1454
1455     case PROP_PIXELS_BELOW_LINES:
1456       g_value_set_int (value,  tag->values->pixels_below_lines);
1457       break;
1458
1459     case PROP_PIXELS_INSIDE_WRAP:
1460       g_value_set_int (value,  tag->values->pixels_inside_wrap);
1461       break;
1462
1463     case PROP_EDITABLE:
1464       g_value_set_boolean (value, tag->values->editable);
1465       break;
1466
1467     case PROP_WRAP_MODE:
1468       g_value_set_enum (value, tag->values->wrap_mode);
1469       break;
1470
1471     case PROP_JUSTIFICATION:
1472       g_value_set_enum (value, tag->values->justification);
1473       break;
1474
1475     case PROP_DIRECTION:
1476       g_value_set_enum (value, tag->values->direction);
1477       break;
1478       
1479     case PROP_LEFT_MARGIN:
1480       g_value_set_int (value,  tag->values->left_margin);
1481       break;
1482
1483     case PROP_INDENT:
1484       g_value_set_int (value,  tag->values->indent);
1485       break;
1486
1487     case PROP_STRIKETHROUGH:
1488       g_value_set_boolean (value, tag->values->appearance.strikethrough);
1489       break;
1490
1491     case PROP_RIGHT_MARGIN:
1492       g_value_set_int (value, tag->values->right_margin);
1493       break;
1494
1495     case PROP_UNDERLINE:
1496       g_value_set_enum (value, tag->values->appearance.underline);
1497       break;
1498
1499     case PROP_RISE:
1500       g_value_set_int (value, tag->values->appearance.rise);
1501       break;
1502
1503     case PROP_BG_FULL_HEIGHT:
1504       g_value_set_boolean (value, tag->values->bg_full_height);
1505       break;
1506
1507     case PROP_LANGUAGE:
1508       g_value_set_string (value, pango_language_to_string (tag->values->language));
1509       break;
1510
1511     case PROP_TABS:
1512       if (tag->values->tabs)
1513         g_value_set_boxed (value, tag->values->tabs);
1514       break;
1515
1516     case PROP_INVISIBLE:
1517       g_value_set_boolean (value, tag->values->invisible);
1518       break;
1519       
1520     case PROP_BACKGROUND_SET:
1521       g_value_set_boolean (value, tag->bg_color_set);
1522       break;
1523
1524     case PROP_FOREGROUND_SET:
1525       g_value_set_boolean (value, tag->fg_color_set);
1526       break;
1527
1528     case PROP_BACKGROUND_STIPPLE_SET:
1529       g_value_set_boolean (value, tag->bg_stipple_set);
1530       break;
1531
1532     case PROP_FOREGROUND_STIPPLE_SET:
1533       g_value_set_boolean (value, tag->fg_stipple_set);
1534       break;
1535
1536     case PROP_FAMILY_SET:
1537     case PROP_STYLE_SET:
1538     case PROP_VARIANT_SET:
1539     case PROP_WEIGHT_SET:
1540     case PROP_STRETCH_SET:
1541     case PROP_SIZE_SET:
1542       {
1543         PangoFontMask set_mask = tag->values->font ? pango_font_description_get_set_fields (tag->values->font) : 0;
1544         PangoFontMask test_mask = get_property_font_set_mask (prop_id);
1545         g_value_set_boolean (value, (set_mask & test_mask) != 0);
1546
1547         break;
1548       }
1549
1550     case PROP_SCALE_SET:
1551       g_value_set_boolean (value, tag->scale_set);
1552       break;
1553       
1554     case PROP_PIXELS_ABOVE_LINES_SET:
1555       g_value_set_boolean (value, tag->pixels_above_lines_set);
1556       break;
1557
1558     case PROP_PIXELS_BELOW_LINES_SET:
1559       g_value_set_boolean (value, tag->pixels_below_lines_set);
1560       break;
1561
1562     case PROP_PIXELS_INSIDE_WRAP_SET:
1563       g_value_set_boolean (value, tag->pixels_inside_wrap_set);
1564       break;
1565
1566     case PROP_EDITABLE_SET:
1567       g_value_set_boolean (value, tag->editable_set);
1568       break;
1569
1570     case PROP_WRAP_MODE_SET:
1571       g_value_set_boolean (value, tag->wrap_mode_set);
1572       break;
1573
1574     case PROP_JUSTIFICATION_SET:
1575       g_value_set_boolean (value, tag->justification_set);
1576       break;
1577       
1578     case PROP_LEFT_MARGIN_SET:
1579       g_value_set_boolean (value, tag->left_margin_set);
1580       break;
1581
1582     case PROP_INDENT_SET:
1583       g_value_set_boolean (value, tag->indent_set);
1584       break;
1585
1586     case PROP_STRIKETHROUGH_SET:
1587       g_value_set_boolean (value, tag->strikethrough_set);
1588       break;
1589
1590     case PROP_RIGHT_MARGIN_SET:
1591       g_value_set_boolean (value, tag->right_margin_set);
1592       break;
1593
1594     case PROP_UNDERLINE_SET:
1595       g_value_set_boolean (value, tag->underline_set);
1596       break;
1597
1598     case PROP_RISE_SET:
1599       g_value_set_boolean (value, tag->rise_set);
1600       break;
1601
1602     case PROP_BG_FULL_HEIGHT_SET:
1603       g_value_set_boolean (value, tag->bg_full_height_set);
1604       break;
1605
1606     case PROP_LANGUAGE_SET:
1607       g_value_set_boolean (value, tag->language_set);
1608       break;
1609
1610     case PROP_TABS_SET:
1611       g_value_set_boolean (value, tag->tabs_set);
1612       break;
1613
1614     case PROP_INVISIBLE_SET:
1615       g_value_set_boolean (value, tag->invisible_set);
1616       break;
1617       
1618     case PROP_BACKGROUND:
1619     case PROP_FOREGROUND:
1620       g_warning ("'foreground' and 'background' properties are not readable, use 'foreground_gdk' and 'background_gdk'");
1621     default:
1622       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1623       break;
1624     }
1625 }
1626
1627 /*
1628  * Tag operations
1629  */
1630
1631 typedef struct {
1632   gint high;
1633   gint low;
1634   gint delta;
1635 } DeltaData;
1636
1637 static void
1638 delta_priority_foreach (GtkTextTag *tag, gpointer user_data)
1639 {
1640   DeltaData *dd = user_data;
1641
1642   if (tag->priority >= dd->low && tag->priority <= dd->high)
1643     tag->priority += dd->delta;
1644 }
1645
1646 /**
1647  * gtk_text_tag_get_priority:
1648  * @tag: a #GtkTextTag
1649  * 
1650  * Get the tag priority.
1651  * 
1652  * Return value: The tag's priority.
1653  **/
1654 gint
1655 gtk_text_tag_get_priority (GtkTextTag *tag)
1656 {
1657   g_return_val_if_fail (GTK_IS_TEXT_TAG (tag), 0);
1658
1659   return tag->priority;
1660 }
1661
1662 /**
1663  * gtk_text_tag_set_priority:
1664  * @tag: a #GtkTextTag
1665  * @priority: the new priority
1666  * 
1667  * Sets the priority of a #GtkTextTag. Valid priorities are
1668  * start at 0 and go to one less than gtk_text_tag_table_get_size().
1669  * Each tag in a table has a unique priority; setting the priority
1670  * of one tag shifts the priorities of all the other tags in the
1671  * table to maintain a unique priority for each tag. Higher priority
1672  * tags "win" if two tags both set the same text attribute. When adding
1673  * a tag to a tag table, it will be assigned the highest priority in
1674  * the table by default; so normally the precedence of a set of tags
1675  * is the order in which they were added to the table, or created with
1676  * gtk_text_buffer_create_tag(), which adds the tag to the buffer's table
1677  * automatically.
1678  **/
1679 void
1680 gtk_text_tag_set_priority (GtkTextTag *tag,
1681                            gint        priority)
1682 {
1683   DeltaData dd;
1684
1685   g_return_if_fail (GTK_IS_TEXT_TAG (tag));
1686   g_return_if_fail (tag->table != NULL);
1687   g_return_if_fail (priority >= 0);
1688   g_return_if_fail (priority < gtk_text_tag_table_get_size (tag->table));
1689
1690   if (priority == tag->priority)
1691     return;
1692
1693   if (priority < tag->priority)
1694     {
1695       dd.low = priority;
1696       dd.high = tag->priority - 1;
1697       dd.delta = 1;
1698     }
1699   else
1700     {
1701       dd.low = tag->priority + 1;
1702       dd.high = priority;
1703       dd.delta = -1;
1704     }
1705
1706   gtk_text_tag_table_foreach (tag->table,
1707                               delta_priority_foreach,
1708                               &dd);
1709
1710   tag->priority = priority;
1711 }
1712
1713 /**
1714  * gtk_text_tag_event:
1715  * @tag: a #GtkTextTag
1716  * @event_object: object that received the event, such as a widget
1717  * @event: the event
1718  * @iter: location where the event was received
1719  * 
1720  * Emits the "event" signal on the #GtkTextTag.
1721  * 
1722  * Return value: result of signal emission (whether the event was handled)
1723  **/
1724 gboolean
1725 gtk_text_tag_event (GtkTextTag        *tag,
1726                     GObject           *event_object,
1727                     GdkEvent          *event,
1728                     const GtkTextIter *iter)
1729 {
1730   gboolean retval = FALSE;
1731
1732   g_return_val_if_fail (GTK_IS_TEXT_TAG (tag), FALSE);
1733   g_return_val_if_fail (G_IS_OBJECT (event_object), FALSE);
1734   g_return_val_if_fail (event != NULL, FALSE);
1735
1736   g_signal_emit (tag,
1737                  signals[EVENT],
1738                  0,
1739                  event_object,
1740                  event,
1741                  iter,
1742                  &retval);
1743
1744   return retval;
1745 }
1746
1747 static int
1748 tag_sort_func (gconstpointer first, gconstpointer second)
1749 {
1750   GtkTextTag *tag1, *tag2;
1751
1752   tag1 = * (GtkTextTag **) first;
1753   tag2 = * (GtkTextTag **) second;
1754   return tag1->priority - tag2->priority;
1755 }
1756
1757 void
1758 _gtk_text_tag_array_sort (GtkTextTag** tag_array_p,
1759                           guint len)
1760 {
1761   int i, j, prio;
1762   GtkTextTag **tag;
1763   GtkTextTag **maxPtrPtr, *tmp;
1764
1765   g_return_if_fail (tag_array_p != NULL);
1766   g_return_if_fail (len > 0);
1767
1768   if (len < 2) {
1769     return;
1770   }
1771   if (len < 20) {
1772     GtkTextTag **iter = tag_array_p;
1773
1774     for (i = len-1; i > 0; i--, iter++) {
1775       maxPtrPtr = tag = iter;
1776       prio = tag[0]->priority;
1777       for (j = i, tag++; j > 0; j--, tag++) {
1778         if (tag[0]->priority < prio) {
1779           prio = tag[0]->priority;
1780           maxPtrPtr = tag;
1781         }
1782       }
1783       tmp = *maxPtrPtr;
1784       *maxPtrPtr = *iter;
1785       *iter = tmp;
1786     }
1787   } else {
1788     qsort ((void *) tag_array_p, (unsigned) len, sizeof (GtkTextTag *),
1789            tag_sort_func);
1790   }
1791
1792 #if 0
1793   {
1794     printf ("Sorted tag array: \n");
1795     i = 0;
1796     while (i < len)
1797       {
1798         GtkTextTag *t = tag_array_p[i];
1799         printf ("  %s priority %d\n", t->name, t->priority);
1800
1801         ++i;
1802       }
1803   }
1804 #endif
1805 }
1806
1807 /*
1808  * Attributes
1809  */
1810
1811 /**
1812  * gtk_text_attributes_new:
1813  * 
1814  * Creates a #GtkTextAttributes, which describes
1815  * a set of properties on some text.
1816  * 
1817  * Return value: a new #GtkTextAttributes
1818  **/
1819 GtkTextAttributes*
1820 gtk_text_attributes_new (void)
1821 {
1822   GtkTextAttributes *values;
1823
1824   values = g_new0 (GtkTextAttributes, 1);
1825
1826   /* 0 is a valid value for most of the struct */
1827
1828   values->refcount = 1;
1829
1830   values->language = gtk_get_default_language ();
1831
1832   values->font_scale = 1.0;
1833   
1834   return values;
1835 }
1836
1837 /**
1838  * gtk_text_attributes_copy:
1839  * @src: a #GtkTextAttributes to be copied
1840  * 
1841  * Copies @src and returns a new #GtkTextAttributes.
1842  * 
1843  * Return value: a copy of @src
1844  **/
1845 GtkTextAttributes*
1846 gtk_text_attributes_copy (GtkTextAttributes *src)
1847 {
1848   GtkTextAttributes *dest;
1849
1850   dest = gtk_text_attributes_new ();
1851   gtk_text_attributes_copy_values (src, dest);
1852
1853   return dest;
1854 }
1855
1856 GType
1857 gtk_text_attributes_get_type (void)
1858 {
1859   static GType our_type = 0;
1860   
1861   if (our_type == 0)
1862     our_type = g_boxed_type_register_static ("GtkTextAttributes",
1863                                              (GBoxedCopyFunc) gtk_text_attributes_ref,
1864                                              (GBoxedFreeFunc) gtk_text_attributes_unref);
1865
1866   return our_type;
1867 }
1868
1869 /**
1870  * gtk_text_attributes_copy_values:
1871  * @src: a #GtkTextAttributes
1872  * @dest: another #GtkTextAttributes
1873  * 
1874  * Copies the values from @src to @dest so that @dest has the same values
1875  * as @src. Frees existing values in @dest.
1876  **/
1877 void
1878 gtk_text_attributes_copy_values (GtkTextAttributes *src,
1879                                  GtkTextAttributes *dest)
1880 {
1881   guint orig_refcount;
1882
1883   g_return_if_fail (!dest->realized);
1884
1885   if (src == dest)
1886     return;
1887
1888   /* Add refs */
1889
1890   if (src->appearance.bg_stipple)
1891     g_object_ref (src->appearance.bg_stipple);
1892
1893   if (src->appearance.fg_stipple)
1894     g_object_ref (src->appearance.fg_stipple);
1895
1896   /* Remove refs */
1897
1898   if (dest->appearance.bg_stipple)
1899     g_object_unref (dest->appearance.bg_stipple);
1900
1901   if (dest->appearance.fg_stipple)
1902     g_object_unref (dest->appearance.fg_stipple);
1903
1904   if (dest->font)
1905     pango_font_description_free (dest->font);
1906   
1907   /* Copy */
1908   orig_refcount = dest->refcount;
1909
1910   *dest = *src;
1911
1912   if (src->tabs)
1913     dest->tabs = pango_tab_array_copy (src->tabs);
1914
1915   dest->language = src->language;
1916
1917   if (dest->font)
1918     dest->font = pango_font_description_copy (src->font);
1919   
1920   dest->refcount = orig_refcount;
1921   dest->realized = FALSE;
1922 }
1923
1924 /**
1925  * gtk_text_attributes_ref:
1926  * @values: a #GtkTextAttributes
1927  * 
1928  * Increments the reference count on @values.
1929  **/
1930 void
1931 gtk_text_attributes_ref (GtkTextAttributes *values)
1932 {
1933   g_return_if_fail (values != NULL);
1934
1935   values->refcount += 1;
1936 }
1937
1938 /**
1939  * gtk_text_attributes_unref:
1940  * @values: a #GtkTextAttributes
1941  * 
1942  * Decrements the reference count on @values, freeing the structure
1943  * if the reference count reaches 0.
1944  **/
1945 void
1946 gtk_text_attributes_unref (GtkTextAttributes *values)
1947 {
1948   g_return_if_fail (values != NULL);
1949   g_return_if_fail (values->refcount > 0);
1950
1951   values->refcount -= 1;
1952
1953   if (values->refcount == 0)
1954     {
1955       g_assert (!values->realized);
1956
1957       if (values->appearance.bg_stipple)
1958         g_object_unref (values->appearance.bg_stipple);
1959
1960       if (values->appearance.fg_stipple)
1961         g_object_unref (values->appearance.fg_stipple);
1962
1963       if (values->tabs)
1964         pango_tab_array_free (values->tabs);
1965
1966       if (values->font)
1967         pango_font_description_free (values->font);
1968       
1969       g_free (values);
1970     }
1971 }
1972
1973 void
1974 _gtk_text_attributes_realize (GtkTextAttributes *values,
1975                               GdkColormap *cmap,
1976                               GdkVisual *visual)
1977 {
1978   g_return_if_fail (values != NULL);
1979   g_return_if_fail (values->refcount > 0);
1980   g_return_if_fail (!values->realized);
1981
1982   /* It is wrong to use this colormap, FIXME */
1983   gdk_colormap_alloc_color (cmap,
1984                             &values->appearance.fg_color,
1985                             FALSE, TRUE);
1986
1987   gdk_colormap_alloc_color (cmap,
1988                             &values->appearance.bg_color,
1989                             FALSE, TRUE);
1990
1991   values->realized = TRUE;
1992 }
1993
1994 void
1995 _gtk_text_attributes_unrealize (GtkTextAttributes *values,
1996                                 GdkColormap *cmap,
1997                                 GdkVisual *visual)
1998 {
1999   g_return_if_fail (values != NULL);
2000   g_return_if_fail (values->refcount > 0);
2001   g_return_if_fail (values->realized);
2002
2003   gdk_colormap_free_colors (cmap,
2004                             &values->appearance.fg_color, 1);
2005
2006
2007   gdk_colormap_free_colors (cmap,
2008                             &values->appearance.bg_color, 1);
2009
2010   values->appearance.fg_color.pixel = 0;
2011   values->appearance.bg_color.pixel = 0;
2012
2013   values->realized = FALSE;
2014 }
2015
2016 void
2017 _gtk_text_attributes_fill_from_tags (GtkTextAttributes *dest,
2018                                      GtkTextTag**       tags,
2019                                      guint              n_tags)
2020 {
2021   guint n = 0;
2022
2023   g_return_if_fail (!dest->realized);
2024
2025   while (n < n_tags)
2026     {
2027       GtkTextTag *tag = tags[n];
2028       GtkTextAttributes *vals = tag->values;
2029
2030       g_assert (tag->table != NULL);
2031       if (n > 0)
2032         g_assert (tags[n]->priority > tags[n-1]->priority);
2033
2034       if (tag->bg_color_set)
2035         {
2036           dest->appearance.bg_color = vals->appearance.bg_color;
2037
2038           dest->appearance.draw_bg = TRUE;
2039         }
2040       if (tag->fg_color_set)
2041         dest->appearance.fg_color = vals->appearance.fg_color;
2042       
2043       if (tag->bg_stipple_set)
2044         {
2045           g_object_ref (vals->appearance.bg_stipple);
2046           if (dest->appearance.bg_stipple)
2047             g_object_unref (dest->appearance.bg_stipple);
2048           dest->appearance.bg_stipple = vals->appearance.bg_stipple;
2049
2050           dest->appearance.draw_bg = TRUE;
2051         }
2052
2053       if (tag->fg_stipple_set)
2054         {
2055           g_object_ref (vals->appearance.fg_stipple);
2056           if (dest->appearance.fg_stipple)
2057             g_object_unref (dest->appearance.fg_stipple);
2058           dest->appearance.fg_stipple = vals->appearance.fg_stipple;
2059         }
2060
2061       if (vals->font)
2062         {
2063           if (dest->font)
2064             pango_font_description_merge (dest->font, vals->font, TRUE);
2065           else
2066             dest->font = pango_font_description_copy (vals->font);
2067         }
2068
2069       /* multiply all the scales together to get a composite */
2070       if (tag->scale_set)
2071         dest->font_scale *= vals->font_scale;
2072       
2073       if (tag->justification_set)
2074         dest->justification = vals->justification;
2075
2076       if (vals->direction != GTK_TEXT_DIR_NONE)
2077         dest->direction = vals->direction;
2078
2079       if (tag->left_margin_set)
2080         dest->left_margin = vals->left_margin;
2081
2082       if (tag->indent_set)
2083         dest->indent = vals->indent;
2084
2085       if (tag->rise_set)
2086         dest->appearance.rise = vals->appearance.rise;
2087
2088       if (tag->right_margin_set)
2089         dest->right_margin = vals->right_margin;
2090
2091       if (tag->pixels_above_lines_set)
2092         dest->pixels_above_lines = vals->pixels_above_lines;
2093
2094       if (tag->pixels_below_lines_set)
2095         dest->pixels_below_lines = vals->pixels_below_lines;
2096
2097       if (tag->pixels_inside_wrap_set)
2098         dest->pixels_inside_wrap = vals->pixels_inside_wrap;
2099
2100       if (tag->tabs_set)
2101         {
2102           if (dest->tabs)
2103             pango_tab_array_free (dest->tabs);
2104           dest->tabs = pango_tab_array_copy (vals->tabs);
2105         }
2106
2107       if (tag->wrap_mode_set)
2108         dest->wrap_mode = vals->wrap_mode;
2109
2110       if (tag->underline_set)
2111         dest->appearance.underline = vals->appearance.underline;
2112
2113       if (tag->strikethrough_set)
2114         dest->appearance.strikethrough = vals->appearance.strikethrough;
2115
2116       if (tag->invisible_set)
2117         dest->invisible = vals->invisible;
2118
2119       if (tag->editable_set)
2120         dest->editable = vals->editable;
2121
2122       if (tag->bg_full_height_set)
2123         dest->bg_full_height = vals->bg_full_height;
2124
2125       if (tag->language_set)
2126         dest->language = vals->language;
2127
2128       ++n;
2129     }
2130 }
2131
2132 gboolean
2133 _gtk_text_tag_affects_size (GtkTextTag *tag)
2134 {
2135   g_return_val_if_fail (GTK_IS_TEXT_TAG (tag), FALSE);
2136
2137   return
2138     (tag->values->font && pango_font_description_get_set_fields (tag->values->font) != 0) ||
2139     tag->scale_set ||
2140     tag->justification_set ||
2141     tag->left_margin_set ||
2142     tag->indent_set ||
2143     tag->rise_set ||
2144     tag->right_margin_set ||
2145     tag->pixels_above_lines_set ||
2146     tag->pixels_below_lines_set ||
2147     tag->pixels_inside_wrap_set ||
2148     tag->tabs_set ||
2149     tag->underline_set ||
2150     tag->wrap_mode_set ||
2151     tag->invisible_set;
2152 }
2153
2154 gboolean
2155 _gtk_text_tag_affects_nonsize_appearance (GtkTextTag *tag)
2156 {
2157   g_return_val_if_fail (GTK_IS_TEXT_TAG (tag), FALSE);
2158
2159   return
2160     tag->bg_color_set ||
2161     tag->bg_stipple_set ||
2162     tag->fg_color_set ||
2163     tag->fg_stipple_set ||
2164     tag->strikethrough_set ||
2165     tag->bg_full_height_set;
2166 }