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