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