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