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