1 /* gtktexttag.c - text tag object
2  *
3  * Copyright (c) 1992-1994 The Regents of the University of California.
4  * Copyright (c) 1994-1997 Sun Microsystems, Inc.
5  * Copyright (c) 2000      Red Hat, Inc.
6  * Tk -> Gtk port by Havoc Pennington <hp@redhat.com>
7  *
8  * This software is copyrighted by the Regents of the University of
9  * California, Sun Microsystems, Inc., and other parties.  The
10  * following terms apply to all files associated with the software
11  * unless explicitly disclaimed in individual files.
12  *
13  * The authors hereby grant permission to use, copy, modify,
14  * distribute, and license this software and its documentation for any
15  * purpose, provided that existing copyright notices are retained in
16  * all copies and that this notice is included verbatim in any
17  * distributions. No written agreement, license, or royalty fee is
18  * required for any of the authorized uses.  Modifications to this
19  * software may be copyrighted by their authors and need not follow
20  * the licensing terms described here, provided that the new terms are
21  * clearly indicated on the first page of each file where they apply.
22  *
23  * IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY
24  * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
25  * DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION,
26  * OR ANY DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED
27  * OF THE POSSIBILITY OF SUCH DAMAGE.
28  *
29  * THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
30  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
31  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
32  * NON-INFRINGEMENT.  THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
33  * AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
34  * MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
35  *
36  * GOVERNMENT USE: If you are acquiring this software on behalf of the
37  * U.S. government, the Government shall have only "Restricted Rights"
38  * in the software and related documentation as defined in the Federal
39  * Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2).  If you
40  * are acquiring the software on behalf of the Department of Defense,
41  * the software shall be classified as "Commercial Computer Software"
42  * and the Government shall have only "Restricted Rights" as defined
43  * in Clause 252.227-7013 (c) (1) of DFARs.  Notwithstanding the
44  * foregoing, the authors grant the U.S. Government and others acting
45  * in its behalf permission to use and distribute the software in
46  * accordance with the terms specified in this license.
47  *
48  */
49 
50 /**
51  * SECTION:gtktexttag
52  * @Title: GtkTextTag
53  * @Short_description: A tag that can be applied to text in a GtkTextBuffer
54  *
55  * You may wish to begin by reading the
56  * [text widget conceptual overview][TextWidget]
57  * which gives an overview of all the objects and
58  * data types related to the text widget and how they work together.
59  *
60  * Tags should be in the #GtkTextTagTable for a given #GtkTextBuffer
61  * before using them with that buffer.
62  *
63  * gtk_text_buffer_create_tag() is the best way to create tags.
64  * See “gtk3-demo” for numerous examples.
65  *
66  * For each property of #GtkTextTag, there is a “set” property, e.g.
67  * “font-set” corresponds to “font”. These “set” properties reflect
68  * whether a property has been set or not.
69  * They are maintained by GTK+ and you should not set them independently.
70  */
71 
72 #include "config.h"
73 
74 #include <stdlib.h>
75 #include <string.h>
76 
77 #include "gtktextattributesprivate.h"
78 #include "gtktexttag.h"
79 #include "gtktexttypes.h"
80 #include "gtktexttagtable.h"
81 #include "gtktexttagtableprivate.h"
82 #include "gtkintl.h"
83 #include "gtkmarshalers.h"
84 #include "gtkprivate.h"
85 #include "gtktypebuiltins.h"
86 
87 enum {
88   EVENT,
89   LAST_SIGNAL
90 };
91 
92 enum {
93   PROP_0,
94   /* Construct args */
95   PROP_NAME,
96 
97   /* Style args */
98   PROP_BACKGROUND,
99   PROP_FOREGROUND,
100   PROP_BACKGROUND_GDK,
101   PROP_FOREGROUND_GDK,
102   PROP_BACKGROUND_RGBA,
103   PROP_FOREGROUND_RGBA,
104   PROP_FONT,
105   PROP_FONT_DESC,
106   PROP_FAMILY,
107   PROP_STYLE,
108   PROP_VARIANT,
109   PROP_WEIGHT,
110   PROP_STRETCH,
111   PROP_SIZE,
112   PROP_SIZE_POINTS,
113   PROP_SCALE,
114   PROP_PIXELS_ABOVE_LINES,
115   PROP_PIXELS_BELOW_LINES,
116   PROP_PIXELS_INSIDE_WRAP,
117   PROP_EDITABLE,
118   PROP_WRAP_MODE,
119   PROP_JUSTIFICATION,
120   PROP_DIRECTION,
121   PROP_LEFT_MARGIN,
122   PROP_INDENT,
123   PROP_STRIKETHROUGH,
124   PROP_STRIKETHROUGH_RGBA,
125   PROP_RIGHT_MARGIN,
126   PROP_UNDERLINE,
127   PROP_UNDERLINE_RGBA,
128   PROP_RISE,
129   PROP_BACKGROUND_FULL_HEIGHT,
130   PROP_LANGUAGE,
131   PROP_TABS,
132   PROP_INVISIBLE,
133   PROP_PARAGRAPH_BACKGROUND,
134   PROP_PARAGRAPH_BACKGROUND_GDK,
135   PROP_PARAGRAPH_BACKGROUND_RGBA,
136   PROP_FALLBACK,
137   PROP_LETTER_SPACING,
138   PROP_FONT_FEATURES,
139 
140   /* Behavior args */
141   PROP_ACCUMULATIVE_MARGIN,
142 
143   /* Whether-a-style-arg-is-set args */
144   PROP_BACKGROUND_SET,
145   PROP_FOREGROUND_SET,
146   PROP_FAMILY_SET,
147   PROP_STYLE_SET,
148   PROP_VARIANT_SET,
149   PROP_WEIGHT_SET,
150   PROP_STRETCH_SET,
151   PROP_SIZE_SET,
152   PROP_SCALE_SET,
153   PROP_PIXELS_ABOVE_LINES_SET,
154   PROP_PIXELS_BELOW_LINES_SET,
155   PROP_PIXELS_INSIDE_WRAP_SET,
156   PROP_EDITABLE_SET,
157   PROP_WRAP_MODE_SET,
158   PROP_JUSTIFICATION_SET,
159   PROP_LEFT_MARGIN_SET,
160   PROP_INDENT_SET,
161   PROP_STRIKETHROUGH_SET,
162   PROP_STRIKETHROUGH_RGBA_SET,
163   PROP_RIGHT_MARGIN_SET,
164   PROP_UNDERLINE_SET,
165   PROP_UNDERLINE_RGBA_SET,
166   PROP_RISE_SET,
167   PROP_BACKGROUND_FULL_HEIGHT_SET,
168   PROP_LANGUAGE_SET,
169   PROP_TABS_SET,
170   PROP_INVISIBLE_SET,
171   PROP_PARAGRAPH_BACKGROUND_SET,
172   PROP_FALLBACK_SET,
173   PROP_LETTER_SPACING_SET,
174   PROP_FONT_FEATURES_SET,
175 
176   LAST_ARG
177 };
178 static void gtk_text_tag_finalize     (GObject         *object);
179 static void gtk_text_tag_set_property (GObject         *object,
180                                        guint            prop_id,
181                                        const GValue    *value,
182                                        GParamSpec      *pspec);
183 static void gtk_text_tag_get_property (GObject         *object,
184                                        guint            prop_id,
185                                        GValue          *value,
186                                        GParamSpec      *pspec);
187 
188 static guint signals[LAST_SIGNAL] = { 0 };
189 
G_DEFINE_TYPE_WITH_PRIVATE(GtkTextTag,gtk_text_tag,G_TYPE_OBJECT)190 G_DEFINE_TYPE_WITH_PRIVATE (GtkTextTag, gtk_text_tag, G_TYPE_OBJECT)
191 
192 static void
193 gtk_text_tag_class_init (GtkTextTagClass *klass)
194 {
195   GObjectClass *object_class = G_OBJECT_CLASS (klass);
196 
197   object_class->set_property = gtk_text_tag_set_property;
198   object_class->get_property = gtk_text_tag_get_property;
199 
200   object_class->finalize = gtk_text_tag_finalize;
201 
202   /* Construct */
203   g_object_class_install_property (object_class,
204                                    PROP_NAME,
205                                    g_param_spec_string ("name",
206                                                         P_("Tag name"),
207                                                         P_("Name used to refer to the text tag. NULL for anonymous tags"),
208                                                         NULL,
209                                                         GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
210 
211   /* Style args */
212 
213   g_object_class_install_property (object_class,
214                                    PROP_BACKGROUND,
215                                    g_param_spec_string ("background",
216                                                         P_("Background color name"),
217                                                         P_("Background color as a string"),
218                                                         NULL,
219                                                         GTK_PARAM_WRITABLE));
220 
221   /**
222    * GtkTextTag:background-gdk:
223    *
224    * Background color as a #GdkColor.
225    *
226    * Deprecated: 3.4: Use #GtkTextTag:background-rgba instead.
227    */
228   g_object_class_install_property (object_class,
229                                    PROP_BACKGROUND_GDK,
230                                    g_param_spec_boxed ("background-gdk",
231                                                        P_("Background color"),
232                                                        P_("Background color as a GdkColor"),
233                                                        g_type_from_name ("GdkColor"),
234                                                        GTK_PARAM_READWRITE | G_PARAM_DEPRECATED));
235 
236   /**
237    * GtkTextTag:background-rgba:
238    *
239    * Background color as a #GdkRGBA.
240    *
241    * Since: 3.2
242    */
243   g_object_class_install_property (object_class,
244                                    PROP_BACKGROUND_RGBA,
245                                    g_param_spec_boxed ("background-rgba",
246                                                        P_("Background RGBA"),
247                                                        P_("Background color as a GdkRGBA"),
248                                                        GDK_TYPE_RGBA,
249                                                        GTK_PARAM_READWRITE));
250 
251   g_object_class_install_property (object_class,
252                                    PROP_BACKGROUND_FULL_HEIGHT,
253                                    g_param_spec_boolean ("background-full-height",
254                                                          P_("Background full height"),
255                                                          P_("Whether the background color fills the entire line height or only the height of the tagged characters"),
256                                                          FALSE,
257                                                          GTK_PARAM_READWRITE));
258 
259   g_object_class_install_property (object_class,
260                                    PROP_FOREGROUND,
261                                    g_param_spec_string ("foreground",
262                                                         P_("Foreground color name"),
263                                                         P_("Foreground color as a string"),
264                                                         NULL,
265                                                         GTK_PARAM_WRITABLE));
266 
267   /**
268    * GtkTextTag:foreground-gdk:
269    *
270    * Foreground color as a #GdkColor.
271    *
272    * Deprecated: 3.4: Use #GtkTextTag:foreground-rgba instead.
273    */
274   g_object_class_install_property (object_class,
275                                    PROP_FOREGROUND_GDK,
276                                    g_param_spec_boxed ("foreground-gdk",
277                                                        P_("Foreground color"),
278                                                        P_("Foreground color as a GdkColor"),
279                                                        g_type_from_name ("GdkColor"),
280                                                        GTK_PARAM_READWRITE | G_PARAM_DEPRECATED));
281 
282   /**
283    * GtkTextTag:foreground-rgba:
284    *
285    * Foreground color as a #GdkRGBA.
286    *
287    * Since: 3.2
288    */
289   g_object_class_install_property (object_class,
290                                    PROP_FOREGROUND_RGBA,
291                                    g_param_spec_boxed ("foreground-rgba",
292                                                        P_("Foreground RGBA"),
293                                                        P_("Foreground color as a GdkRGBA"),
294                                                        GDK_TYPE_RGBA,
295                                                        GTK_PARAM_READWRITE));
296 
297   g_object_class_install_property (object_class,
298                                    PROP_DIRECTION,
299                                    g_param_spec_enum ("direction",
300                                                       P_("Text direction"),
301                                                       P_("Text direction, e.g. right-to-left or left-to-right"),
302                                                       GTK_TYPE_TEXT_DIRECTION,
303                                                       GTK_TEXT_DIR_NONE,
304                                                       GTK_PARAM_READWRITE));
305 
306   g_object_class_install_property (object_class,
307                                    PROP_EDITABLE,
308                                    g_param_spec_boolean ("editable",
309                                                          P_("Editable"),
310                                                          P_("Whether the text can be modified by the user"),
311                                                          TRUE,
312                                                          GTK_PARAM_READWRITE));
313 
314   /**
315    * GtkTextTag:font:
316    *
317    * Font description as string, e.g. \"Sans Italic 12\".
318    *
319    * Note that the initial value of this property depends on
320    * the internals of #PangoFontDescription.
321    */
322   g_object_class_install_property (object_class,
323                                    PROP_FONT,
324                                    g_param_spec_string ("font",
325                                                         P_("Font"),
326                                                         P_("Font description as a string, e.g. \"Sans Italic 12\""),
327                                                         NULL,
328                                                         GTK_PARAM_READWRITE));
329 
330   g_object_class_install_property (object_class,
331                                    PROP_FONT_DESC,
332                                    g_param_spec_boxed ("font-desc",
333                                                        P_("Font"),
334                                                        P_("Font description as a PangoFontDescription struct"),
335                                                        PANGO_TYPE_FONT_DESCRIPTION,
336                                                        GTK_PARAM_READWRITE));
337 
338   g_object_class_install_property (object_class,
339                                    PROP_FAMILY,
340                                    g_param_spec_string ("family",
341                                                         P_("Font family"),
342                                                         P_("Name of the font family, e.g. Sans, Helvetica, Times, Monospace"),
343                                                         NULL,
344                                                         GTK_PARAM_READWRITE));
345 
346   g_object_class_install_property (object_class,
347                                    PROP_STYLE,
348                                    g_param_spec_enum ("style",
349                                                       P_("Font style"),
350                                                       P_("Font style as a PangoStyle, e.g. PANGO_STYLE_ITALIC"),
351                                                       PANGO_TYPE_STYLE,
352                                                       PANGO_STYLE_NORMAL,
353                                                       GTK_PARAM_READWRITE));
354 
355   g_object_class_install_property (object_class,
356                                    PROP_VARIANT,
357                                    g_param_spec_enum ("variant",
358                                                      P_("Font variant"),
359                                                      P_("Font variant as a PangoVariant, e.g. PANGO_VARIANT_SMALL_CAPS"),
360                                                       PANGO_TYPE_VARIANT,
361                                                       PANGO_VARIANT_NORMAL,
362                                                       GTK_PARAM_READWRITE));
363 
364   g_object_class_install_property (object_class,
365                                    PROP_WEIGHT,
366                                    g_param_spec_int ("weight",
367                                                      P_("Font weight"),
368                                                      P_("Font weight as an integer, see predefined values in PangoWeight; for example, PANGO_WEIGHT_BOLD"),
369                                                      0,
370                                                      G_MAXINT,
371                                                      PANGO_WEIGHT_NORMAL,
372                                                      GTK_PARAM_READWRITE));
373 
374 
375   g_object_class_install_property (object_class,
376                                    PROP_STRETCH,
377                                    g_param_spec_enum ("stretch",
378                                                       P_("Font stretch"),
379                                                       P_("Font stretch as a PangoStretch, e.g. PANGO_STRETCH_CONDENSED"),
380                                                       PANGO_TYPE_STRETCH,
381                                                       PANGO_STRETCH_NORMAL,
382                                                       GTK_PARAM_READWRITE));
383 
384   g_object_class_install_property (object_class,
385                                    PROP_SIZE,
386                                    g_param_spec_int ("size",
387                                                      P_("Font size"),
388                                                      P_("Font size in Pango units"),
389                                                      0,
390                                                      G_MAXINT,
391                                                      0,
392                                                      GTK_PARAM_READWRITE));
393 
394   g_object_class_install_property (object_class,
395                                    PROP_SCALE,
396                                    g_param_spec_double ("scale",
397                                                         P_("Font scale"),
398                                                         P_("Font size as a scale factor relative to the default font size. This properly adapts to theme changes etc. so is recommended. Pango predefines some scales such as PANGO_SCALE_X_LARGE"),
399                                                         0.0,
400                                                         G_MAXDOUBLE,
401                                                         1.0,
402                                                         GTK_PARAM_READWRITE));
403 
404   g_object_class_install_property (object_class,
405                                    PROP_SIZE_POINTS,
406                                    g_param_spec_double ("size-points",
407                                                         P_("Font points"),
408                                                         P_("Font size in points"),
409                                                         0.0,
410                                                         G_MAXDOUBLE,
411                                                         0.0,
412                                                         GTK_PARAM_READWRITE));
413 
414   g_object_class_install_property (object_class,
415                                    PROP_JUSTIFICATION,
416                                    g_param_spec_enum ("justification",
417                                                       P_("Justification"),
418                                                       P_("Left, right, or center justification"),
419                                                       GTK_TYPE_JUSTIFICATION,
420                                                       GTK_JUSTIFY_LEFT,
421                                                       GTK_PARAM_READWRITE));
422 
423   /**
424    * GtkTextTag:language:
425    *
426    * The language this text is in, as an ISO code. Pango can use this as a
427    * hint when rendering the text. If not set, an appropriate default will be
428    * used.
429    *
430    * Note that the initial value of this property depends on the current
431    * locale, see also gtk_get_default_language().
432    */
433   g_object_class_install_property (object_class,
434                                    PROP_LANGUAGE,
435                                    g_param_spec_string ("language",
436                                                         P_("Language"),
437                                                         P_("The language this text is in, as an ISO code. Pango can use this as a hint when rendering the text. If not set, an appropriate default will be used."),
438                                                         NULL,
439                                                         GTK_PARAM_READWRITE));
440 
441   g_object_class_install_property (object_class,
442                                    PROP_LEFT_MARGIN,
443                                    g_param_spec_int ("left-margin",
444                                                      P_("Left margin"),
445                                                      P_("Width of the left margin in pixels"),
446                                                      0,
447                                                      G_MAXINT,
448                                                      0,
449                                                      GTK_PARAM_READWRITE));
450 
451   g_object_class_install_property (object_class,
452                                    PROP_RIGHT_MARGIN,
453                                    g_param_spec_int ("right-margin",
454                                                      P_("Right margin"),
455                                                      P_("Width of the right margin in pixels"),
456                                                      0,
457                                                      G_MAXINT,
458                                                      0,
459                                                      GTK_PARAM_READWRITE));
460 
461 
462   g_object_class_install_property (object_class,
463                                    PROP_INDENT,
464                                    g_param_spec_int ("indent",
465                                                      P_("Indent"),
466                                                      P_("Amount to indent the paragraph, in pixels"),
467                                                      G_MININT,
468                                                      G_MAXINT,
469                                                      0,
470                                                      GTK_PARAM_READWRITE));
471 
472 
473   g_object_class_install_property (object_class,
474                                    PROP_RISE,
475                                    g_param_spec_int ("rise",
476                                                      P_("Rise"),
477                                                      P_("Offset of text above the baseline (below the baseline if rise is negative) in Pango units"),
478 						     G_MININT,
479                                                      G_MAXINT,
480                                                      0,
481                                                      GTK_PARAM_READWRITE));
482 
483   g_object_class_install_property (object_class,
484                                    PROP_PIXELS_ABOVE_LINES,
485                                    g_param_spec_int ("pixels-above-lines",
486                                                      P_("Pixels above lines"),
487                                                      P_("Pixels of blank space above paragraphs"),
488                                                      0,
489                                                      G_MAXINT,
490                                                      0,
491                                                      GTK_PARAM_READWRITE));
492 
493   g_object_class_install_property (object_class,
494                                    PROP_PIXELS_BELOW_LINES,
495                                    g_param_spec_int ("pixels-below-lines",
496                                                      P_("Pixels below lines"),
497                                                      P_("Pixels of blank space below paragraphs"),
498                                                      0,
499                                                      G_MAXINT,
500                                                      0,
501                                                      GTK_PARAM_READWRITE));
502 
503   g_object_class_install_property (object_class,
504                                    PROP_PIXELS_INSIDE_WRAP,
505                                    g_param_spec_int ("pixels-inside-wrap",
506                                                      P_("Pixels inside wrap"),
507                                                      P_("Pixels of blank space between wrapped lines in a paragraph"),
508                                                      0,
509                                                      G_MAXINT,
510                                                      0,
511                                                      GTK_PARAM_READWRITE));
512 
513   g_object_class_install_property (object_class,
514                                    PROP_STRIKETHROUGH,
515                                    g_param_spec_boolean ("strikethrough",
516                                                          P_("Strikethrough"),
517                                                          P_("Whether to strike through the text"),
518                                                          FALSE,
519                                                          GTK_PARAM_READWRITE));
520 
521   g_object_class_install_property (object_class,
522                                    PROP_UNDERLINE,
523                                    g_param_spec_enum ("underline",
524                                                       P_("Underline"),
525                                                       P_("Style of underline for this text"),
526                                                       PANGO_TYPE_UNDERLINE,
527                                                       PANGO_UNDERLINE_NONE,
528                                                       GTK_PARAM_READWRITE));
529 
530   /**
531    * GtkTextTag:underline-rgba:
532    *
533    * This property modifies the color of underlines. If not set, underlines
534    * will use the forground color.
535    *
536    * If #GtkTextTag:underline is set to %PANGO_UNDERLINE_ERROR, an alternate
537    * color may be applied instead of the foreground. Setting this property
538    * will always override those defaults.
539    *
540    * Since: 3.16
541    */
542   g_object_class_install_property (object_class,
543                                    PROP_UNDERLINE_RGBA,
544                                    g_param_spec_boxed ("underline-rgba",
545                                                        P_("Underline RGBA"),
546                                                        P_("Color of underline for this text"),
547                                                        GDK_TYPE_RGBA,
548                                                        GTK_PARAM_READWRITE));
549 
550   /**
551    * GtkTextTag:strikethrough-rgba:
552    *
553    * This property modifies the color of strikeouts. If not set, strikeouts
554    * will use the forground color.
555    *
556    * Since: 3.16
557    */
558   g_object_class_install_property (object_class,
559                                    PROP_STRIKETHROUGH_RGBA,
560                                    g_param_spec_boxed ("strikethrough-rgba",
561                                                        P_("Strikethrough RGBA"),
562                                                        P_("Color of strikethrough for this text"),
563                                                        GDK_TYPE_RGBA,
564                                                        GTK_PARAM_READWRITE));
565 
566   g_object_class_install_property (object_class,
567                                    PROP_WRAP_MODE,
568                                    g_param_spec_enum ("wrap-mode",
569                                                      P_("Wrap mode"),
570                                                      P_("Whether to wrap lines never, at word boundaries, or at character boundaries"),
571                                                       GTK_TYPE_WRAP_MODE,
572                                                       GTK_WRAP_NONE,
573                                                       GTK_PARAM_READWRITE));
574 
575 
576   g_object_class_install_property (object_class,
577                                    PROP_TABS,
578                                    g_param_spec_boxed ("tabs",
579                                                        P_("Tabs"),
580                                                        P_("Custom tabs for this text"),
581                                                        PANGO_TYPE_TAB_ARRAY,
582                                                        GTK_PARAM_READWRITE));
583 
584   /**
585    * GtkTextTag:invisible:
586    *
587    * Whether this text is hidden.
588    *
589    * Note that there may still be problems with the support for invisible
590    * text, in particular when navigating programmatically inside a buffer
591    * containing invisible segments.
592    *
593    * Since: 2.8
594    */
595   g_object_class_install_property (object_class,
596                                    PROP_INVISIBLE,
597                                    g_param_spec_boolean ("invisible",
598                                                          P_("Invisible"),
599                                                          P_("Whether this text is hidden."),
600                                                          FALSE,
601                                                          GTK_PARAM_READWRITE));
602 
603   /**
604    * GtkTextTag:paragraph-background:
605    *
606    * The paragraph background color as a string.
607    *
608    * Since: 2.8
609    */
610   g_object_class_install_property (object_class,
611                                    PROP_PARAGRAPH_BACKGROUND,
612                                    g_param_spec_string ("paragraph-background",
613                                                         P_("Paragraph background color name"),
614                                                         P_("Paragraph background color as a string"),
615                                                         NULL,
616                                                         GTK_PARAM_WRITABLE));
617 
618   /**
619    * GtkTextTag:paragraph-background-gdk:
620    *
621    * The paragraph background color as a #GdkColor.
622    *
623    * Since: 2.8
624    *
625    * Deprecated: 3.4: Use #GtkTextTag:paragraph-background-rgba instead.
626    */
627   g_object_class_install_property (object_class,
628                                    PROP_PARAGRAPH_BACKGROUND_GDK,
629                                    g_param_spec_boxed ("paragraph-background-gdk",
630                                                        P_("Paragraph background color"),
631                                                        P_("Paragraph background color as a GdkColor"),
632                                                        g_type_from_name ("GdkColor"),
633                                                        GTK_PARAM_READWRITE | G_PARAM_DEPRECATED));
634 
635   /**
636    * GtkTextTag:paragraph-background-rgba:
637    *
638    * The paragraph background color as a #GdkRGBA.
639    *
640    * Since: 3.2
641    */
642   g_object_class_install_property (object_class,
643                                    PROP_PARAGRAPH_BACKGROUND_RGBA,
644                                    g_param_spec_boxed ("paragraph-background-rgba",
645                                                        P_("Paragraph background RGBA"),
646                                                        P_("Paragraph background RGBA as a GdkRGBA"),
647                                                        GDK_TYPE_RGBA,
648                                                        GTK_PARAM_READWRITE));
649 
650   /**
651    * GtkTextTag:fallback:
652    *
653    * Whether font fallback is enabled.
654    *
655    * When set to %TRUE, other fonts will be substituted
656    * where the current font is missing glyphs.
657    *
658    * Since: 3.16
659    */
660   g_object_class_install_property (object_class,
661                                    PROP_FALLBACK,
662                                    g_param_spec_boolean ("fallback",
663                                                          P_("Fallback"),
664                                                          P_("Whether font fallback is enabled."),
665                                                          TRUE,
666                                                          GTK_PARAM_READWRITE));
667 
668   /**
669    * GtkTextTag:letter-spacing:
670    *
671    * Extra spacing between graphemes, in Pango units.
672    *
673    * Since: 3.16
674    */
675   g_object_class_install_property (object_class,
676                                    PROP_LETTER_SPACING,
677                                    g_param_spec_int ("letter-spacing",
678                                                      P_("Letter Spacing"),
679                                                      P_("Extra spacing between graphemes"),
680                                                      0, G_MAXINT, 0,
681                                                      GTK_PARAM_READWRITE));
682 
683   /**
684    * GtkTextTag:font-features:
685    *
686    * OpenType font features, as a string.
687    *
688    * Since: 3.18
689    */
690   g_object_class_install_property (object_class,
691                                    PROP_FONT_FEATURES,
692                                    g_param_spec_string ("font-features",
693                                                         P_("Font Features"),
694                                                         P_("OpenType Font Features to use"),
695                                                         NULL,
696                                                         GTK_PARAM_READWRITE));
697 
698   /**
699    * GtkTextTag:accumulative-margin:
700    *
701    * Whether the margins accumulate or override each other.
702    *
703    * When set to %TRUE the margins of this tag are added to the margins
704    * of any other non-accumulative margins present. When set to %FALSE
705    * the margins override one another (the default).
706    *
707    * Since: 2.12
708    */
709   g_object_class_install_property (object_class,
710                                    PROP_ACCUMULATIVE_MARGIN,
711                                    g_param_spec_boolean ("accumulative-margin",
712                                                          P_("Margin Accumulates"),
713                                                          P_("Whether left and right margins accumulate."),
714                                                          FALSE,
715                                                          GTK_PARAM_READWRITE));
716 
717   /* Style props are set or not */
718 
719 #define ADD_SET_PROP(propname, propval, nick, blurb) g_object_class_install_property (object_class, propval, g_param_spec_boolean (propname, nick, blurb, FALSE, GTK_PARAM_READWRITE))
720 
721   ADD_SET_PROP ("background-set", PROP_BACKGROUND_SET,
722                 P_("Background set"),
723                 P_("Whether this tag affects the background color"));
724 
725   ADD_SET_PROP ("background-full-height-set", PROP_BACKGROUND_FULL_HEIGHT_SET,
726                 P_("Background full height set"),
727                 P_("Whether this tag affects background height"));
728 
729   ADD_SET_PROP ("foreground-set", PROP_FOREGROUND_SET,
730                 P_("Foreground set"),
731                 P_("Whether this tag affects the foreground color"));
732 
733   ADD_SET_PROP ("editable-set", PROP_EDITABLE_SET,
734                 P_("Editability set"),
735                 P_("Whether this tag affects text editability"));
736 
737   ADD_SET_PROP ("family-set", PROP_FAMILY_SET,
738                 P_("Font family set"),
739                 P_("Whether this tag affects the font family"));
740 
741   ADD_SET_PROP ("style-set", PROP_STYLE_SET,
742                 P_("Font style set"),
743                 P_("Whether this tag affects the font style"));
744 
745   ADD_SET_PROP ("variant-set", PROP_VARIANT_SET,
746                 P_("Font variant set"),
747                 P_("Whether this tag affects the font variant"));
748 
749   ADD_SET_PROP ("weight-set", PROP_WEIGHT_SET,
750                 P_("Font weight set"),
751                 P_("Whether this tag affects the font weight"));
752 
753   ADD_SET_PROP ("stretch-set", PROP_STRETCH_SET,
754                 P_("Font stretch set"),
755                 P_("Whether this tag affects the font stretch"));
756 
757   ADD_SET_PROP ("size-set", PROP_SIZE_SET,
758                 P_("Font size set"),
759                 P_("Whether this tag affects the font size"));
760 
761   ADD_SET_PROP ("scale-set", PROP_SCALE_SET,
762                 P_("Font scale set"),
763                 P_("Whether this tag scales the font size by a factor"));
764 
765   ADD_SET_PROP ("justification-set", PROP_JUSTIFICATION_SET,
766                 P_("Justification set"),
767                 P_("Whether this tag affects paragraph justification"));
768 
769   ADD_SET_PROP ("language-set", PROP_LANGUAGE_SET,
770                 P_("Language set"),
771                 P_("Whether this tag affects the language the text is rendered as"));
772 
773   ADD_SET_PROP ("left-margin-set", PROP_LEFT_MARGIN_SET,
774                 P_("Left margin set"),
775                 P_("Whether this tag affects the left margin"));
776 
777   ADD_SET_PROP ("indent-set", PROP_INDENT_SET,
778                 P_("Indent set"),
779                 P_("Whether this tag affects indentation"));
780 
781   ADD_SET_PROP ("rise-set", PROP_RISE_SET,
782                 P_("Rise set"),
783                 P_("Whether this tag affects the rise"));
784 
785   ADD_SET_PROP ("pixels-above-lines-set", PROP_PIXELS_ABOVE_LINES_SET,
786                 P_("Pixels above lines set"),
787                 P_("Whether this tag affects the number of pixels above lines"));
788 
789   ADD_SET_PROP ("pixels-below-lines-set", PROP_PIXELS_BELOW_LINES_SET,
790                 P_("Pixels below lines set"),
791                 P_("Whether this tag affects the number of pixels above lines"));
792 
793   ADD_SET_PROP ("pixels-inside-wrap-set", PROP_PIXELS_INSIDE_WRAP_SET,
794                 P_("Pixels inside wrap set"),
795                 P_("Whether this tag affects the number of pixels between wrapped lines"));
796 
797   ADD_SET_PROP ("strikethrough-set", PROP_STRIKETHROUGH_SET,
798                 P_("Strikethrough set"),
799                 P_("Whether this tag affects strikethrough"));
800 
801   ADD_SET_PROP ("right-margin-set", PROP_RIGHT_MARGIN_SET,
802                 P_("Right margin set"),
803                 P_("Whether this tag affects the right margin"));
804 
805   ADD_SET_PROP ("underline-set", PROP_UNDERLINE_SET,
806                 P_("Underline set"),
807                 P_("Whether this tag affects underlining"));
808 
809   /**
810    * GtkTextTag:underline-rgba-set:
811    *
812    * If the #GtkTextTag:underline-rgba property has been set.
813    *
814    * Since: 3.16
815    */
816   ADD_SET_PROP ("underline-rgba-set", PROP_UNDERLINE_RGBA_SET,
817                 P_("Underline RGBA set"),
818                 P_("Whether this tag affects underlining color"));
819 
820   /**
821    * GtkTextTag:strikethrough-rgba-set:
822    *
823    * If the #GtkTextTag:strikethrough-rgba property has been set.
824    *
825    * Since: 3.16
826    */
827   ADD_SET_PROP ("strikethrough-rgba-set", PROP_STRIKETHROUGH_RGBA_SET,
828                 P_("Strikethrough RGBA set"),
829                 P_("Whether this tag affects strikethrough color"));
830 
831   ADD_SET_PROP ("wrap-mode-set", PROP_WRAP_MODE_SET,
832                 P_("Wrap mode set"),
833                 P_("Whether this tag affects line wrap mode"));
834 
835   ADD_SET_PROP ("tabs-set", PROP_TABS_SET,
836                 P_("Tabs set"),
837                 P_("Whether this tag affects tabs"));
838 
839   ADD_SET_PROP ("invisible-set", PROP_INVISIBLE_SET,
840                 P_("Invisible set"),
841                 P_("Whether this tag affects text visibility"));
842 
843   ADD_SET_PROP ("paragraph-background-set", PROP_PARAGRAPH_BACKGROUND_SET,
844                 P_("Paragraph background set"),
845                 P_("Whether this tag affects the paragraph background color"));
846 
847   ADD_SET_PROP ("fallback-set", PROP_FALLBACK_SET,
848                 P_("Fallback set"),
849                 P_("Whether this tag affects font fallback"));
850 
851   ADD_SET_PROP ("letter-spacing-set", PROP_LETTER_SPACING_SET,
852                 P_("Letter spacing set"),
853                 P_("Whether this tag affects letter spacing"));
854 
855   ADD_SET_PROP ("font-features-set", PROP_FONT_FEATURES_SET,
856                 P_("Font features set"),
857                 P_("Whether this tag affects font features"));
858 
859   /**
860    * GtkTextTag::event:
861    * @tag: the #GtkTextTag on which the signal is emitted
862    * @object: the object the event was fired from (typically a #GtkTextView)
863    * @event: the event which triggered the signal
864    * @iter: a #GtkTextIter pointing at the location the event occurred
865    *
866    * The ::event signal is emitted when an event occurs on a region of the
867    * buffer marked with this tag.
868    *
869    * Returns: %TRUE to stop other handlers from being invoked for the
870    * event. %FALSE to propagate the event further.
871    */
872   signals[EVENT] =
873     g_signal_new (I_("event"),
874                   G_OBJECT_CLASS_TYPE (object_class),
875                   G_SIGNAL_RUN_LAST,
876                   G_STRUCT_OFFSET (GtkTextTagClass, event),
877                   _gtk_boolean_handled_accumulator, NULL,
878                   _gtk_marshal_BOOLEAN__OBJECT_BOXED_BOXED,
879                   G_TYPE_BOOLEAN,
880                   3,
881                   G_TYPE_OBJECT,
882                   GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE,
883                   GTK_TYPE_TEXT_ITER);
884   g_signal_set_va_marshaller (signals[EVENT],
885                               G_OBJECT_CLASS_TYPE (object_class),
886                               _gtk_marshal_BOOLEAN__OBJECT_BOXED_BOXEDv);
887 }
888 
889 static void
gtk_text_tag_init(GtkTextTag * text_tag)890 gtk_text_tag_init (GtkTextTag *text_tag)
891 {
892   text_tag->priv = gtk_text_tag_get_instance_private (text_tag);
893   text_tag->priv->values = gtk_text_attributes_new ();
894 }
895 
896 /**
897  * gtk_text_tag_new:
898  * @name: (allow-none): tag name, or %NULL
899  *
900  * Creates a #GtkTextTag. Configure the tag using object arguments,
901  * i.e. using g_object_set().
902  *
903  * Returns: a new #GtkTextTag
904  **/
905 GtkTextTag*
gtk_text_tag_new(const gchar * name)906 gtk_text_tag_new (const gchar *name)
907 {
908   GtkTextTag *tag;
909 
910   tag = g_object_new (GTK_TYPE_TEXT_TAG, "name", name, NULL);
911 
912   return tag;
913 }
914 
915 static void
gtk_text_tag_finalize(GObject * object)916 gtk_text_tag_finalize (GObject *object)
917 {
918   GtkTextTag *text_tag = GTK_TEXT_TAG (object);
919   GtkTextTagPrivate *priv = text_tag->priv;
920 
921   if (priv->table)
922     gtk_text_tag_table_remove (priv->table, text_tag);
923 
924   g_assert (priv->table == NULL);
925 
926   gtk_text_attributes_unref (priv->values);
927   priv->values = NULL;
928 
929   g_free (priv->name);
930   priv->name = NULL;
931 
932   G_OBJECT_CLASS (gtk_text_tag_parent_class)->finalize (object);
933 }
934 
935 static void
copy_rgba_to_gdk_color(GdkRGBA * src,GdkColor * dest)936 copy_rgba_to_gdk_color (GdkRGBA  *src,
937 			GdkColor *dest)
938 {
939   dest->red   = CLAMP (src->red,   0.0, 1.0) * 65535.0;
940   dest->green = CLAMP (src->green, 0.0, 1.0) * 65535.0;
941   dest->blue  = CLAMP (src->blue,  0.0, 1.0) * 65535.0;
942 }
943 
944 static void
copy_gdk_color_to_rgba(GdkColor * src,GdkRGBA * dest)945 copy_gdk_color_to_rgba (GdkColor *src,
946 			GdkRGBA  *dest)
947 {
948   dest->red   = src->red / 65535.;
949   dest->green = src->green / 65535.;
950   dest->blue  = src->blue / 65535.;
951   dest->alpha = 1;
952 }
953 
954 static void
set_underline_rgba(GtkTextTag * tag,const GdkRGBA * rgba)955 set_underline_rgba (GtkTextTag    *tag,
956                     const GdkRGBA *rgba)
957 {
958   GtkTextTagPrivate *priv = tag->priv;
959 
960   if (rgba)
961     {
962       GTK_TEXT_APPEARANCE_SET_UNDERLINE_RGBA (&priv->values->appearance, rgba);
963 
964       if (!GTK_TEXT_APPEARANCE_GET_UNDERLINE_RGBA_SET (&priv->values->appearance))
965         {
966           GTK_TEXT_APPEARANCE_SET_UNDERLINE_RGBA_SET (&priv->values->appearance, TRUE);
967           g_object_notify (G_OBJECT (tag), "underline-rgba-set");
968         }
969     }
970   else
971     {
972       GdkRGBA black = { 0 };
973 
974       GTK_TEXT_APPEARANCE_SET_UNDERLINE_RGBA (&priv->values->appearance, &black);
975 
976       if (GTK_TEXT_APPEARANCE_GET_UNDERLINE_RGBA_SET (&priv->values->appearance))
977         {
978           GTK_TEXT_APPEARANCE_SET_UNDERLINE_RGBA_SET (&priv->values->appearance, FALSE);
979           g_object_notify (G_OBJECT (tag), "underline-rgba-set");
980         }
981     }
982 }
983 
984 static void
set_strikethrough_rgba(GtkTextTag * tag,const GdkRGBA * rgba)985 set_strikethrough_rgba (GtkTextTag    *tag,
986                         const GdkRGBA *rgba)
987 {
988   GtkTextTagPrivate *priv = tag->priv;
989 
990   if (rgba)
991     {
992       GTK_TEXT_APPEARANCE_SET_STRIKETHROUGH_RGBA (&priv->values->appearance, rgba);
993 
994       if (!GTK_TEXT_APPEARANCE_GET_STRIKETHROUGH_RGBA_SET (&priv->values->appearance))
995         {
996           GTK_TEXT_APPEARANCE_SET_STRIKETHROUGH_RGBA_SET (&priv->values->appearance, TRUE);
997           g_object_notify (G_OBJECT (tag), "strikethrough-rgba-set");
998         }
999     }
1000   else
1001     {
1002       GdkRGBA black = { 0 };
1003 
1004       GTK_TEXT_APPEARANCE_SET_STRIKETHROUGH_RGBA (&priv->values->appearance, &black);
1005 
1006       if (GTK_TEXT_APPEARANCE_GET_STRIKETHROUGH_RGBA_SET (&priv->values->appearance))
1007         {
1008           GTK_TEXT_APPEARANCE_SET_STRIKETHROUGH_RGBA_SET (&priv->values->appearance, FALSE);
1009           g_object_notify (G_OBJECT (tag), "strikethrough-rgba-set");
1010         }
1011     }
1012 }
1013 
1014 static void
set_bg_rgba(GtkTextTag * tag,GdkRGBA * rgba)1015 set_bg_rgba (GtkTextTag *tag, GdkRGBA *rgba)
1016 {
1017   GtkTextTagPrivate *priv = tag->priv;
1018 
1019   if (priv->values->appearance.rgba[0])
1020     gdk_rgba_free (priv->values->appearance.rgba[0]);
1021 
1022   priv->values->appearance.rgba[0] = NULL;
1023 
1024   if (rgba)
1025     {
1026       if (!priv->bg_color_set)
1027         {
1028           priv->bg_color_set = TRUE;
1029           g_object_notify (G_OBJECT (tag), "background-set");
1030         }
1031 
1032       priv->values->appearance.rgba[0] = gdk_rgba_copy (rgba);
1033 
1034       copy_rgba_to_gdk_color (rgba, &priv->values->appearance.bg_color);
1035     }
1036   else
1037     {
1038       if (priv->bg_color_set)
1039         {
1040           priv->bg_color_set = FALSE;
1041           g_object_notify (G_OBJECT (tag), "background-set");
1042         }
1043     }
1044 }
1045 
1046 static void
set_fg_rgba(GtkTextTag * tag,GdkRGBA * rgba)1047 set_fg_rgba (GtkTextTag *tag, GdkRGBA *rgba)
1048 {
1049   GtkTextTagPrivate *priv = tag->priv;
1050 
1051   if (priv->values->appearance.rgba[1])
1052     gdk_rgba_free (priv->values->appearance.rgba[1]);
1053 
1054   priv->values->appearance.rgba[1] = NULL;
1055 
1056   if (rgba)
1057     {
1058       if (!priv->fg_color_set)
1059         {
1060           priv->fg_color_set = TRUE;
1061           g_object_notify (G_OBJECT (tag), "foreground-set");
1062         }
1063 
1064       priv->values->appearance.rgba[1] = gdk_rgba_copy (rgba);
1065 
1066       copy_rgba_to_gdk_color (rgba, &priv->values->appearance.fg_color);
1067     }
1068   else
1069     {
1070       if (priv->fg_color_set)
1071         {
1072           priv->fg_color_set = FALSE;
1073           g_object_notify (G_OBJECT (tag), "foreground-set");
1074         }
1075     }
1076 }
1077 
1078 static void
set_pg_bg_rgba(GtkTextTag * tag,GdkRGBA * rgba)1079 set_pg_bg_rgba (GtkTextTag *tag, GdkRGBA *rgba)
1080 {
1081   GtkTextTagPrivate *priv = tag->priv;
1082 
1083   if (priv->values->pg_bg_rgba)
1084     gdk_rgba_free (priv->values->pg_bg_rgba);
1085 
1086 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
1087   if (priv->values->pg_bg_color)
1088     gdk_color_free (priv->values->pg_bg_color);
1089 G_GNUC_END_IGNORE_DEPRECATIONS
1090 
1091   priv->values->pg_bg_rgba = NULL;
1092   priv->values->pg_bg_color = NULL;
1093 
1094   if (rgba)
1095     {
1096       GdkColor color = { 0, };
1097 
1098       if (!priv->pg_bg_color_set)
1099         {
1100           priv->pg_bg_color_set = TRUE;
1101           g_object_notify (G_OBJECT (tag), "paragraph-background-set");
1102         }
1103 
1104       priv->values->pg_bg_rgba = gdk_rgba_copy (rgba);
1105 
1106       copy_rgba_to_gdk_color (rgba, &color);
1107 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
1108       priv->values->pg_bg_color = gdk_color_copy (&color);
1109 G_GNUC_END_IGNORE_DEPRECATIONS
1110     }
1111   else
1112     {
1113       if (priv->pg_bg_color_set)
1114         {
1115           priv->pg_bg_color_set = FALSE;
1116           g_object_notify (G_OBJECT (tag), "paragraph-background-set");
1117         }
1118     }
1119 }
1120 
1121 
1122 static void
set_bg_color(GtkTextTag * tag,GdkColor * color)1123 set_bg_color (GtkTextTag *tag, GdkColor *color)
1124 {
1125   if (color)
1126     {
1127       GdkRGBA rgba;
1128 
1129       copy_gdk_color_to_rgba (color, &rgba);
1130       set_bg_rgba (tag, &rgba);
1131     }
1132   else
1133     set_bg_rgba (tag, NULL);
1134 }
1135 
1136 static void
set_fg_color(GtkTextTag * tag,GdkColor * color)1137 set_fg_color (GtkTextTag *tag, GdkColor *color)
1138 {
1139   if (color)
1140     {
1141       GdkRGBA rgba;
1142 
1143       copy_gdk_color_to_rgba (color, &rgba);
1144       set_fg_rgba (tag, &rgba);
1145     }
1146   else
1147     set_fg_rgba (tag, NULL);
1148 }
1149 
1150 static void
set_pg_bg_color(GtkTextTag * tag,GdkColor * color)1151 set_pg_bg_color (GtkTextTag *tag, GdkColor *color)
1152 {
1153   if (color)
1154     {
1155       GdkRGBA rgba;
1156 
1157       copy_gdk_color_to_rgba (color, &rgba);
1158       set_pg_bg_rgba (tag, &rgba);
1159     }
1160   else
1161     set_pg_bg_rgba (tag, NULL);
1162 }
1163 
1164 static PangoFontMask
get_property_font_set_mask(guint prop_id)1165 get_property_font_set_mask (guint prop_id)
1166 {
1167   switch (prop_id)
1168     {
1169     case PROP_FAMILY_SET:
1170       return PANGO_FONT_MASK_FAMILY;
1171     case PROP_STYLE_SET:
1172       return PANGO_FONT_MASK_STYLE;
1173     case PROP_VARIANT_SET:
1174       return PANGO_FONT_MASK_VARIANT;
1175     case PROP_WEIGHT_SET:
1176       return PANGO_FONT_MASK_WEIGHT;
1177     case PROP_STRETCH_SET:
1178       return PANGO_FONT_MASK_STRETCH;
1179     case PROP_SIZE_SET:
1180       return PANGO_FONT_MASK_SIZE;
1181     }
1182 
1183   return 0;
1184 }
1185 
1186 static PangoFontMask
set_font_desc_fields(PangoFontDescription * desc,PangoFontMask to_set)1187 set_font_desc_fields (PangoFontDescription *desc,
1188 		      PangoFontMask         to_set)
1189 {
1190   PangoFontMask changed_mask = 0;
1191 
1192   if (to_set & PANGO_FONT_MASK_FAMILY)
1193     {
1194       const char *family = pango_font_description_get_family (desc);
1195       if (!family)
1196 	{
1197 	  family = "sans";
1198 	  changed_mask |= PANGO_FONT_MASK_FAMILY;
1199 	}
1200 
1201       pango_font_description_set_family (desc, family);
1202     }
1203   if (to_set & PANGO_FONT_MASK_STYLE)
1204     pango_font_description_set_style (desc, pango_font_description_get_style (desc));
1205   if (to_set & PANGO_FONT_MASK_VARIANT)
1206     pango_font_description_set_variant (desc, pango_font_description_get_variant (desc));
1207   if (to_set & PANGO_FONT_MASK_WEIGHT)
1208     pango_font_description_set_weight (desc, pango_font_description_get_weight (desc));
1209   if (to_set & PANGO_FONT_MASK_STRETCH)
1210     pango_font_description_set_stretch (desc, pango_font_description_get_stretch (desc));
1211   if (to_set & PANGO_FONT_MASK_SIZE)
1212     {
1213       gint size = pango_font_description_get_size (desc);
1214       if (size <= 0)
1215 	{
1216 	  size = 10 * PANGO_SCALE;
1217 	  changed_mask |= PANGO_FONT_MASK_SIZE;
1218 	}
1219 
1220       pango_font_description_set_size (desc, size);
1221     }
1222 
1223   return changed_mask;
1224 }
1225 
1226 static void
notify_set_changed(GObject * object,PangoFontMask changed_mask)1227 notify_set_changed (GObject       *object,
1228 		    PangoFontMask  changed_mask)
1229 {
1230   if (changed_mask & PANGO_FONT_MASK_FAMILY)
1231     g_object_notify (object, "family-set");
1232   if (changed_mask & PANGO_FONT_MASK_STYLE)
1233     g_object_notify (object, "style-set");
1234   if (changed_mask & PANGO_FONT_MASK_VARIANT)
1235     g_object_notify (object, "variant-set");
1236   if (changed_mask & PANGO_FONT_MASK_WEIGHT)
1237     g_object_notify (object, "weight-set");
1238   if (changed_mask & PANGO_FONT_MASK_STRETCH)
1239     g_object_notify (object, "stretch-set");
1240   if (changed_mask & PANGO_FONT_MASK_SIZE)
1241     g_object_notify (object, "size-set");
1242 }
1243 
1244 static void
notify_fields_changed(GObject * object,PangoFontMask changed_mask)1245 notify_fields_changed (GObject       *object,
1246 		       PangoFontMask  changed_mask)
1247 {
1248   if (changed_mask & PANGO_FONT_MASK_FAMILY)
1249     g_object_notify (object, "family");
1250   if (changed_mask & PANGO_FONT_MASK_STYLE)
1251     g_object_notify (object, "style");
1252   if (changed_mask & PANGO_FONT_MASK_VARIANT)
1253     g_object_notify (object, "variant");
1254   if (changed_mask & PANGO_FONT_MASK_WEIGHT)
1255     g_object_notify (object, "weight");
1256   if (changed_mask & PANGO_FONT_MASK_STRETCH)
1257     g_object_notify (object, "stretch");
1258   if (changed_mask & PANGO_FONT_MASK_SIZE)
1259     g_object_notify (object, "size");
1260 }
1261 
1262 static void
set_font_description(GtkTextTag * text_tag,PangoFontDescription * font_desc)1263 set_font_description (GtkTextTag           *text_tag,
1264                       PangoFontDescription *font_desc)
1265 {
1266   GtkTextTagPrivate *priv = text_tag->priv;
1267   GObject *object = G_OBJECT (text_tag);
1268   PangoFontDescription *new_font_desc;
1269   PangoFontMask old_mask, new_mask, changed_mask, set_changed_mask;
1270 
1271   if (font_desc)
1272     new_font_desc = pango_font_description_copy (font_desc);
1273   else
1274     new_font_desc = pango_font_description_new ();
1275 
1276   if (priv->values->font)
1277     old_mask = pango_font_description_get_set_fields (priv->values->font);
1278   else
1279     old_mask = 0;
1280 
1281   new_mask = pango_font_description_get_set_fields (new_font_desc);
1282 
1283   changed_mask = old_mask | new_mask;
1284   set_changed_mask = old_mask ^ new_mask;
1285 
1286   if (priv->values->font)
1287     pango_font_description_free (priv->values->font);
1288   priv->values->font = new_font_desc;
1289 
1290   g_object_freeze_notify (object);
1291 
1292   g_object_notify (object, "font-desc");
1293   g_object_notify (object, "font");
1294 
1295   if (changed_mask & PANGO_FONT_MASK_FAMILY)
1296     g_object_notify (object, "family");
1297   if (changed_mask & PANGO_FONT_MASK_STYLE)
1298     g_object_notify (object, "style");
1299   if (changed_mask & PANGO_FONT_MASK_VARIANT)
1300     g_object_notify (object, "variant");
1301   if (changed_mask & PANGO_FONT_MASK_WEIGHT)
1302     g_object_notify (object, "weight");
1303   if (changed_mask & PANGO_FONT_MASK_STRETCH)
1304     g_object_notify (object, "stretch");
1305   if (changed_mask & PANGO_FONT_MASK_SIZE)
1306     {
1307       g_object_notify (object, "size");
1308       g_object_notify (object, "size-points");
1309     }
1310 
1311   notify_set_changed (object, set_changed_mask);
1312 
1313   g_object_thaw_notify (object);
1314 }
1315 
1316 static void
gtk_text_tag_ensure_font(GtkTextTag * text_tag)1317 gtk_text_tag_ensure_font (GtkTextTag *text_tag)
1318 {
1319   GtkTextTagPrivate *priv = text_tag->priv;
1320 
1321   if (!priv->values->font)
1322     priv->values->font = pango_font_description_new ();
1323 }
1324 
1325 static void
gtk_text_tag_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)1326 gtk_text_tag_set_property (GObject      *object,
1327                            guint         prop_id,
1328                            const GValue *value,
1329                            GParamSpec   *pspec)
1330 {
1331   GtkTextTag *text_tag = GTK_TEXT_TAG (object);
1332   GtkTextTagPrivate *priv = text_tag->priv;
1333   gboolean size_changed = FALSE;
1334 
1335   switch (prop_id)
1336     {
1337     case PROP_NAME:
1338       g_return_if_fail (priv->name == NULL);
1339       priv->name = g_value_dup_string (value);
1340       break;
1341 
1342     case PROP_BACKGROUND:
1343       {
1344         GdkRGBA rgba;
1345 
1346         if (!g_value_get_string (value))
1347           set_bg_rgba (text_tag, NULL);       /* reset background_set to FALSE */
1348         else if (gdk_rgba_parse (&rgba, g_value_get_string (value)))
1349           set_bg_rgba (text_tag, &rgba);
1350         else
1351           g_warning ("Don't know color '%s'", g_value_get_string (value));
1352 
1353         g_object_notify (object, "background-gdk");
1354       }
1355       break;
1356 
1357     case PROP_FOREGROUND:
1358       {
1359         GdkRGBA rgba;
1360 
1361         if (!g_value_get_string (value))
1362           set_fg_rgba (text_tag, NULL);       /* reset to foreground_set to FALSE */
1363         else if (gdk_rgba_parse (&rgba, g_value_get_string (value)))
1364           set_fg_rgba (text_tag, &rgba);
1365         else
1366           g_warning ("Don't know color '%s'", g_value_get_string (value));
1367 
1368         g_object_notify (object, "foreground-gdk");
1369       }
1370       break;
1371 
1372     case PROP_BACKGROUND_GDK:
1373       {
1374         GdkColor *color = g_value_get_boxed (value);
1375 
1376         set_bg_color (text_tag, color);
1377       }
1378       break;
1379 
1380     case PROP_FOREGROUND_GDK:
1381       {
1382         GdkColor *color = g_value_get_boxed (value);
1383 
1384         set_fg_color (text_tag, color);
1385       }
1386       break;
1387 
1388     case PROP_BACKGROUND_RGBA:
1389       {
1390         GdkRGBA *color = g_value_get_boxed (value);
1391 
1392         set_bg_rgba (text_tag, color);
1393       }
1394       break;
1395 
1396     case PROP_FOREGROUND_RGBA:
1397       {
1398         GdkRGBA *color = g_value_get_boxed (value);
1399 
1400         set_fg_rgba (text_tag, color);
1401       }
1402       break;
1403 
1404     case PROP_FONT:
1405       {
1406         PangoFontDescription *font_desc = NULL;
1407         const gchar *name;
1408 
1409         name = g_value_get_string (value);
1410 
1411         if (name)
1412           font_desc = pango_font_description_from_string (name);
1413 
1414         set_font_description (text_tag, font_desc);
1415 	if (font_desc)
1416 	  pango_font_description_free (font_desc);
1417 
1418         size_changed = TRUE;
1419       }
1420       break;
1421 
1422     case PROP_FONT_DESC:
1423       {
1424         PangoFontDescription *font_desc;
1425 
1426         font_desc = g_value_get_boxed (value);
1427 
1428         set_font_description (text_tag, font_desc);
1429 
1430         size_changed = TRUE;
1431       }
1432       break;
1433 
1434     case PROP_FAMILY:
1435     case PROP_STYLE:
1436     case PROP_VARIANT:
1437     case PROP_WEIGHT:
1438     case PROP_STRETCH:
1439     case PROP_SIZE:
1440     case PROP_SIZE_POINTS:
1441       {
1442 	PangoFontMask old_set_mask;
1443 
1444 	gtk_text_tag_ensure_font (text_tag);
1445 	old_set_mask = pango_font_description_get_set_fields (priv->values->font);
1446 
1447 	switch (prop_id)
1448 	  {
1449 	  case PROP_FAMILY:
1450 	    pango_font_description_set_family (priv->values->font,
1451 					       g_value_get_string (value));
1452 	    break;
1453 	  case PROP_STYLE:
1454 	    pango_font_description_set_style (priv->values->font,
1455 					      g_value_get_enum (value));
1456 	    break;
1457 	  case PROP_VARIANT:
1458 	    pango_font_description_set_variant (priv->values->font,
1459 						g_value_get_enum (value));
1460 	    break;
1461 	  case PROP_WEIGHT:
1462 	    pango_font_description_set_weight (priv->values->font,
1463 					       g_value_get_int (value));
1464 	    break;
1465 	  case PROP_STRETCH:
1466 	    pango_font_description_set_stretch (priv->values->font,
1467 						g_value_get_enum (value));
1468 	    break;
1469 	  case PROP_SIZE:
1470 	    pango_font_description_set_size (priv->values->font,
1471 					     g_value_get_int (value));
1472 	    g_object_notify (object, "size-points");
1473 	    break;
1474 	  case PROP_SIZE_POINTS:
1475 	    pango_font_description_set_size (priv->values->font,
1476 					     g_value_get_double (value) * PANGO_SCALE);
1477 	    g_object_notify (object, "size");
1478 	    break;
1479 	  }
1480 
1481 	size_changed = TRUE;
1482 	notify_set_changed (object, old_set_mask & pango_font_description_get_set_fields (priv->values->font));
1483 	g_object_notify (object, "font-desc");
1484 	g_object_notify (object, "font");
1485 
1486 	break;
1487       }
1488 
1489     case PROP_SCALE:
1490       priv->values->font_scale = g_value_get_double (value);
1491       priv->scale_set = TRUE;
1492       g_object_notify (object, "scale-set");
1493       size_changed = TRUE;
1494       break;
1495 
1496     case PROP_PIXELS_ABOVE_LINES:
1497       priv->pixels_above_lines_set = TRUE;
1498       priv->values->pixels_above_lines = g_value_get_int (value);
1499       g_object_notify (object, "pixels-above-lines-set");
1500       size_changed = TRUE;
1501       break;
1502 
1503     case PROP_PIXELS_BELOW_LINES:
1504       priv->pixels_below_lines_set = TRUE;
1505       priv->values->pixels_below_lines = g_value_get_int (value);
1506       g_object_notify (object, "pixels-below-lines-set");
1507       size_changed = TRUE;
1508       break;
1509 
1510     case PROP_PIXELS_INSIDE_WRAP:
1511       priv->pixels_inside_wrap_set = TRUE;
1512       priv->values->pixels_inside_wrap = g_value_get_int (value);
1513       g_object_notify (object, "pixels-inside-wrap-set");
1514       size_changed = TRUE;
1515       break;
1516 
1517     case PROP_EDITABLE:
1518       priv->editable_set = TRUE;
1519       priv->values->editable = g_value_get_boolean (value);
1520       g_object_notify (object, "editable-set");
1521       break;
1522 
1523     case PROP_WRAP_MODE:
1524       priv->wrap_mode_set = TRUE;
1525       priv->values->wrap_mode = g_value_get_enum (value);
1526       g_object_notify (object, "wrap-mode-set");
1527       size_changed = TRUE;
1528       break;
1529 
1530     case PROP_JUSTIFICATION:
1531       priv->justification_set = TRUE;
1532       priv->values->justification = g_value_get_enum (value);
1533       g_object_notify (object, "justification-set");
1534       size_changed = TRUE;
1535       break;
1536 
1537     case PROP_DIRECTION:
1538       priv->values->direction = g_value_get_enum (value);
1539       break;
1540 
1541     case PROP_LEFT_MARGIN:
1542       priv->left_margin_set = TRUE;
1543       priv->values->left_margin = g_value_get_int (value);
1544       g_object_notify (object, "left-margin-set");
1545       size_changed = TRUE;
1546       break;
1547 
1548     case PROP_INDENT:
1549       priv->indent_set = TRUE;
1550       priv->values->indent = g_value_get_int (value);
1551       g_object_notify (object, "indent-set");
1552       size_changed = TRUE;
1553       break;
1554 
1555     case PROP_STRIKETHROUGH:
1556       priv->strikethrough_set = TRUE;
1557       priv->values->appearance.strikethrough = g_value_get_boolean (value);
1558       g_object_notify (object, "strikethrough-set");
1559       break;
1560 
1561     case PROP_STRIKETHROUGH_RGBA:
1562       {
1563         GdkRGBA *color = g_value_get_boxed (value);
1564         set_strikethrough_rgba (text_tag, color);
1565       }
1566       break;
1567 
1568     case PROP_RIGHT_MARGIN:
1569       priv->right_margin_set = TRUE;
1570       priv->values->right_margin = g_value_get_int (value);
1571       g_object_notify (object, "right-margin-set");
1572       size_changed = TRUE;
1573       break;
1574 
1575     case PROP_UNDERLINE:
1576       priv->underline_set = TRUE;
1577       priv->values->appearance.underline = g_value_get_enum (value);
1578       g_object_notify (object, "underline-set");
1579       break;
1580 
1581     case PROP_UNDERLINE_RGBA:
1582       {
1583         GdkRGBA *color = g_value_get_boxed (value);
1584         set_underline_rgba (text_tag, color);
1585       }
1586       break;
1587 
1588     case PROP_RISE:
1589       priv->rise_set = TRUE;
1590       priv->values->appearance.rise = g_value_get_int (value);
1591       g_object_notify (object, "rise-set");
1592       size_changed = TRUE;
1593       break;
1594 
1595     case PROP_BACKGROUND_FULL_HEIGHT:
1596       priv->bg_full_height_set = TRUE;
1597       priv->values->bg_full_height = g_value_get_boolean (value);
1598       g_object_notify (object, "background-full-height-set");
1599       break;
1600 
1601     case PROP_LANGUAGE:
1602       priv->language_set = TRUE;
1603       priv->values->language = pango_language_from_string (g_value_get_string (value));
1604       g_object_notify (object, "language-set");
1605       break;
1606 
1607     case PROP_TABS:
1608       priv->tabs_set = TRUE;
1609 
1610       if (priv->values->tabs)
1611         pango_tab_array_free (priv->values->tabs);
1612 
1613       /* FIXME I'm not sure if this is a memleak or not */
1614       priv->values->tabs =
1615         pango_tab_array_copy (g_value_get_boxed (value));
1616 
1617       g_object_notify (object, "tabs-set");
1618 
1619       size_changed = TRUE;
1620       break;
1621 
1622     case PROP_INVISIBLE:
1623       priv->invisible_set = TRUE;
1624       priv->values->invisible = g_value_get_boolean (value);
1625       g_object_notify (object, "invisible-set");
1626       size_changed = TRUE;
1627       break;
1628 
1629     case PROP_PARAGRAPH_BACKGROUND:
1630       {
1631         GdkRGBA rgba;
1632 
1633         if (!g_value_get_string (value))
1634           set_pg_bg_rgba (text_tag, NULL);       /* reset paragraph_background_set to FALSE */
1635         else if (gdk_rgba_parse (&rgba, g_value_get_string (value)))
1636           set_pg_bg_rgba (text_tag, &rgba);
1637         else
1638           g_warning ("Don't know color '%s'", g_value_get_string (value));
1639 
1640         g_object_notify (object, "paragraph-background-gdk");
1641       }
1642       break;
1643 
1644     case PROP_PARAGRAPH_BACKGROUND_GDK:
1645       {
1646         GdkColor *color = g_value_get_boxed (value);
1647 
1648         set_pg_bg_color (text_tag, color);
1649       }
1650       break;
1651 
1652     case PROP_PARAGRAPH_BACKGROUND_RGBA:
1653       {
1654         GdkRGBA *color = g_value_get_boxed (value);
1655 
1656         set_pg_bg_rgba (text_tag, color);
1657       }
1658       break;
1659 
1660     case PROP_FALLBACK:
1661       priv->fallback_set = TRUE;
1662       priv->values->no_fallback = !g_value_get_boolean (value);
1663       g_object_notify (object, "fallback-set");
1664       break;
1665 
1666     case PROP_LETTER_SPACING:
1667       priv->letter_spacing_set = TRUE;
1668       priv->values->letter_spacing = g_value_get_int (value);
1669       g_object_notify (object, "letter-spacing-set");
1670       break;
1671 
1672     case PROP_FONT_FEATURES:
1673       priv->font_features_set = TRUE;
1674       priv->values->font_features = g_value_dup_string (value);
1675       g_object_notify (object, "font-features-set");
1676       break;
1677 
1678     case PROP_ACCUMULATIVE_MARGIN:
1679       priv->accumulative_margin = g_value_get_boolean (value);
1680       g_object_notify (object, "accumulative-margin");
1681       size_changed = TRUE;
1682       break;
1683 
1684       /* Whether the value should be used... */
1685 
1686     case PROP_BACKGROUND_SET:
1687       priv->bg_color_set = g_value_get_boolean (value);
1688       break;
1689 
1690     case PROP_FOREGROUND_SET:
1691       priv->fg_color_set = g_value_get_boolean (value);
1692       break;
1693 
1694     case PROP_FAMILY_SET:
1695     case PROP_STYLE_SET:
1696     case PROP_VARIANT_SET:
1697     case PROP_WEIGHT_SET:
1698     case PROP_STRETCH_SET:
1699     case PROP_SIZE_SET:
1700       if (!g_value_get_boolean (value))
1701 	{
1702 	  if (priv->values->font)
1703 	    pango_font_description_unset_fields (priv->values->font,
1704 						 get_property_font_set_mask (prop_id));
1705 	}
1706       else
1707 	{
1708 	  PangoFontMask changed_mask;
1709 
1710 	  gtk_text_tag_ensure_font (text_tag);
1711 	  changed_mask = set_font_desc_fields (priv->values->font,
1712 					       get_property_font_set_mask (prop_id));
1713 	  notify_fields_changed (G_OBJECT (text_tag), changed_mask);
1714 	}
1715       break;
1716 
1717     case PROP_SCALE_SET:
1718       priv->scale_set = g_value_get_boolean (value);
1719       size_changed = TRUE;
1720       break;
1721 
1722     case PROP_PIXELS_ABOVE_LINES_SET:
1723       priv->pixels_above_lines_set = g_value_get_boolean (value);
1724       size_changed = TRUE;
1725       break;
1726 
1727     case PROP_PIXELS_BELOW_LINES_SET:
1728       priv->pixels_below_lines_set = g_value_get_boolean (value);
1729       size_changed = TRUE;
1730       break;
1731 
1732     case PROP_PIXELS_INSIDE_WRAP_SET:
1733       priv->pixels_inside_wrap_set = g_value_get_boolean (value);
1734       size_changed = TRUE;
1735       break;
1736 
1737     case PROP_EDITABLE_SET:
1738       priv->editable_set = g_value_get_boolean (value);
1739       break;
1740 
1741     case PROP_WRAP_MODE_SET:
1742       priv->wrap_mode_set = g_value_get_boolean (value);
1743       size_changed = TRUE;
1744       break;
1745 
1746     case PROP_JUSTIFICATION_SET:
1747       priv->justification_set = g_value_get_boolean (value);
1748       size_changed = TRUE;
1749       break;
1750 
1751     case PROP_LEFT_MARGIN_SET:
1752       priv->left_margin_set = g_value_get_boolean (value);
1753       size_changed = TRUE;
1754       break;
1755 
1756     case PROP_INDENT_SET:
1757       priv->indent_set = g_value_get_boolean (value);
1758       size_changed = TRUE;
1759       break;
1760 
1761     case PROP_STRIKETHROUGH_SET:
1762       priv->strikethrough_set = g_value_get_boolean (value);
1763       break;
1764 
1765     case PROP_STRIKETHROUGH_RGBA_SET:
1766       GTK_TEXT_APPEARANCE_SET_STRIKETHROUGH_RGBA_SET (&priv->values->appearance,
1767                                                       g_value_get_boolean (value));
1768       break;
1769 
1770     case PROP_RIGHT_MARGIN_SET:
1771       priv->right_margin_set = g_value_get_boolean (value);
1772       size_changed = TRUE;
1773       break;
1774 
1775     case PROP_UNDERLINE_SET:
1776       priv->underline_set = g_value_get_boolean (value);
1777       break;
1778 
1779     case PROP_UNDERLINE_RGBA_SET:
1780       GTK_TEXT_APPEARANCE_SET_UNDERLINE_RGBA_SET (&priv->values->appearance,
1781                                                   g_value_get_boolean (value));
1782       break;
1783 
1784     case PROP_RISE_SET:
1785       priv->rise_set = g_value_get_boolean (value);
1786       size_changed = TRUE;
1787       break;
1788 
1789     case PROP_BACKGROUND_FULL_HEIGHT_SET:
1790       priv->bg_full_height_set = g_value_get_boolean (value);
1791       break;
1792 
1793     case PROP_LANGUAGE_SET:
1794       priv->language_set = g_value_get_boolean (value);
1795       size_changed = TRUE;
1796       break;
1797 
1798     case PROP_TABS_SET:
1799       priv->tabs_set = g_value_get_boolean (value);
1800       size_changed = TRUE;
1801       break;
1802 
1803     case PROP_INVISIBLE_SET:
1804       priv->invisible_set = g_value_get_boolean (value);
1805       size_changed = TRUE;
1806       break;
1807 
1808     case PROP_PARAGRAPH_BACKGROUND_SET:
1809       priv->pg_bg_color_set = g_value_get_boolean (value);
1810       break;
1811 
1812     case PROP_FALLBACK_SET:
1813       priv->fallback_set = g_value_get_boolean (value);
1814       break;
1815 
1816     case PROP_LETTER_SPACING_SET:
1817       priv->letter_spacing_set = g_value_get_boolean (value);
1818       break;
1819 
1820     case PROP_FONT_FEATURES_SET:
1821       priv->font_features_set = g_value_get_boolean (value);
1822       break;
1823 
1824     default:
1825       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1826       break;
1827     }
1828 
1829   /* The signal is emitted for each set_property(). A possible optimization is
1830    * to send the signal only once when several properties are set at the same
1831    * time with e.g. g_object_set(). The signal could be emitted when the notify
1832    * signal is thawed.
1833    */
1834   gtk_text_tag_changed (text_tag, size_changed);
1835 }
1836 
1837 static void
gtk_text_tag_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)1838 gtk_text_tag_get_property (GObject      *object,
1839                            guint         prop_id,
1840                            GValue       *value,
1841                            GParamSpec   *pspec)
1842 {
1843   GtkTextTag *tag = GTK_TEXT_TAG (object);
1844   GtkTextTagPrivate *priv = tag->priv;
1845 
1846   switch (prop_id)
1847     {
1848     case PROP_NAME:
1849       g_value_set_string (value, priv->name);
1850       break;
1851 
1852     case PROP_BACKGROUND_GDK:
1853       g_value_set_boxed (value, &priv->values->appearance.bg_color);
1854       break;
1855 
1856     case PROP_BACKGROUND_RGBA:
1857       g_value_set_boxed (value, priv->values->appearance.rgba[0]);
1858       break;
1859 
1860     case PROP_FOREGROUND_GDK:
1861       g_value_set_boxed (value, &priv->values->appearance.fg_color);
1862       break;
1863 
1864     case PROP_FOREGROUND_RGBA:
1865       g_value_set_boxed (value, priv->values->appearance.rgba[1]);
1866       break;
1867 
1868     case PROP_FONT:
1869         {
1870           gchar *str;
1871 
1872 	  gtk_text_tag_ensure_font (tag);
1873 
1874 	  str = pango_font_description_to_string (priv->values->font);
1875           g_value_take_string (value, str);
1876         }
1877       break;
1878 
1879     case PROP_FONT_DESC:
1880       gtk_text_tag_ensure_font (tag);
1881       g_value_set_boxed (value, priv->values->font);
1882       break;
1883 
1884     case PROP_FAMILY:
1885     case PROP_STYLE:
1886     case PROP_VARIANT:
1887     case PROP_WEIGHT:
1888     case PROP_STRETCH:
1889     case PROP_SIZE:
1890     case PROP_SIZE_POINTS:
1891       gtk_text_tag_ensure_font (tag);
1892       switch (prop_id)
1893 	{
1894 	case PROP_FAMILY:
1895 	  g_value_set_string (value, pango_font_description_get_family (priv->values->font));
1896 	  break;
1897 
1898 	case PROP_STYLE:
1899 	  g_value_set_enum (value, pango_font_description_get_style (priv->values->font));
1900 	  break;
1901 
1902 	case PROP_VARIANT:
1903 	  g_value_set_enum (value, pango_font_description_get_variant (priv->values->font));
1904 	  break;
1905 
1906 	case PROP_WEIGHT:
1907 	  g_value_set_int (value, pango_font_description_get_weight (priv->values->font));
1908 	  break;
1909 
1910 	case PROP_STRETCH:
1911 	  g_value_set_enum (value, pango_font_description_get_stretch (priv->values->font));
1912 	  break;
1913 
1914 	case PROP_SIZE:
1915 	  g_value_set_int (value, pango_font_description_get_size (priv->values->font));
1916 	  break;
1917 
1918 	case PROP_SIZE_POINTS:
1919 	  g_value_set_double (value, ((double)pango_font_description_get_size (priv->values->font)) / (double)PANGO_SCALE);
1920 	  break;
1921 	}
1922       break;
1923 
1924     case PROP_SCALE:
1925       g_value_set_double (value, priv->values->font_scale);
1926       break;
1927 
1928     case PROP_PIXELS_ABOVE_LINES:
1929       g_value_set_int (value,  priv->values->pixels_above_lines);
1930       break;
1931 
1932     case PROP_PIXELS_BELOW_LINES:
1933       g_value_set_int (value,  priv->values->pixels_below_lines);
1934       break;
1935 
1936     case PROP_PIXELS_INSIDE_WRAP:
1937       g_value_set_int (value,  priv->values->pixels_inside_wrap);
1938       break;
1939 
1940     case PROP_EDITABLE:
1941       g_value_set_boolean (value, priv->values->editable);
1942       break;
1943 
1944     case PROP_WRAP_MODE:
1945       g_value_set_enum (value, priv->values->wrap_mode);
1946       break;
1947 
1948     case PROP_JUSTIFICATION:
1949       g_value_set_enum (value, priv->values->justification);
1950       break;
1951 
1952     case PROP_DIRECTION:
1953       g_value_set_enum (value, priv->values->direction);
1954       break;
1955 
1956     case PROP_LEFT_MARGIN:
1957       g_value_set_int (value,  priv->values->left_margin);
1958       break;
1959 
1960     case PROP_INDENT:
1961       g_value_set_int (value,  priv->values->indent);
1962       break;
1963 
1964     case PROP_STRIKETHROUGH:
1965       g_value_set_boolean (value, priv->values->appearance.strikethrough);
1966       break;
1967 
1968     case PROP_STRIKETHROUGH_RGBA:
1969       if (GTK_TEXT_APPEARANCE_GET_STRIKETHROUGH_RGBA_SET (&priv->values->appearance))
1970         {
1971           GdkRGBA rgba;
1972 
1973           GTK_TEXT_APPEARANCE_GET_STRIKETHROUGH_RGBA (&priv->values->appearance, &rgba);
1974           g_value_set_boxed (value, &rgba);
1975         }
1976       break;
1977 
1978     case PROP_RIGHT_MARGIN:
1979       g_value_set_int (value, priv->values->right_margin);
1980       break;
1981 
1982     case PROP_UNDERLINE:
1983       g_value_set_enum (value, priv->values->appearance.underline);
1984       break;
1985 
1986     case PROP_UNDERLINE_RGBA:
1987       if (GTK_TEXT_APPEARANCE_GET_UNDERLINE_RGBA_SET (&priv->values->appearance))
1988         {
1989           GdkRGBA rgba;
1990 
1991           GTK_TEXT_APPEARANCE_GET_UNDERLINE_RGBA (&priv->values->appearance, &rgba);
1992           g_value_set_boxed (value, &rgba);
1993         }
1994       break;
1995 
1996     case PROP_RISE:
1997       g_value_set_int (value, priv->values->appearance.rise);
1998       break;
1999 
2000     case PROP_BACKGROUND_FULL_HEIGHT:
2001       g_value_set_boolean (value, priv->values->bg_full_height);
2002       break;
2003 
2004     case PROP_LANGUAGE:
2005       g_value_set_string (value, pango_language_to_string (priv->values->language));
2006       break;
2007 
2008     case PROP_TABS:
2009       if (priv->values->tabs)
2010         g_value_set_boxed (value, priv->values->tabs);
2011       break;
2012 
2013     case PROP_INVISIBLE:
2014       g_value_set_boolean (value, priv->values->invisible);
2015       break;
2016 
2017     case PROP_PARAGRAPH_BACKGROUND_GDK:
2018       g_value_set_boxed (value, priv->values->pg_bg_color);
2019       break;
2020 
2021     case PROP_PARAGRAPH_BACKGROUND_RGBA:
2022       g_value_set_boxed (value, priv->values->pg_bg_rgba);
2023       break;
2024 
2025     case PROP_FALLBACK:
2026       g_value_set_boolean (value, !priv->values->no_fallback);
2027       break;
2028 
2029     case PROP_LETTER_SPACING:
2030       g_value_set_int (value, priv->values->letter_spacing);
2031       break;
2032 
2033     case PROP_FONT_FEATURES:
2034       g_value_set_string (value, priv->values->font_features);
2035       break;
2036 
2037     case PROP_ACCUMULATIVE_MARGIN:
2038       g_value_set_boolean (value, priv->accumulative_margin);
2039       break;
2040 
2041     case PROP_BACKGROUND_SET:
2042       g_value_set_boolean (value, priv->bg_color_set);
2043       break;
2044 
2045     case PROP_FOREGROUND_SET:
2046       g_value_set_boolean (value, priv->fg_color_set);
2047       break;
2048 
2049     case PROP_FAMILY_SET:
2050     case PROP_STYLE_SET:
2051     case PROP_VARIANT_SET:
2052     case PROP_WEIGHT_SET:
2053     case PROP_STRETCH_SET:
2054     case PROP_SIZE_SET:
2055       {
2056 	PangoFontMask set_mask = priv->values->font ? pango_font_description_get_set_fields (priv->values->font) : 0;
2057 	PangoFontMask test_mask = get_property_font_set_mask (prop_id);
2058 	g_value_set_boolean (value, (set_mask & test_mask) != 0);
2059 
2060 	break;
2061       }
2062 
2063     case PROP_SCALE_SET:
2064       g_value_set_boolean (value, priv->scale_set);
2065       break;
2066 
2067     case PROP_PIXELS_ABOVE_LINES_SET:
2068       g_value_set_boolean (value, priv->pixels_above_lines_set);
2069       break;
2070 
2071     case PROP_PIXELS_BELOW_LINES_SET:
2072       g_value_set_boolean (value, priv->pixels_below_lines_set);
2073       break;
2074 
2075     case PROP_PIXELS_INSIDE_WRAP_SET:
2076       g_value_set_boolean (value, priv->pixels_inside_wrap_set);
2077       break;
2078 
2079     case PROP_EDITABLE_SET:
2080       g_value_set_boolean (value, priv->editable_set);
2081       break;
2082 
2083     case PROP_WRAP_MODE_SET:
2084       g_value_set_boolean (value, priv->wrap_mode_set);
2085       break;
2086 
2087     case PROP_JUSTIFICATION_SET:
2088       g_value_set_boolean (value, priv->justification_set);
2089       break;
2090 
2091     case PROP_LEFT_MARGIN_SET:
2092       g_value_set_boolean (value, priv->left_margin_set);
2093       break;
2094 
2095     case PROP_INDENT_SET:
2096       g_value_set_boolean (value, priv->indent_set);
2097       break;
2098 
2099     case PROP_STRIKETHROUGH_SET:
2100       g_value_set_boolean (value, priv->strikethrough_set);
2101       break;
2102 
2103     case PROP_STRIKETHROUGH_RGBA_SET:
2104       g_value_set_boolean (value,
2105                            GTK_TEXT_APPEARANCE_GET_STRIKETHROUGH_RGBA_SET (&priv->values->appearance));
2106       break;
2107 
2108     case PROP_RIGHT_MARGIN_SET:
2109       g_value_set_boolean (value, priv->right_margin_set);
2110       break;
2111 
2112     case PROP_UNDERLINE_SET:
2113       g_value_set_boolean (value, priv->underline_set);
2114       break;
2115 
2116     case PROP_UNDERLINE_RGBA_SET:
2117       g_value_set_boolean (value,
2118                            GTK_TEXT_APPEARANCE_GET_UNDERLINE_RGBA_SET (&priv->values->appearance));
2119       break;
2120 
2121     case PROP_RISE_SET:
2122       g_value_set_boolean (value, priv->rise_set);
2123       break;
2124 
2125     case PROP_BACKGROUND_FULL_HEIGHT_SET:
2126       g_value_set_boolean (value, priv->bg_full_height_set);
2127       break;
2128 
2129     case PROP_LANGUAGE_SET:
2130       g_value_set_boolean (value, priv->language_set);
2131       break;
2132 
2133     case PROP_TABS_SET:
2134       g_value_set_boolean (value, priv->tabs_set);
2135       break;
2136 
2137     case PROP_INVISIBLE_SET:
2138       g_value_set_boolean (value, priv->invisible_set);
2139       break;
2140 
2141     case PROP_PARAGRAPH_BACKGROUND_SET:
2142       g_value_set_boolean (value, priv->pg_bg_color_set);
2143       break;
2144 
2145     case PROP_FALLBACK_SET:
2146       g_value_set_boolean (value, priv->fallback_set);
2147       break;
2148 
2149     case PROP_LETTER_SPACING_SET:
2150       g_value_set_boolean (value, priv->letter_spacing_set);
2151       break;
2152 
2153     case PROP_FONT_FEATURES_SET:
2154       g_value_set_boolean (value, priv->font_features_set);
2155       break;
2156 
2157     case PROP_BACKGROUND:
2158     case PROP_FOREGROUND:
2159     case PROP_PARAGRAPH_BACKGROUND:
2160       g_warning ("'foreground', 'background' and 'paragraph_background' properties are not readable, use 'foreground_gdk', 'background_gdk' and 'paragraph_background_gdk'");
2161       break;
2162     default:
2163       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2164       break;
2165     }
2166 }
2167 
2168 /*
2169  * Tag operations
2170  */
2171 
2172 typedef struct {
2173   gint high;
2174   gint low;
2175   gint delta;
2176 } DeltaData;
2177 
2178 static void
delta_priority_foreach(GtkTextTag * tag,gpointer user_data)2179 delta_priority_foreach (GtkTextTag *tag, gpointer user_data)
2180 {
2181   GtkTextTagPrivate *priv = tag->priv;
2182   DeltaData *dd = user_data;
2183 
2184   if (priv->priority >= dd->low && priv->priority <= dd->high)
2185     priv->priority += dd->delta;
2186 }
2187 
2188 /**
2189  * gtk_text_tag_get_priority:
2190  * @tag: a #GtkTextTag
2191  *
2192  * Get the tag priority.
2193  *
2194  * Returns: The tag’s priority.
2195  **/
2196 gint
gtk_text_tag_get_priority(GtkTextTag * tag)2197 gtk_text_tag_get_priority (GtkTextTag *tag)
2198 {
2199   g_return_val_if_fail (GTK_IS_TEXT_TAG (tag), 0);
2200 
2201   return tag->priv->priority;
2202 }
2203 
2204 /**
2205  * gtk_text_tag_set_priority:
2206  * @tag: a #GtkTextTag
2207  * @priority: the new priority
2208  *
2209  * Sets the priority of a #GtkTextTag. Valid priorities
2210  * start at 0 and go to one less than gtk_text_tag_table_get_size().
2211  * Each tag in a table has a unique priority; setting the priority
2212  * of one tag shifts the priorities of all the other tags in the
2213  * table to maintain a unique priority for each tag. Higher priority
2214  * tags “win” if two tags both set the same text attribute. When adding
2215  * a tag to a tag table, it will be assigned the highest priority in
2216  * the table by default; so normally the precedence of a set of tags
2217  * is the order in which they were added to the table, or created with
2218  * gtk_text_buffer_create_tag(), which adds the tag to the buffer’s table
2219  * automatically.
2220  **/
2221 void
gtk_text_tag_set_priority(GtkTextTag * tag,gint priority)2222 gtk_text_tag_set_priority (GtkTextTag *tag,
2223                            gint        priority)
2224 {
2225   GtkTextTagPrivate *priv;
2226   DeltaData dd;
2227 
2228   g_return_if_fail (GTK_IS_TEXT_TAG (tag));
2229 
2230   priv = tag->priv;
2231 
2232   g_return_if_fail (priv->table != NULL);
2233   g_return_if_fail (priority >= 0);
2234   g_return_if_fail (priority < gtk_text_tag_table_get_size (priv->table));
2235 
2236   if (priority == priv->priority)
2237     return;
2238 
2239   if (priority < priv->priority)
2240     {
2241       dd.low = priority;
2242       dd.high = priv->priority - 1;
2243       dd.delta = 1;
2244     }
2245   else
2246     {
2247       dd.low = priv->priority + 1;
2248       dd.high = priority;
2249       dd.delta = -1;
2250     }
2251 
2252   gtk_text_tag_table_foreach (priv->table,
2253                               delta_priority_foreach,
2254                               &dd);
2255 
2256   priv->priority = priority;
2257 }
2258 
2259 /**
2260  * gtk_text_tag_event:
2261  * @tag: a #GtkTextTag
2262  * @event_object: object that received the event, such as a widget
2263  * @event: the event
2264  * @iter: location where the event was received
2265  *
2266  * Emits the “event” signal on the #GtkTextTag.
2267  *
2268  * Returns: result of signal emission (whether the event was handled)
2269  **/
2270 gboolean
gtk_text_tag_event(GtkTextTag * tag,GObject * event_object,GdkEvent * event,const GtkTextIter * iter)2271 gtk_text_tag_event (GtkTextTag        *tag,
2272                     GObject           *event_object,
2273                     GdkEvent          *event,
2274                     const GtkTextIter *iter)
2275 {
2276   gboolean retval = FALSE;
2277 
2278   g_return_val_if_fail (GTK_IS_TEXT_TAG (tag), FALSE);
2279   g_return_val_if_fail (G_IS_OBJECT (event_object), FALSE);
2280   g_return_val_if_fail (event != NULL, FALSE);
2281 
2282   g_signal_emit (tag,
2283                  signals[EVENT],
2284                  0,
2285                  event_object,
2286                  event,
2287                  iter,
2288                  &retval);
2289 
2290   return retval;
2291 }
2292 
2293 /**
2294  * gtk_text_tag_changed:
2295  * @tag: a #GtkTextTag.
2296  * @size_changed: whether the change affects the #GtkTextView layout.
2297  *
2298  * Emits the #GtkTextTagTable::tag-changed signal on the #GtkTextTagTable where
2299  * the tag is included.
2300  *
2301  * The signal is already emitted when setting a #GtkTextTag property. This
2302  * function is useful for a #GtkTextTag subclass.
2303  *
2304  * Since: 3.20
2305  */
2306 void
gtk_text_tag_changed(GtkTextTag * tag,gboolean size_changed)2307 gtk_text_tag_changed (GtkTextTag *tag,
2308                       gboolean    size_changed)
2309 {
2310   GtkTextTagPrivate *priv;
2311 
2312   g_return_if_fail (GTK_IS_TEXT_TAG (tag));
2313 
2314   priv = tag->priv;
2315 
2316   /* This is somewhat weird since we emit another object's signal here, but the
2317    * two objects are already tightly bound. If a GtkTextTag::changed signal is
2318    * added, this would increase significantly the number of signal connections.
2319    */
2320   if (priv->table != NULL)
2321     _gtk_text_tag_table_tag_changed (priv->table, tag, size_changed);
2322 }
2323 
2324 static int
tag_sort_func(gconstpointer first,gconstpointer second)2325 tag_sort_func (gconstpointer first, gconstpointer second)
2326 {
2327   GtkTextTag *tag1, *tag2;
2328 
2329   tag1 = * (GtkTextTag **) first;
2330   tag2 = * (GtkTextTag **) second;
2331   return tag1->priv->priority - tag2->priv->priority;
2332 }
2333 
2334 void
_gtk_text_tag_array_sort(GtkTextTag ** tag_array_p,guint len)2335 _gtk_text_tag_array_sort (GtkTextTag** tag_array_p,
2336                           guint len)
2337 {
2338   int i, j, prio;
2339   GtkTextTag **tag;
2340   GtkTextTag **maxPtrPtr, *tmp;
2341 
2342   g_return_if_fail (tag_array_p != NULL);
2343   g_return_if_fail (len > 0);
2344 
2345   if (len < 2) {
2346     return;
2347   }
2348   if (len < 20) {
2349     GtkTextTag **iter = tag_array_p;
2350 
2351     for (i = len-1; i > 0; i--, iter++) {
2352       maxPtrPtr = tag = iter;
2353       prio = tag[0]->priv->priority;
2354       for (j = i, tag++; j > 0; j--, tag++) {
2355         if (tag[0]->priv->priority < prio) {
2356           prio = tag[0]->priv->priority;
2357           maxPtrPtr = tag;
2358         }
2359       }
2360       tmp = *maxPtrPtr;
2361       *maxPtrPtr = *iter;
2362       *iter = tmp;
2363     }
2364   } else {
2365     qsort ((void *) tag_array_p, (unsigned) len, sizeof (GtkTextTag *),
2366            tag_sort_func);
2367   }
2368 
2369 #if 0
2370   {
2371     printf ("Sorted tag array: \n");
2372     i = 0;
2373     while (i < len)
2374       {
2375         GtkTextTag *t = tag_array_p[i];
2376         printf ("  %s priority %d\n", t->name, t->priority);
2377 
2378         ++i;
2379       }
2380   }
2381 #endif
2382 }
2383 
2384