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