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