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