]> Pileus Git - ~andy/gtk/blob - gtk/gtktexttag.c
Draw underlines one pixel higher.
[~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
57 #include <stdlib.h>
58 #include <string.h>
59
60 enum {
61   EVENT,
62   LAST_SIGNAL
63 };
64
65 enum {
66   ARG_0,
67   /* Construct args */
68   ARG_NAME,
69
70   /* Style args */
71   ARG_BACKGROUND,
72   ARG_FOREGROUND,
73   ARG_BACKGROUND_GDK,
74   ARG_FOREGROUND_GDK,
75   ARG_BACKGROUND_STIPPLE,
76   ARG_FOREGROUND_STIPPLE,
77   ARG_FONT,
78   ARG_FONT_DESC,
79   ARG_FAMILY,
80   ARG_STYLE,
81   ARG_VARIANT,
82   ARG_WEIGHT,
83   ARG_STRETCH,
84   ARG_SIZE,
85   ARG_SIZE_POINTS,
86   ARG_PIXELS_ABOVE_LINES,
87   ARG_PIXELS_BELOW_LINES,
88   ARG_PIXELS_INSIDE_WRAP,
89   ARG_EDITABLE,
90   ARG_WRAP_MODE,
91   ARG_JUSTIFY,
92   ARG_DIRECTION,
93   ARG_LEFT_MARGIN,
94   ARG_INDENT,
95   ARG_STRIKETHROUGH,
96   ARG_RIGHT_MARGIN,
97   ARG_UNDERLINE,
98   ARG_RISE,
99   ARG_BG_FULL_HEIGHT,
100   ARG_LANGUAGE,
101   ARG_TABS,
102   ARG_INVISIBLE,
103   
104   /* Whether-a-style-arg-is-set args */
105   ARG_BACKGROUND_SET,
106   ARG_FOREGROUND_SET,
107   ARG_BACKGROUND_GDK_SET,
108   ARG_FOREGROUND_GDK_SET,
109   ARG_BACKGROUND_STIPPLE_SET,
110   ARG_FOREGROUND_STIPPLE_SET,
111   ARG_FAMILY_SET,
112   ARG_STYLE_SET,
113   ARG_VARIANT_SET,
114   ARG_WEIGHT_SET,
115   ARG_STRETCH_SET,
116   ARG_SIZE_SET,
117   ARG_PIXELS_ABOVE_LINES_SET,
118   ARG_PIXELS_BELOW_LINES_SET,
119   ARG_PIXELS_INSIDE_WRAP_SET,
120   ARG_EDITABLE_SET,
121   ARG_WRAP_MODE_SET,
122   ARG_JUSTIFY_SET,
123   ARG_LEFT_MARGIN_SET,
124   ARG_INDENT_SET,
125   ARG_STRIKETHROUGH_SET,
126   ARG_RIGHT_MARGIN_SET,
127   ARG_UNDERLINE_SET,
128   ARG_RISE_SET,
129   ARG_BG_FULL_HEIGHT_SET,
130   ARG_LANGUAGE_SET,
131   ARG_TABS_SET,
132   ARG_INVISIBLE_SET,
133
134   LAST_ARG
135 };
136
137 static void gtk_text_tag_init       (GtkTextTag      *text_tag);
138 static void gtk_text_tag_class_init (GtkTextTagClass *klass);
139 static void gtk_text_tag_destroy    (GtkObject       *object);
140 static void gtk_text_tag_finalize   (GObject         *object);
141 static void gtk_text_tag_set_arg    (GtkObject       *object,
142                                      GtkArg          *arg,
143                                      guint            arg_id);
144 static void gtk_text_tag_get_arg    (GtkObject       *object,
145                                      GtkArg          *arg,
146                                      guint            arg_id);
147
148 static GtkObjectClass *parent_class = NULL;
149 static guint signals[LAST_SIGNAL] = { 0 };
150
151 GtkType
152 gtk_text_tag_get_type (void)
153 {
154   static GtkType our_type = 0;
155
156   if (our_type == 0)
157     {
158       static const GtkTypeInfo our_info =
159       {
160         "GtkTextTag",
161         sizeof (GtkTextTag),
162         sizeof (GtkTextTagClass),
163         (GtkClassInitFunc) gtk_text_tag_class_init,
164         (GtkObjectInitFunc) gtk_text_tag_init,
165         /* reserved_1 */ NULL,
166         /* reserved_2 */ NULL,
167         (GtkClassInitFunc) NULL
168       };
169
170       our_type = gtk_type_unique (GTK_TYPE_OBJECT, &our_info);
171     }
172
173   return our_type;
174 }
175
176 static void
177 gtk_text_tag_class_init (GtkTextTagClass *klass)
178 {
179   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
180   GtkObjectClass *object_class = GTK_OBJECT_CLASS (klass);
181
182   parent_class = gtk_type_class (GTK_TYPE_OBJECT);
183
184   /* Construct */
185   gtk_object_add_arg_type ("GtkTextTag::name", GTK_TYPE_STRING,
186                            GTK_ARG_READWRITE | GTK_ARG_CONSTRUCT_ONLY,
187                            ARG_NAME);
188
189   /* Style args */
190   gtk_object_add_arg_type ("GtkTextTag::background", GTK_TYPE_STRING,
191                            GTK_ARG_WRITABLE, ARG_BACKGROUND);
192   gtk_object_add_arg_type ("GtkTextTag::background_gdk", GTK_TYPE_GDK_COLOR,
193                            GTK_ARG_READWRITE, ARG_BACKGROUND_GDK);
194   gtk_object_add_arg_type ("GtkTextTag::background_full_height", GTK_TYPE_BOOL,
195                            GTK_ARG_READWRITE, ARG_BG_FULL_HEIGHT);
196   gtk_object_add_arg_type ("GtkTextTag::background_stipple",
197                            GDK_TYPE_PIXMAP,
198                            GTK_ARG_READWRITE, ARG_BACKGROUND_STIPPLE);
199   gtk_object_add_arg_type ("GtkTextTag::direction", GTK_TYPE_ENUM,
200                            GTK_ARG_READWRITE, ARG_DIRECTION);
201   gtk_object_add_arg_type ("GtkTextTag::editable", GTK_TYPE_BOOL,
202                            GTK_ARG_READWRITE, ARG_EDITABLE);
203   gtk_object_add_arg_type ("GtkTextTag::font", GTK_TYPE_STRING,
204                            GTK_ARG_READWRITE, ARG_FONT);
205   gtk_object_add_arg_type ("GtkTextTag::font_desc", GTK_TYPE_BOXED,
206                            GTK_ARG_READWRITE, ARG_FONT_DESC);      
207   gtk_object_add_arg_type ("GtkTextTag::family", GTK_TYPE_STRING,
208                            GTK_ARG_READWRITE, ARG_FAMILY);
209   gtk_object_add_arg_type ("GtkTextTag::style", GTK_TYPE_ENUM,
210                            GTK_ARG_READWRITE, ARG_STYLE);
211   gtk_object_add_arg_type ("GtkTextTag::variant", GTK_TYPE_ENUM,
212                            GTK_ARG_READWRITE, ARG_VARIANT);
213   gtk_object_add_arg_type ("GtkTextTag::weight", GTK_TYPE_ENUM,
214                            GTK_ARG_READWRITE, ARG_WEIGHT);
215   gtk_object_add_arg_type ("GtkTextTag::stretch", GTK_TYPE_ENUM,
216                            GTK_ARG_READWRITE, ARG_STRETCH);
217   gtk_object_add_arg_type ("GtkTextTag::size", GTK_TYPE_INT,
218                            GTK_ARG_READWRITE, ARG_SIZE);
219   gtk_object_add_arg_type ("GtkTextTag::size_points", GTK_TYPE_DOUBLE,
220                            GTK_ARG_READWRITE, ARG_SIZE_POINTS);
221   gtk_object_add_arg_type ("GtkTextTag::foreground", GTK_TYPE_STRING,
222                            GTK_ARG_WRITABLE, ARG_FOREGROUND);
223   gtk_object_add_arg_type ("GtkTextTag::foreground_gdk", GTK_TYPE_GDK_COLOR,
224                            GTK_ARG_READWRITE, ARG_FOREGROUND_GDK);
225   gtk_object_add_arg_type ("GtkTextTag::foreground_stipple",
226                            GDK_TYPE_PIXMAP,
227                            GTK_ARG_READWRITE, ARG_FOREGROUND_STIPPLE);
228   gtk_object_add_arg_type ("GtkTextTag::justify", GTK_TYPE_ENUM,
229                            GTK_ARG_READWRITE, ARG_JUSTIFY);
230   gtk_object_add_arg_type ("GtkTextTag::language", GTK_TYPE_STRING,
231                            GTK_ARG_READWRITE, ARG_LANGUAGE);
232   gtk_object_add_arg_type ("GtkTextTag::left_margin", GTK_TYPE_INT,
233                            GTK_ARG_READWRITE, ARG_LEFT_MARGIN);
234   gtk_object_add_arg_type ("GtkTextTag::indent", GTK_TYPE_INT,
235                            GTK_ARG_READWRITE, ARG_INDENT);
236   gtk_object_add_arg_type ("GtkTextTag::rise", GTK_TYPE_INT,
237                            GTK_ARG_READWRITE, ARG_RISE);
238   gtk_object_add_arg_type ("GtkTextTag::pixels_above_lines", GTK_TYPE_INT,
239                            GTK_ARG_READWRITE, ARG_PIXELS_ABOVE_LINES);
240   gtk_object_add_arg_type ("GtkTextTag::pixels_below_lines", GTK_TYPE_INT,
241                            GTK_ARG_READWRITE, ARG_PIXELS_BELOW_LINES);
242   gtk_object_add_arg_type ("GtkTextTag::pixels_inside_wrap", GTK_TYPE_INT,
243                            GTK_ARG_READWRITE, ARG_PIXELS_INSIDE_WRAP);
244   gtk_object_add_arg_type ("GtkTextTag::right_margin", GTK_TYPE_INT,
245                            GTK_ARG_READWRITE, ARG_RIGHT_MARGIN);
246   gtk_object_add_arg_type ("GtkTextTag::strikethrough", GTK_TYPE_BOOL,
247                            GTK_ARG_READWRITE, ARG_STRIKETHROUGH);
248   gtk_object_add_arg_type ("GtkTextTag::underline", GTK_TYPE_ENUM,
249                            GTK_ARG_READWRITE, ARG_UNDERLINE);
250   gtk_object_add_arg_type ("GtkTextTag::wrap_mode", GTK_TYPE_ENUM,
251                            GTK_ARG_READWRITE, ARG_WRAP_MODE);
252   gtk_object_add_arg_type ("GtkTextTag::tabs", GTK_TYPE_POINTER, /* FIXME */
253                            GTK_ARG_READWRITE, ARG_TABS);
254   gtk_object_add_arg_type ("GtkTextTag::invisible", GTK_TYPE_BOOL,
255                            GTK_ARG_READWRITE, ARG_INVISIBLE);
256   
257   /* Style args are set or not */
258   gtk_object_add_arg_type ("GtkTextTag::background_set", GTK_TYPE_BOOL,
259                            GTK_ARG_READWRITE, ARG_BACKGROUND_SET);
260   gtk_object_add_arg_type ("GtkTextTag::background_full_height_set", GTK_TYPE_BOOL,
261                            GTK_ARG_READWRITE, ARG_BG_FULL_HEIGHT_SET);
262   gtk_object_add_arg_type ("GtkTextTag::background_gdk_set", GTK_TYPE_BOOL,
263                            GTK_ARG_READWRITE, ARG_BACKGROUND_GDK_SET);
264   gtk_object_add_arg_type ("GtkTextTag::background_stipple_set", GTK_TYPE_BOOL,
265                            GTK_ARG_READWRITE, ARG_BACKGROUND_STIPPLE_SET);
266   gtk_object_add_arg_type ("GtkTextTag::editable_set", GTK_TYPE_BOOL,
267                            GTK_ARG_READWRITE, ARG_EDITABLE_SET);  
268   gtk_object_add_arg_type ("GtkTextTag::family_set", GTK_TYPE_BOOL,
269                            GTK_ARG_READWRITE, ARG_FAMILY_SET);
270   gtk_object_add_arg_type ("GtkTextTag::style_set", GTK_TYPE_BOOL,
271                            GTK_ARG_READWRITE, ARG_STYLE_SET);
272   gtk_object_add_arg_type ("GtkTextTag::variant_set", GTK_TYPE_BOOL,
273                            GTK_ARG_READWRITE, ARG_VARIANT_SET);
274   gtk_object_add_arg_type ("GtkTextTag::weight_set", GTK_TYPE_BOOL,
275                            GTK_ARG_READWRITE, ARG_WEIGHT_SET);
276   gtk_object_add_arg_type ("GtkTextTag::stretch_set", GTK_TYPE_BOOL,
277                            GTK_ARG_READWRITE, ARG_STRETCH_SET);
278   gtk_object_add_arg_type ("GtkTextTag::size_set", GTK_TYPE_BOOL,
279                            GTK_ARG_READWRITE, ARG_SIZE_SET);
280   gtk_object_add_arg_type ("GtkTextTag::foreground_set", GTK_TYPE_BOOL,
281                            GTK_ARG_READWRITE, ARG_FOREGROUND_SET);
282   gtk_object_add_arg_type ("GtkTextTag::foreground_gdk_set", GTK_TYPE_BOOL,
283                            GTK_ARG_READWRITE, ARG_FOREGROUND_GDK_SET);
284   gtk_object_add_arg_type ("GtkTextTag::foreground_stipple_set", GTK_TYPE_BOOL,
285                            GTK_ARG_READWRITE, ARG_FOREGROUND_STIPPLE_SET);
286   gtk_object_add_arg_type ("GtkTextTag::justify_set", GTK_TYPE_BOOL,
287                            GTK_ARG_READWRITE, ARG_JUSTIFY_SET);
288   gtk_object_add_arg_type ("GtkTextTag::language_set", GTK_TYPE_BOOL,
289                            GTK_ARG_READWRITE, ARG_LANGUAGE_SET);
290   gtk_object_add_arg_type ("GtkTextTag::left_margin_set", GTK_TYPE_BOOL,
291                            GTK_ARG_READWRITE, ARG_LEFT_MARGIN_SET);
292   gtk_object_add_arg_type ("GtkTextTag::indent_set", GTK_TYPE_BOOL,
293                            GTK_ARG_READWRITE, ARG_INDENT_SET);
294   gtk_object_add_arg_type ("GtkTextTag::rise_set", GTK_TYPE_BOOL,
295                            GTK_ARG_READWRITE, ARG_RISE_SET);
296   gtk_object_add_arg_type ("GtkTextTag::pixels_above_lines_set", GTK_TYPE_BOOL,
297                            GTK_ARG_READWRITE, ARG_PIXELS_ABOVE_LINES_SET);
298   gtk_object_add_arg_type ("GtkTextTag::pixels_below_lines_set", GTK_TYPE_BOOL,
299                            GTK_ARG_READWRITE, ARG_PIXELS_BELOW_LINES_SET);
300   gtk_object_add_arg_type ("GtkTextTag::pixels_inside_wrap_set", GTK_TYPE_BOOL,
301                            GTK_ARG_READWRITE, ARG_PIXELS_INSIDE_WRAP_SET);
302   gtk_object_add_arg_type ("GtkTextTag::strikethrough_set", GTK_TYPE_BOOL,
303                            GTK_ARG_READWRITE, ARG_STRIKETHROUGH_SET);
304   gtk_object_add_arg_type ("GtkTextTag::right_margin_set", GTK_TYPE_BOOL,
305                            GTK_ARG_READWRITE, ARG_RIGHT_MARGIN_SET);
306   gtk_object_add_arg_type ("GtkTextTag::underline_set", GTK_TYPE_ENUM,
307                            GTK_ARG_READWRITE, ARG_UNDERLINE_SET);
308   gtk_object_add_arg_type ("GtkTextTag::wrap_mode_set", GTK_TYPE_BOOL,
309                            GTK_ARG_READWRITE, ARG_WRAP_MODE_SET);
310   gtk_object_add_arg_type ("GtkTextTag::tabs_set", GTK_TYPE_BOOL,
311                            GTK_ARG_READWRITE, ARG_TABS_SET);
312   gtk_object_add_arg_type ("GtkTextTag::invisible_set", GTK_TYPE_BOOL,
313                            GTK_ARG_READWRITE, ARG_INVISIBLE_SET);
314   
315
316   signals[EVENT] =
317     gtk_signal_new ("event",
318                     GTK_RUN_LAST,
319                     GTK_CLASS_TYPE (object_class),
320                     GTK_SIGNAL_OFFSET (GtkTextTagClass, event),
321                     gtk_marshal_INT__OBJECT_BOXED_BOXED,
322                     GTK_TYPE_INT,
323                     3,
324                     G_TYPE_OBJECT,
325                     GTK_TYPE_GDK_EVENT,
326                     GTK_TYPE_TEXT_ITER);
327
328   gtk_object_class_add_signals (object_class, signals, LAST_SIGNAL);
329
330   object_class->set_arg = gtk_text_tag_set_arg;
331   object_class->get_arg = gtk_text_tag_get_arg;
332
333   object_class->destroy = gtk_text_tag_destroy;
334   gobject_class->finalize = gtk_text_tag_finalize;
335 }
336
337 void
338 gtk_text_tag_init (GtkTextTag *text_tag)
339 {
340   /* 0 is basically a fine way to initialize everything in the
341      entire struct */
342
343 }
344
345 /**
346  * gtk_text_tag_new:
347  * @name: tag name, or %NULL
348  * 
349  * Creates a #GtkTextTag. Configure the tag using object arguments,
350  * i.e. using g_object_set().
351  * 
352  * Return value: a new #GtkTextTag
353  **/
354 GtkTextTag*
355 gtk_text_tag_new (const gchar *name)
356 {
357   GtkTextTag *tag;
358
359   tag = GTK_TEXT_TAG (gtk_type_new (gtk_text_tag_get_type ()));
360
361   tag->name = g_strdup (name);
362
363   tag->values = gtk_text_attributes_new ();
364
365   return tag;
366 }
367
368 static void
369 gtk_text_tag_destroy (GtkObject *object)
370 {
371   GtkTextTag *text_tag;
372
373   text_tag = GTK_TEXT_TAG (object);
374
375   g_assert (!text_tag->values->realized);
376
377   if (text_tag->table)
378     gtk_text_tag_table_remove (text_tag->table, text_tag);
379
380   g_assert (text_tag->table == NULL);
381
382   gtk_text_attributes_unref (text_tag->values);
383   text_tag->values = NULL;
384
385   (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
386 }
387
388 static void
389 gtk_text_tag_finalize (GObject *object)
390 {
391   GtkTextTag *text_tag;
392
393   text_tag = GTK_TEXT_TAG (object);
394
395   g_free (text_tag->name);
396   text_tag->name = NULL;
397
398   (* G_OBJECT_CLASS (parent_class)->finalize) (object);
399 }
400
401 static void
402 set_bg_color (GtkTextTag *tag, GdkColor *color)
403 {
404   if (color)
405     {
406       tag->bg_color_set = TRUE;
407       tag->values->appearance.bg_color = *color;
408     }
409   else
410     {
411       tag->bg_color_set = FALSE;
412     }
413 }
414
415 static void
416 set_fg_color (GtkTextTag *tag, GdkColor *color)
417 {
418   if (color)
419     {
420       tag->fg_color_set = TRUE;
421       tag->values->appearance.fg_color = *color;
422     }
423   else
424     {
425       tag->fg_color_set = FALSE;
426     }
427 }
428
429 static void
430 set_font_description (GtkTextTag           *text_tag,
431                       PangoFontDescription *font_desc)
432 {
433   if (font_desc != NULL)
434     {
435       /* pango_font_description_from_string() will sometimes return
436        * a NULL family or -1 size, so handle those cases.
437        */
438       
439       if (font_desc->family_name)
440         gtk_object_set (GTK_OBJECT (text_tag),
441                         "family", font_desc->family_name,
442                         NULL);
443       
444       if (font_desc->size >= 0)
445         gtk_object_set (GTK_OBJECT (text_tag),
446                         "size", font_desc->size,
447                         NULL);
448         
449       gtk_object_set (GTK_OBJECT (text_tag),
450                       "style", font_desc->style,
451                       "variant", font_desc->variant,
452                       "weight", font_desc->weight,
453                       "stretch", font_desc->stretch,
454                       NULL);
455     }
456   else
457     {      
458       text_tag->family_set = FALSE;
459       text_tag->style_set = FALSE;
460       text_tag->variant_set = FALSE;
461       text_tag->weight_set = FALSE;
462       text_tag->stretch_set = FALSE;
463       text_tag->size_set = FALSE;
464     }
465 }
466
467 static void
468 gtk_text_tag_set_arg (GtkObject *object, GtkArg *arg, guint arg_id)
469 {
470   GtkTextTag *text_tag;
471   gboolean size_changed = FALSE;
472
473   text_tag = GTK_TEXT_TAG (object);
474
475   g_return_if_fail (!text_tag->values->realized);
476
477   switch (arg_id)
478     {
479     case ARG_NAME:
480       g_return_if_fail (text_tag->name == NULL);
481       text_tag->name = g_strdup (GTK_VALUE_STRING (*arg));
482       break;
483
484     case ARG_BACKGROUND:
485       {
486         GdkColor color;
487
488         if (gdk_color_parse (GTK_VALUE_STRING (*arg), &color))
489           set_bg_color (text_tag, &color);
490         else
491           g_warning ("Don't know color `%s'", GTK_VALUE_STRING (*arg));
492       }
493       break;
494
495     case ARG_FOREGROUND:
496       {
497         GdkColor color;
498
499         if (gdk_color_parse (GTK_VALUE_STRING (*arg), &color))
500           set_fg_color (text_tag, &color);
501         else
502           g_warning ("Don't know color `%s'", GTK_VALUE_STRING (*arg));
503       }
504       break;
505
506     case ARG_BACKGROUND_GDK:
507       {
508         GdkColor *color = GTK_VALUE_POINTER (*arg);
509         set_bg_color (text_tag, color);
510       }
511       break;
512
513     case ARG_FOREGROUND_GDK:
514       {
515         GdkColor *color = GTK_VALUE_POINTER (*arg);
516         set_fg_color (text_tag, color);
517       }
518       break;
519
520     case ARG_BACKGROUND_STIPPLE:
521       {
522         GdkBitmap *bitmap = GTK_VALUE_POINTER (*arg);
523
524         text_tag->bg_stipple_set = TRUE;
525
526         if (text_tag->values->appearance.bg_stipple != bitmap)
527           {
528             if (bitmap != NULL)
529               gdk_bitmap_ref (bitmap);
530
531             if (text_tag->values->appearance.bg_stipple)
532               gdk_bitmap_unref (text_tag->values->appearance.bg_stipple);
533
534             text_tag->values->appearance.bg_stipple = bitmap;
535           }
536       }
537       break;
538
539     case ARG_FOREGROUND_STIPPLE:
540       {
541         GdkBitmap *bitmap = GTK_VALUE_POINTER (*arg);
542
543         text_tag->fg_stipple_set = TRUE;
544
545         if (text_tag->values->appearance.fg_stipple != bitmap)
546           {
547             if (bitmap != NULL)
548               gdk_bitmap_ref (bitmap);
549
550             if (text_tag->values->appearance.fg_stipple)
551               gdk_bitmap_unref (text_tag->values->appearance.fg_stipple);
552
553             text_tag->values->appearance.fg_stipple = bitmap;
554           }
555       }
556       break;
557
558     case ARG_FONT:
559       {
560         PangoFontDescription *font_desc = NULL;
561         const gchar *name;
562
563         name = GTK_VALUE_STRING (*arg);
564
565         if (name)
566           font_desc = pango_font_description_from_string (name);
567
568         set_font_description (text_tag, font_desc);
569         
570         if (font_desc)
571           pango_font_description_free (font_desc); 
572
573         size_changed = TRUE;
574       }
575       break;
576
577     case ARG_FONT_DESC:
578       {
579         PangoFontDescription *font_desc;
580
581         font_desc = GTK_VALUE_BOXED (*arg);
582
583         set_font_description (text_tag, font_desc);
584
585         size_changed = TRUE;
586       }
587       break;
588
589     case ARG_FAMILY:
590       if (text_tag->values->font.family_name)
591         g_free (text_tag->values->font.family_name);
592       text_tag->values->font.family_name = g_strdup (GTK_VALUE_STRING (*arg));
593       text_tag->family_set = TRUE;
594       size_changed = TRUE;
595       break;
596
597     case ARG_STYLE:
598       text_tag->values->font.style = GTK_VALUE_ENUM (*arg);
599       text_tag->style_set = TRUE;
600       size_changed = TRUE;
601       break;
602
603     case ARG_VARIANT:
604       text_tag->values->font.variant = GTK_VALUE_ENUM (*arg);
605       text_tag->variant_set = TRUE;
606       size_changed = TRUE;
607       break;
608
609     case ARG_WEIGHT:
610       text_tag->values->font.weight = GTK_VALUE_ENUM (*arg);
611       text_tag->weight_set = TRUE;
612       size_changed = TRUE;
613       break;
614
615     case ARG_STRETCH:
616       text_tag->values->font.stretch = GTK_VALUE_ENUM (*arg);
617       text_tag->stretch_set = TRUE;
618       size_changed = TRUE;
619       break;
620
621     case ARG_SIZE:
622       text_tag->values->font.size = GTK_VALUE_INT (*arg);
623       text_tag->size_set = TRUE;
624       size_changed = TRUE;
625       break;
626
627     case ARG_SIZE_POINTS:
628       text_tag->values->font.size = GTK_VALUE_DOUBLE (*arg) * PANGO_SCALE;
629       text_tag->size_set = TRUE;
630       size_changed = TRUE;
631       break;
632       
633     case ARG_PIXELS_ABOVE_LINES:
634       text_tag->pixels_above_lines_set = TRUE;
635       text_tag->values->pixels_above_lines = GTK_VALUE_INT (*arg);
636       size_changed = TRUE;
637       break;
638
639     case ARG_PIXELS_BELOW_LINES:
640       text_tag->pixels_below_lines_set = TRUE;
641       text_tag->values->pixels_below_lines = GTK_VALUE_INT (*arg);
642       size_changed = TRUE;
643       break;
644
645     case ARG_PIXELS_INSIDE_WRAP:
646       text_tag->pixels_inside_wrap_set = TRUE;
647       text_tag->values->pixels_inside_wrap = GTK_VALUE_INT (*arg);
648       size_changed = TRUE;
649       break;
650
651     case ARG_EDITABLE:
652       text_tag->editable_set = TRUE;
653       text_tag->values->editable = GTK_VALUE_BOOL (*arg);
654       break;
655
656     case ARG_WRAP_MODE:
657       text_tag->wrap_mode_set = TRUE;
658       text_tag->values->wrap_mode = GTK_VALUE_ENUM (*arg);
659       size_changed = TRUE;
660       break;
661
662     case ARG_JUSTIFY:
663       text_tag->justify_set = TRUE;
664       text_tag->values->justify = GTK_VALUE_ENUM (*arg);
665       size_changed = TRUE;
666       break;
667
668     case ARG_DIRECTION:
669       text_tag->values->direction = GTK_VALUE_ENUM (*arg);
670       break;
671
672     case ARG_LEFT_MARGIN:
673       text_tag->left_margin_set = TRUE;
674       text_tag->values->left_margin = GTK_VALUE_INT (*arg);
675       size_changed = TRUE;
676       break;
677
678     case ARG_INDENT:
679       text_tag->indent_set = TRUE;
680       text_tag->values->indent = GTK_VALUE_INT (*arg);
681       size_changed = TRUE;
682       break;
683
684     case ARG_STRIKETHROUGH:
685       text_tag->strikethrough_set = TRUE;
686       text_tag->values->appearance.strikethrough = GTK_VALUE_BOOL (*arg);
687       break;
688
689     case ARG_RIGHT_MARGIN:
690       text_tag->right_margin_set = TRUE;
691       text_tag->values->right_margin = GTK_VALUE_INT (*arg);
692       size_changed = TRUE;
693       break;
694
695     case ARG_UNDERLINE:
696       text_tag->underline_set = TRUE;
697       text_tag->values->appearance.underline = GTK_VALUE_ENUM (*arg);
698       break;
699
700     case ARG_RISE:
701       text_tag->rise_set = TRUE;
702       text_tag->values->appearance.rise = GTK_VALUE_INT (*arg);
703       size_changed = TRUE;
704       break;
705
706     case ARG_BG_FULL_HEIGHT:
707       text_tag->bg_full_height_set = TRUE;
708       text_tag->values->bg_full_height = GTK_VALUE_BOOL (*arg);
709       break;
710
711     case ARG_LANGUAGE:
712       text_tag->language_set = TRUE;
713       text_tag->values->language = g_strdup (GTK_VALUE_STRING (*arg));
714       break;
715
716     case ARG_TABS:
717       text_tag->tabs_set = TRUE;
718
719       if (text_tag->values->tabs)
720         pango_tab_array_free (text_tag->values->tabs);
721
722       text_tag->values->tabs =
723         pango_tab_array_copy (GTK_VALUE_POINTER (*arg));
724
725       size_changed = TRUE;
726       break;
727
728     case ARG_INVISIBLE:
729       text_tag->invisible_set = TRUE;
730       text_tag->values->invisible = GTK_VALUE_BOOL (*arg);
731       size_changed = TRUE;
732       break;
733       
734       /* Whether the value should be used... */
735
736     case ARG_BACKGROUND_SET:
737     case ARG_BACKGROUND_GDK_SET:
738       text_tag->bg_color_set = GTK_VALUE_BOOL (*arg);
739       break;
740
741     case ARG_FOREGROUND_SET:
742     case ARG_FOREGROUND_GDK_SET:
743       text_tag->fg_color_set = GTK_VALUE_BOOL (*arg);
744       break;
745
746     case ARG_BACKGROUND_STIPPLE_SET:
747       text_tag->bg_stipple_set = GTK_VALUE_BOOL (*arg);
748       if (!text_tag->bg_stipple_set &&
749           text_tag->values->appearance.bg_stipple)
750         {
751           g_object_unref (G_OBJECT (text_tag->values->appearance.bg_stipple));
752           text_tag->values->appearance.bg_stipple = NULL;
753         }
754       break;
755
756     case ARG_FOREGROUND_STIPPLE_SET:
757       text_tag->fg_stipple_set = GTK_VALUE_BOOL (*arg);
758       if (!text_tag->fg_stipple_set &&
759           text_tag->values->appearance.fg_stipple)
760         {
761           g_object_unref (G_OBJECT (text_tag->values->appearance.fg_stipple));
762           text_tag->values->appearance.fg_stipple = NULL;
763         }
764       break;
765
766     case ARG_FAMILY_SET:
767       text_tag->family_set = GTK_VALUE_BOOL (*arg);
768       size_changed = TRUE;
769       break;
770
771     case ARG_STYLE_SET:
772       text_tag->style_set = GTK_VALUE_BOOL (*arg);
773       size_changed = TRUE;
774       break;
775
776     case ARG_VARIANT_SET:
777       text_tag->variant_set = GTK_VALUE_BOOL (*arg);
778       size_changed = TRUE;
779       break;
780
781     case ARG_WEIGHT_SET:
782       text_tag->weight_set = GTK_VALUE_BOOL (*arg);
783       size_changed = TRUE;
784       break;
785
786     case ARG_STRETCH_SET:
787       text_tag->stretch_set = GTK_VALUE_BOOL (*arg);
788       size_changed = TRUE;
789       break;
790
791     case ARG_SIZE_SET:
792       text_tag->size_set = GTK_VALUE_BOOL (*arg);
793       size_changed = TRUE;
794       break;
795       
796     case ARG_PIXELS_ABOVE_LINES_SET:
797       text_tag->pixels_above_lines_set = GTK_VALUE_BOOL (*arg);
798       size_changed = TRUE;
799       break;
800
801     case ARG_PIXELS_BELOW_LINES_SET:
802       text_tag->pixels_below_lines_set = GTK_VALUE_BOOL (*arg);
803       size_changed = TRUE;
804       break;
805
806     case ARG_PIXELS_INSIDE_WRAP_SET:
807       text_tag->pixels_inside_wrap_set = GTK_VALUE_BOOL (*arg);
808       size_changed = TRUE;
809       break;
810
811     case ARG_EDITABLE_SET:
812       text_tag->editable_set = GTK_VALUE_BOOL (*arg);
813       break;
814
815     case ARG_WRAP_MODE_SET:
816       text_tag->wrap_mode_set = GTK_VALUE_BOOL (*arg);
817       size_changed = TRUE;
818       break;
819
820     case ARG_JUSTIFY_SET:
821       text_tag->justify_set = GTK_VALUE_BOOL (*arg);
822       size_changed = TRUE;
823       break;
824
825     case ARG_LEFT_MARGIN_SET:
826       text_tag->left_margin_set = GTK_VALUE_BOOL (*arg);
827       size_changed = TRUE;
828       break;
829
830     case ARG_INDENT_SET:
831       text_tag->indent_set = GTK_VALUE_BOOL (*arg);
832       size_changed = TRUE;
833       break;
834
835     case ARG_STRIKETHROUGH_SET:
836       text_tag->strikethrough_set = GTK_VALUE_BOOL (*arg);
837       break;
838
839     case ARG_RIGHT_MARGIN_SET:
840       text_tag->right_margin_set = GTK_VALUE_BOOL (*arg);
841       size_changed = TRUE;
842       break;
843
844     case ARG_UNDERLINE_SET:
845       text_tag->underline_set = GTK_VALUE_BOOL (*arg);
846       break;
847
848     case ARG_RISE_SET:
849       text_tag->rise_set = GTK_VALUE_BOOL (*arg);
850       size_changed = TRUE;
851       break;
852
853     case ARG_BG_FULL_HEIGHT_SET:
854       text_tag->bg_full_height_set = GTK_VALUE_BOOL (*arg);
855       break;
856
857     case ARG_LANGUAGE_SET:
858       text_tag->language_set = GTK_VALUE_BOOL (*arg);
859       size_changed = TRUE;
860       break;
861
862     case ARG_TABS_SET:
863       text_tag->tabs_set = GTK_VALUE_BOOL (*arg);
864       size_changed = TRUE;
865       break;
866
867     case ARG_INVISIBLE_SET:
868       text_tag->invisible_set = GTK_VALUE_BOOL (*arg);
869       size_changed = TRUE;
870       break;
871       
872     default:
873       g_assert_not_reached ();
874       break;
875     }
876
877   /* FIXME I would like to do this after all set_arg in a single
878      gtk_object_set () have been called. But an idle function
879      won't work; we need to emit when the tag is changed, not
880      when we get around to the event loop. So blah, we eat some
881      inefficiency. */
882
883   /* This is also somewhat weird since we emit another object's
884      signal here, but the two objects are already tightly bound. */
885
886   if (text_tag->table)
887     gtk_signal_emit_by_name (GTK_OBJECT (text_tag->table),
888                              "tag_changed",
889                              text_tag, size_changed);
890 }
891
892 static void
893 get_color_arg (GtkArg *arg, GdkColor *orig)
894 {
895   GdkColor *color;
896
897   color = g_new (GdkColor, 1);
898   *color = *orig;
899   GTK_VALUE_BOXED (*arg) = color;
900 }
901
902 static void
903 gtk_text_tag_get_arg (GtkObject *object, GtkArg *arg, guint arg_id)
904 {
905   GtkTextTag *tag;
906
907   tag = GTK_TEXT_TAG (object);
908
909   switch (arg_id)
910     {
911     case ARG_NAME:
912       GTK_VALUE_STRING (*arg) = g_strdup (tag->name);
913       break;
914
915     case ARG_BACKGROUND_GDK:
916       get_color_arg (arg, &tag->values->appearance.bg_color);
917       break;
918
919     case ARG_FOREGROUND_GDK:
920       get_color_arg (arg, &tag->values->appearance.fg_color);
921       break;
922
923     case ARG_BACKGROUND_STIPPLE:
924       if (tag->bg_stipple_set)
925         GTK_VALUE_BOXED (*arg) = tag->values->appearance.bg_stipple;
926       else
927         GTK_VALUE_BOXED (*arg) = NULL;
928       break;
929
930     case ARG_FOREGROUND_STIPPLE:
931       if (tag->fg_stipple_set)
932         GTK_VALUE_BOXED (*arg) = tag->values->appearance.fg_stipple;
933       else
934         GTK_VALUE_BOXED (*arg) = NULL;
935       break;
936
937     case ARG_FONT:
938       if (tag->family_set &&
939           tag->style_set &&
940           tag->variant_set &&
941           tag->size_set &&
942           tag->stretch_set &&
943           tag->weight_set)
944         GTK_VALUE_STRING (*arg) =
945           pango_font_description_to_string (&tag->values->font);
946       else
947         GTK_VALUE_STRING (*arg) = NULL;
948       break;
949
950     case ARG_FONT_DESC:
951       if (tag->family_set &&
952           tag->style_set &&
953           tag->variant_set &&
954           tag->size_set &&
955           tag->stretch_set &&
956           tag->weight_set)
957         GTK_VALUE_BOXED (*arg) = pango_font_description_copy (&tag->values->font);
958       else
959         GTK_VALUE_BOXED (*arg) = NULL;
960       break;
961
962     case ARG_FAMILY:
963       GTK_VALUE_STRING (*arg) = g_strdup (tag->values->font.family_name);
964       break;
965
966     case ARG_STYLE:
967       GTK_VALUE_ENUM (*arg) = tag->values->font.style;
968       break;
969
970     case ARG_VARIANT:
971       GTK_VALUE_ENUM (*arg) = tag->values->font.variant;
972       break;
973
974     case ARG_WEIGHT:
975       GTK_VALUE_ENUM (*arg) = tag->values->font.weight;
976       break;
977
978     case ARG_STRETCH:
979       GTK_VALUE_ENUM (*arg) = tag->values->font.stretch;
980       break;
981
982     case ARG_SIZE:
983       GTK_VALUE_INT (*arg) = tag->values->font.size;
984       break;
985
986     case ARG_SIZE_POINTS:
987       GTK_VALUE_DOUBLE (*arg) = ((double)tag->values->font.size) / (double)PANGO_SCALE;
988       break;
989       
990     case ARG_PIXELS_ABOVE_LINES:
991       GTK_VALUE_INT (*arg) = tag->values->pixels_above_lines;
992       break;
993
994     case ARG_PIXELS_BELOW_LINES:
995       GTK_VALUE_INT (*arg) = tag->values->pixels_below_lines;
996       break;
997
998     case ARG_PIXELS_INSIDE_WRAP:
999       GTK_VALUE_INT (*arg) = tag->values->pixels_inside_wrap;
1000       break;
1001
1002     case ARG_EDITABLE:
1003       GTK_VALUE_BOOL (*arg) = tag->values->editable;
1004       break;
1005
1006     case ARG_WRAP_MODE:
1007       GTK_VALUE_ENUM (*arg) = tag->values->wrap_mode;
1008       break;
1009
1010     case ARG_JUSTIFY:
1011       GTK_VALUE_ENUM (*arg) = tag->values->justify;
1012       break;
1013
1014     case ARG_LEFT_MARGIN:
1015       GTK_VALUE_INT (*arg) = tag->values->left_margin;
1016       break;
1017
1018     case ARG_INDENT:
1019       GTK_VALUE_INT (*arg) = tag->values->indent;
1020       break;
1021
1022     case ARG_STRIKETHROUGH:
1023       GTK_VALUE_BOOL (*arg) = tag->values->appearance.strikethrough;
1024       break;
1025
1026     case ARG_RIGHT_MARGIN:
1027       GTK_VALUE_INT (*arg) = tag->values->right_margin;
1028       break;
1029
1030     case ARG_UNDERLINE:
1031       GTK_VALUE_ENUM (*arg) = tag->values->appearance.underline;
1032       break;
1033
1034     case ARG_RISE:
1035       GTK_VALUE_INT (*arg) = tag->values->appearance.rise;
1036       break;
1037
1038     case ARG_BG_FULL_HEIGHT:
1039       GTK_VALUE_BOOL (*arg) = tag->values->bg_full_height;
1040       break;
1041
1042     case ARG_LANGUAGE:
1043       GTK_VALUE_STRING (*arg) = g_strdup (tag->values->language);
1044       break;
1045
1046     case ARG_TABS:
1047       GTK_VALUE_POINTER (*arg) = tag->values->tabs ?
1048         pango_tab_array_copy (tag->values->tabs) : NULL;
1049       break;
1050
1051     case ARG_BACKGROUND_SET:
1052     case ARG_BACKGROUND_GDK_SET:
1053       GTK_VALUE_BOOL (*arg) = tag->bg_color_set;
1054       break;
1055
1056     case ARG_FOREGROUND_SET:
1057     case ARG_FOREGROUND_GDK_SET:
1058       GTK_VALUE_BOOL (*arg) = tag->fg_color_set;
1059       break;
1060
1061     case ARG_BACKGROUND_STIPPLE_SET:
1062       GTK_VALUE_BOOL (*arg) = tag->bg_stipple_set;
1063       break;
1064
1065     case ARG_FOREGROUND_STIPPLE_SET:
1066       GTK_VALUE_BOOL (*arg) = tag->fg_stipple_set;
1067       break;
1068
1069     case ARG_FAMILY_SET:
1070       GTK_VALUE_BOOL (*arg) = tag->family_set;
1071       break;
1072
1073     case ARG_STYLE_SET:
1074       GTK_VALUE_BOOL (*arg) = tag->style_set;
1075       break;
1076
1077     case ARG_VARIANT_SET:
1078       GTK_VALUE_BOOL (*arg) = tag->variant_set;
1079       break;
1080
1081     case ARG_WEIGHT_SET:
1082       GTK_VALUE_BOOL (*arg) = tag->weight_set;
1083       break;
1084
1085     case ARG_STRETCH_SET:
1086       GTK_VALUE_BOOL (*arg) = tag->stretch_set;
1087       break;
1088
1089     case ARG_SIZE_SET:
1090       GTK_VALUE_BOOL (*arg) = tag->size_set;
1091       break;
1092       
1093     case ARG_PIXELS_ABOVE_LINES_SET:
1094       GTK_VALUE_BOOL (*arg) = tag->pixels_above_lines_set;
1095       break;
1096
1097     case ARG_PIXELS_BELOW_LINES_SET:
1098       GTK_VALUE_BOOL (*arg) = tag->pixels_below_lines_set;
1099       break;
1100
1101     case ARG_PIXELS_INSIDE_WRAP_SET:
1102       GTK_VALUE_BOOL (*arg) = tag->pixels_inside_wrap_set;
1103       break;
1104
1105     case ARG_EDITABLE_SET:
1106       GTK_VALUE_BOOL (*arg) = tag->editable_set;
1107       break;
1108
1109     case ARG_WRAP_MODE_SET:
1110       GTK_VALUE_BOOL (*arg) = tag->wrap_mode_set;
1111       break;
1112
1113     case ARG_JUSTIFY_SET:
1114       GTK_VALUE_BOOL (*arg) = tag->justify_set;
1115       break;
1116
1117     case ARG_LEFT_MARGIN_SET:
1118       GTK_VALUE_BOOL (*arg) = tag->left_margin_set;
1119       break;
1120
1121     case ARG_INDENT_SET:
1122       GTK_VALUE_BOOL (*arg) = tag->indent_set;
1123       break;
1124
1125     case ARG_STRIKETHROUGH_SET:
1126       GTK_VALUE_BOOL (*arg) = tag->strikethrough_set;
1127       break;
1128
1129     case ARG_RIGHT_MARGIN_SET:
1130       GTK_VALUE_BOOL (*arg) = tag->right_margin_set;
1131       break;
1132
1133     case ARG_UNDERLINE_SET:
1134       GTK_VALUE_BOOL (*arg) = tag->underline_set;
1135       break;
1136
1137     case ARG_RISE_SET:
1138       GTK_VALUE_BOOL (*arg) = tag->rise_set;
1139       break;
1140
1141     case ARG_BG_FULL_HEIGHT_SET:
1142       GTK_VALUE_BOOL (*arg) = tag->bg_full_height_set;
1143       break;
1144
1145     case ARG_LANGUAGE_SET:
1146       GTK_VALUE_BOOL (*arg) = tag->language_set;
1147       break;
1148
1149     case ARG_TABS_SET:
1150       GTK_VALUE_BOOL (*arg) = tag->tabs_set;
1151       break;
1152
1153     case ARG_BACKGROUND:
1154     case ARG_FOREGROUND:
1155     default:
1156       arg->type = GTK_TYPE_INVALID;
1157       break;
1158     }
1159   /* FIXME */
1160   arg->type = GTK_TYPE_INVALID;
1161 }
1162
1163 /*
1164  * Tag operations
1165  */
1166
1167 typedef struct {
1168   gint high;
1169   gint low;
1170   gint delta;
1171 } DeltaData;
1172
1173 static void
1174 delta_priority_foreach (GtkTextTag *tag, gpointer user_data)
1175 {
1176   DeltaData *dd = user_data;
1177
1178   if (tag->priority >= dd->low && tag->priority <= dd->high)
1179     tag->priority += dd->delta;
1180 }
1181
1182 /**
1183  * gtk_text_tag_get_priority:
1184  * @tag: a #GtkTextTag
1185  * 
1186  * Get the tag priority.
1187  * 
1188  * Return value: The tag's priority.
1189  **/
1190 gint
1191 gtk_text_tag_get_priority (GtkTextTag *tag)
1192 {
1193   g_return_val_if_fail (GTK_IS_TEXT_TAG (tag), 0);
1194
1195   return tag->priority;
1196 }
1197
1198 /**
1199  * gtk_text_tag_set_priority:
1200  * @tag: a #GtkTextTag
1201  * @priority: the new priority
1202  * 
1203  * Sets the priority of a #GtkTextTag. Valid priorities are
1204  * start at 0 and go to one less than gtk_text_tag_table_size().
1205  * Each tag in a table has a unique priority; setting the priority
1206  * of one tag shifts the priorities of all the other tags in the
1207  * table to maintain a unique priority for each tag. Higher priority
1208  * tags "win" if two tags both set the same text attribute. When adding
1209  * a tag to a tag table, it will be assigned the highest priority in
1210  * the table by default; so normally the precedence of a set of tags
1211  * is the order in which they were added to the table, or created with
1212  * gtk_text_buffer_create_tag(), which adds the tag to the buffer's table
1213  * automatically.
1214  **/
1215 void
1216 gtk_text_tag_set_priority (GtkTextTag *tag,
1217                            gint        priority)
1218 {
1219   DeltaData dd;
1220
1221   g_return_if_fail (GTK_IS_TEXT_TAG (tag));
1222   g_return_if_fail (tag->table != NULL);
1223   g_return_if_fail (priority >= 0);
1224   g_return_if_fail (priority < gtk_text_tag_table_size (tag->table));
1225
1226   if (priority == tag->priority)
1227     return;
1228
1229   if (priority < tag->priority)
1230     {
1231       dd.low = priority;
1232       dd.high = tag->priority - 1;
1233       dd.delta = 1;
1234     }
1235   else
1236     {
1237       dd.low = tag->priority + 1;
1238       dd.high = priority;
1239       dd.delta = -1;
1240     }
1241
1242   gtk_text_tag_table_foreach (tag->table,
1243                               delta_priority_foreach,
1244                               &dd);
1245
1246   tag->priority = priority;
1247 }
1248
1249 /**
1250  * gtk_text_tag_event:
1251  * @tag: a #GtkTextTag
1252  * @event_object: object that received the event, such as a widget
1253  * @event: the event
1254  * @iter: location where the event was received
1255  * 
1256  * Emits the "event" signal on the #GtkTextTag.
1257  * 
1258  * Return value: result of signal emission (whether the event was handled)
1259  **/
1260 gint
1261 gtk_text_tag_event (GtkTextTag        *tag,
1262                     GObject           *event_object,
1263                     GdkEvent          *event,
1264                     const GtkTextIter *iter)
1265 {
1266   gint retval = FALSE;
1267
1268   g_return_val_if_fail (GTK_IS_TEXT_TAG (tag), FALSE);
1269   g_return_val_if_fail (GTK_IS_OBJECT (event_object), FALSE);
1270   g_return_val_if_fail (event != NULL, FALSE);
1271
1272   gtk_signal_emit (GTK_OBJECT (tag),
1273                    signals[EVENT],
1274                    event_object,
1275                    event,
1276                    iter,
1277                    &retval);
1278
1279   return retval;
1280 }
1281
1282 static int
1283 tag_sort_func (gconstpointer first, gconstpointer second)
1284 {
1285   GtkTextTag *tag1, *tag2;
1286
1287   tag1 = * (GtkTextTag **) first;
1288   tag2 = * (GtkTextTag **) second;
1289   return tag1->priority - tag2->priority;
1290 }
1291
1292 void
1293 gtk_text_tag_array_sort (GtkTextTag** tag_array_p,
1294                          guint len)
1295 {
1296   int i, j, prio;
1297   GtkTextTag **tag;
1298   GtkTextTag **maxPtrPtr, *tmp;
1299
1300   g_return_if_fail (tag_array_p != NULL);
1301   g_return_if_fail (len > 0);
1302
1303   if (len < 2) {
1304     return;
1305   }
1306   if (len < 20) {
1307     GtkTextTag **iter = tag_array_p;
1308
1309     for (i = len-1; i > 0; i--, iter++) {
1310       maxPtrPtr = tag = iter;
1311       prio = tag[0]->priority;
1312       for (j = i, tag++; j > 0; j--, tag++) {
1313         if (tag[0]->priority < prio) {
1314           prio = tag[0]->priority;
1315           maxPtrPtr = tag;
1316         }
1317       }
1318       tmp = *maxPtrPtr;
1319       *maxPtrPtr = *iter;
1320       *iter = tmp;
1321     }
1322   } else {
1323     qsort ((void *) tag_array_p, (unsigned) len, sizeof (GtkTextTag *),
1324            tag_sort_func);
1325   }
1326
1327 #if 0
1328   {
1329     printf ("Sorted tag array: \n");
1330     i = 0;
1331     while (i < len)
1332       {
1333         GtkTextTag *t = tag_array_p[i];
1334         printf ("  %s priority %d\n", t->name, t->priority);
1335
1336         ++i;
1337       }
1338   }
1339 #endif
1340 }
1341
1342 /*
1343  * Attributes
1344  */
1345
1346 /**
1347  * gtk_text_attributes_new:
1348  * 
1349  * Creates a #GtkTextAttributes, which describes
1350  * a set of properties on some text.
1351  * 
1352  * Return value: a new #GtkTextAttributes
1353  **/
1354 GtkTextAttributes*
1355 gtk_text_attributes_new (void)
1356 {
1357   GtkTextAttributes *values;
1358
1359   values = g_new0 (GtkTextAttributes, 1);
1360
1361   /* 0 is a valid value for most of the struct */
1362
1363   values->refcount = 1;
1364
1365   values->language = gtk_get_default_language ();
1366
1367   return values;
1368 }
1369
1370 /* FIXME change the signature of this to be correct */
1371 void
1372 gtk_text_attributes_copy (GtkTextAttributes *src,
1373                           GtkTextAttributes *dest)
1374 {
1375   guint orig_refcount;
1376
1377   g_return_if_fail (!dest->realized);
1378
1379   if (src == dest)
1380     return;
1381
1382   /* Add refs */
1383
1384   if (src->appearance.bg_stipple)
1385     gdk_bitmap_ref (src->appearance.bg_stipple);
1386
1387   if (src->appearance.fg_stipple)
1388     gdk_bitmap_ref (src->appearance.fg_stipple);
1389
1390   /* Remove refs */
1391
1392   if (dest->appearance.bg_stipple)
1393     gdk_bitmap_unref (dest->appearance.bg_stipple);
1394
1395   if (dest->appearance.fg_stipple)
1396     gdk_bitmap_unref (dest->appearance.fg_stipple);
1397
1398   if (dest->language)
1399     g_free (dest->language);
1400
1401   if (dest->font.family_name)
1402     g_free (dest->font.family_name);
1403   
1404   /* Copy */
1405   orig_refcount = dest->refcount;
1406
1407   *dest = *src;
1408
1409   if (src->tabs)
1410     dest->tabs = pango_tab_array_copy (src->tabs);
1411
1412   dest->language = g_strdup (src->language);
1413
1414   dest->font.family_name = g_strdup (src->font.family_name);
1415   
1416   dest->refcount = orig_refcount;
1417   dest->realized = FALSE;
1418 }
1419
1420 void
1421 gtk_text_attributes_ref (GtkTextAttributes *values)
1422 {
1423   g_return_if_fail (values != NULL);
1424
1425   values->refcount += 1;
1426 }
1427
1428 void
1429 gtk_text_attributes_unref (GtkTextAttributes *values)
1430 {
1431   g_return_if_fail (values != NULL);
1432   g_return_if_fail (values->refcount > 0);
1433
1434   values->refcount -= 1;
1435
1436   if (values->refcount == 0)
1437     {
1438       g_assert (!values->realized);
1439
1440       if (values->appearance.bg_stipple)
1441         gdk_bitmap_unref (values->appearance.bg_stipple);
1442
1443       if (values->appearance.fg_stipple)
1444         gdk_bitmap_unref (values->appearance.fg_stipple);
1445
1446       if (values->tabs)
1447         pango_tab_array_free (values->tabs);
1448
1449       if (values->language)
1450         g_free (values->language);
1451
1452       if (values->font.family_name)
1453         g_free (values->font.family_name);
1454       
1455       g_free (values);
1456     }
1457 }
1458
1459 void
1460 gtk_text_attributes_realize (GtkTextAttributes *values,
1461                              GdkColormap *cmap,
1462                              GdkVisual *visual)
1463 {
1464   g_return_if_fail (values != NULL);
1465   g_return_if_fail (values->refcount > 0);
1466   g_return_if_fail (!values->realized);
1467
1468   /* It is wrong to use this colormap, FIXME */
1469   gdk_colormap_alloc_color (cmap,
1470                             &values->appearance.fg_color,
1471                             FALSE, TRUE);
1472
1473   gdk_colormap_alloc_color (cmap,
1474                             &values->appearance.bg_color,
1475                             FALSE, TRUE);
1476
1477   values->realized = TRUE;
1478 }
1479
1480 void
1481 gtk_text_attributes_unrealize (GtkTextAttributes *values,
1482                                GdkColormap *cmap,
1483                                GdkVisual *visual)
1484 {
1485   g_return_if_fail (values != NULL);
1486   g_return_if_fail (values->refcount > 0);
1487   g_return_if_fail (values->realized);
1488
1489   gdk_colormap_free_colors (cmap,
1490                             &values->appearance.fg_color, 1);
1491
1492
1493   gdk_colormap_free_colors (cmap,
1494                             &values->appearance.bg_color, 1);
1495
1496   values->appearance.fg_color.pixel = 0;
1497   values->appearance.bg_color.pixel = 0;
1498
1499   values->realized = FALSE;
1500 }
1501
1502 void
1503 gtk_text_attributes_fill_from_tags (GtkTextAttributes *dest,
1504                                     GtkTextTag**       tags,
1505                                     guint              n_tags)
1506 {
1507   guint n = 0;
1508
1509   g_return_if_fail (!dest->realized);
1510
1511   while (n < n_tags)
1512     {
1513       GtkTextTag *tag = tags[n];
1514       GtkTextAttributes *vals = tag->values;
1515
1516       if (n > 0)
1517         g_assert (tags[n]->priority > tags[n-1]->priority);
1518
1519       if (tag->bg_color_set)
1520         {
1521           dest->appearance.bg_color = vals->appearance.bg_color;
1522
1523           dest->appearance.draw_bg = TRUE;
1524         }
1525       if (tag->fg_color_set)
1526         dest->appearance.fg_color = vals->appearance.fg_color;
1527       
1528       if (tag->bg_stipple_set)
1529         {
1530           gdk_bitmap_ref (vals->appearance.bg_stipple);
1531           if (dest->appearance.bg_stipple)
1532             gdk_bitmap_unref (dest->appearance.bg_stipple);
1533           dest->appearance.bg_stipple = vals->appearance.bg_stipple;
1534
1535           dest->appearance.draw_bg = TRUE;
1536         }
1537
1538       if (tag->fg_stipple_set)
1539         {
1540           gdk_bitmap_ref (vals->appearance.fg_stipple);
1541           if (dest->appearance.fg_stipple)
1542             gdk_bitmap_unref (dest->appearance.fg_stipple);
1543           dest->appearance.fg_stipple = vals->appearance.fg_stipple;
1544         }
1545
1546       if (tag->family_set)
1547         {
1548           if (dest->font.family_name)
1549             g_free (dest->font.family_name);
1550
1551           dest->font.family_name = g_strdup (vals->font.family_name);
1552         }
1553
1554       if (tag->style_set)
1555         dest->font.style = vals->font.style;
1556
1557       if (tag->variant_set)
1558         dest->font.variant = vals->font.variant;
1559
1560       if (tag->weight_set)
1561         dest->font.weight = vals->font.weight;
1562
1563       if (tag->stretch_set)
1564         dest->font.stretch = vals->font.stretch;
1565
1566       if (tag->size_set)
1567         dest->font.size = vals->font.size;
1568
1569       if (tag->justify_set)
1570         dest->justify = vals->justify;
1571
1572       if (vals->direction != GTK_TEXT_DIR_NONE)
1573         dest->direction = vals->direction;
1574
1575       if (tag->left_margin_set)
1576         dest->left_margin = vals->left_margin;
1577
1578       if (tag->indent_set)
1579         dest->indent = vals->indent;
1580
1581       if (tag->rise_set)
1582         dest->appearance.rise = vals->appearance.rise;
1583
1584       if (tag->right_margin_set)
1585         dest->right_margin = vals->right_margin;
1586
1587       if (tag->pixels_above_lines_set)
1588         dest->pixels_above_lines = vals->pixels_above_lines;
1589
1590       if (tag->pixels_below_lines_set)
1591         dest->pixels_below_lines = vals->pixels_below_lines;
1592
1593       if (tag->pixels_inside_wrap_set)
1594         dest->pixels_inside_wrap = vals->pixels_inside_wrap;
1595
1596       if (tag->tabs_set)
1597         {
1598           if (dest->tabs)
1599             pango_tab_array_free (dest->tabs);
1600           dest->tabs = pango_tab_array_copy (vals->tabs);
1601         }
1602
1603       if (tag->wrap_mode_set)
1604         dest->wrap_mode = vals->wrap_mode;
1605
1606       if (tag->underline_set)
1607         dest->appearance.underline = vals->appearance.underline;
1608
1609       if (tag->strikethrough_set)
1610         dest->appearance.strikethrough = vals->appearance.strikethrough;
1611
1612       if (tag->invisible_set)
1613         dest->invisible = vals->invisible;
1614
1615       if (tag->editable_set)
1616         dest->editable = vals->editable;
1617
1618       if (tag->bg_full_height_set)
1619         dest->bg_full_height = vals->bg_full_height;
1620
1621       if (tag->language_set)
1622         {
1623           g_free (dest->language);
1624           dest->language = g_strdup (vals->language);
1625         }
1626
1627       ++n;
1628     }
1629 }
1630
1631 gboolean
1632 gtk_text_tag_affects_size (GtkTextTag *tag)
1633 {
1634   g_return_val_if_fail (GTK_IS_TEXT_TAG (tag), FALSE);
1635
1636   return
1637     tag->family_set ||
1638     tag->style_set ||
1639     tag->variant_set ||
1640     tag->weight_set ||
1641     tag->size_set ||
1642     tag->stretch_set ||
1643     tag->justify_set ||
1644     tag->left_margin_set ||
1645     tag->indent_set ||
1646     tag->rise_set ||
1647     tag->right_margin_set ||
1648     tag->pixels_above_lines_set ||
1649     tag->pixels_below_lines_set ||
1650     tag->pixels_inside_wrap_set ||
1651     tag->tabs_set ||
1652     tag->underline_set ||
1653     tag->wrap_mode_set ||
1654     tag->invisible_set;
1655 }
1656
1657 gboolean
1658 gtk_text_tag_affects_nonsize_appearance (GtkTextTag *tag)
1659 {
1660   g_return_val_if_fail (GTK_IS_TEXT_TAG (tag), FALSE);
1661
1662   return
1663     tag->bg_color_set ||
1664     tag->bg_stipple_set ||
1665     tag->fg_color_set ||
1666     tag->fg_stipple_set ||
1667     tag->strikethrough_set ||
1668     tag->bg_full_height_set;
1669 }