1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 2011 Red Hat, Inc.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include "config.h"
19 
20 #include "gtkcsssectionprivate.h"
21 
22 #include "gtkcssparserprivate.h"
23 #include "gtkprivate.h"
24 
25 struct _GtkCssSection
26 {
27   gint                ref_count;
28   GtkCssSectionType   section_type;
29   GtkCssSection      *parent;
30   GFile              *file;
31   guint               start_line;
32   guint               start_position;
33   GtkCssParser       *parser;         /* parser if section isn't finished parsing yet or %NULL */
34   guint               end_line;       /* end line if parser is %NULL */
35   guint               end_position;   /* end position if parser is %NULL */
36 };
37 
G_DEFINE_BOXED_TYPE(GtkCssSection,gtk_css_section,gtk_css_section_ref,gtk_css_section_unref)38 G_DEFINE_BOXED_TYPE (GtkCssSection, gtk_css_section, gtk_css_section_ref, gtk_css_section_unref)
39 
40 GtkCssSection *
41 _gtk_css_section_new (GtkCssSection     *parent,
42                       GtkCssSectionType  type,
43                       GtkCssParser      *parser)
44 {
45   GtkCssSection *section;
46 
47   gtk_internal_return_val_if_fail (parser != NULL, NULL);
48 
49   section = g_slice_new0 (GtkCssSection);
50 
51   section->ref_count = 1;
52   section->section_type = type;
53   if (parent)
54     section->parent = gtk_css_section_ref (parent);
55   section->file = _gtk_css_parser_get_file (parser);
56   if (section->file)
57     g_object_ref (section->file);
58   section->start_line = _gtk_css_parser_get_line (parser);
59   section->start_position = _gtk_css_parser_get_position (parser);
60   section->parser = parser;
61 
62   return section;
63 }
64 
65 GtkCssSection *
_gtk_css_section_new_for_file(GtkCssSectionType type,GFile * file)66 _gtk_css_section_new_for_file (GtkCssSectionType  type,
67                                GFile             *file)
68 {
69   GtkCssSection *section;
70 
71   gtk_internal_return_val_if_fail (G_IS_FILE (file), NULL);
72 
73   section = g_slice_new0 (GtkCssSection);
74 
75   section->ref_count = 1;
76   section->section_type = type;
77   section->file = g_object_ref (file);
78 
79   return section;
80 }
81 
82 void
_gtk_css_section_end(GtkCssSection * section)83 _gtk_css_section_end (GtkCssSection *section)
84 {
85   gtk_internal_return_if_fail (section != NULL);
86   gtk_internal_return_if_fail (section->parser != NULL);
87 
88   section->end_line = _gtk_css_parser_get_line (section->parser);
89   section->end_position = _gtk_css_parser_get_position (section->parser);
90   section->parser = NULL;
91 }
92 
93 /**
94  * gtk_css_section_ref:
95  * @section: a #GtkCssSection
96  *
97  * Increments the reference count on @section.
98  *
99  * Returns: @section itself.
100  *
101  * Since: 3.2
102  **/
103 GtkCssSection *
gtk_css_section_ref(GtkCssSection * section)104 gtk_css_section_ref (GtkCssSection *section)
105 {
106   gtk_internal_return_val_if_fail (section != NULL, NULL);
107 
108   section->ref_count += 1;
109 
110   return section;
111 }
112 
113 /**
114  * gtk_css_section_unref:
115  * @section: a #GtkCssSection
116  *
117  * Decrements the reference count on @section, freeing the
118  * structure if the reference count reaches 0.
119  *
120  * Since: 3.2
121  **/
122 void
gtk_css_section_unref(GtkCssSection * section)123 gtk_css_section_unref (GtkCssSection *section)
124 {
125   gtk_internal_return_if_fail (section != NULL);
126 
127   section->ref_count -= 1;
128   if (section->ref_count > 0)
129     return;
130 
131   if (section->parent)
132     gtk_css_section_unref (section->parent);
133   if (section->file)
134     g_object_unref (section->file);
135 
136   g_slice_free (GtkCssSection, section);
137 }
138 
139 /**
140  * gtk_css_section_get_section_type:
141  * @section: the section
142  *
143  * Gets the type of information that @section describes.
144  *
145  * Returns: the type of @section
146  *
147  * Since: 3.2
148  **/
149 GtkCssSectionType
gtk_css_section_get_section_type(const GtkCssSection * section)150 gtk_css_section_get_section_type (const GtkCssSection *section)
151 {
152   gtk_internal_return_val_if_fail (section != NULL, GTK_CSS_SECTION_DOCUMENT);
153 
154   return section->section_type;
155 }
156 
157 /**
158  * gtk_css_section_get_parent:
159  * @section: the section
160  *
161  * Gets the parent section for the given @section. The parent section is
162  * the section that contains this @section. A special case are sections of
163  * type #GTK_CSS_SECTION_DOCUMENT. Their parent will either be %NULL
164  * if they are the original CSS document that was loaded by
165  * gtk_css_provider_load_from_file() or a section of type
166  * #GTK_CSS_SECTION_IMPORT if it was loaded with an import rule from
167  * a different file.
168  *
169  * Returns: (nullable) (transfer none): the parent section or %NULL if none
170  *
171  * Since: 3.2
172  **/
173 GtkCssSection *
gtk_css_section_get_parent(const GtkCssSection * section)174 gtk_css_section_get_parent (const GtkCssSection *section)
175 {
176   gtk_internal_return_val_if_fail (section != NULL, NULL);
177 
178   return section->parent;
179 }
180 
181 /**
182  * gtk_css_section_get_file:
183  * @section: the section
184  *
185  * Gets the file that @section was parsed from. If no such file exists,
186  * for example because the CSS was loaded via
187  * @gtk_css_provider_load_from_data(), then %NULL is returned.
188  *
189  * Returns: (transfer none): the #GFile that @section was parsed from
190  *     or %NULL if @section was parsed from other data
191  *
192  * Since: 3.2
193  **/
194 GFile *
gtk_css_section_get_file(const GtkCssSection * section)195 gtk_css_section_get_file (const GtkCssSection *section)
196 {
197   gtk_internal_return_val_if_fail (section != NULL, NULL);
198 
199   return section->file;
200 }
201 
202 /**
203  * gtk_css_section_get_start_line:
204  * @section: the section
205  *
206  * Returns the line in the CSS document where this section starts.
207  * The line number is 0-indexed, so the first line of the document
208  * will return 0.
209  *
210  * Returns: the line number
211  *
212  * Since: 3.2
213  **/
214 guint
gtk_css_section_get_start_line(const GtkCssSection * section)215 gtk_css_section_get_start_line (const GtkCssSection *section)
216 {
217   gtk_internal_return_val_if_fail (section != NULL, 0);
218 
219   return section->start_line;
220 }
221 
222 /**
223  * gtk_css_section_get_start_position:
224  * @section: the section
225  *
226  * Returns the offset in bytes from the start of the current line
227  * returned via gtk_css_section_get_start_line().
228  *
229  * Returns: the offset in bytes from the start of the line.
230  *
231  * Since: 3.2
232  **/
233 guint
gtk_css_section_get_start_position(const GtkCssSection * section)234 gtk_css_section_get_start_position (const GtkCssSection *section)
235 {
236   gtk_internal_return_val_if_fail (section != NULL, 0);
237 
238   return section->start_position;
239 }
240 
241 /**
242  * gtk_css_section_get_end_line:
243  * @section: the section
244  *
245  * Returns the line in the CSS document where this section end.
246  * The line number is 0-indexed, so the first line of the document
247  * will return 0.
248  * This value may change in future invocations of this function if
249  * @section is not yet parsed completely. This will for example
250  * happen in the GtkCssProvider::parsing-error signal.
251  * The end position and line may be identical to the start
252  * position and line for sections which failed to parse anything
253  * successfully.
254  *
255  * Returns: the line number
256  *
257  * Since: 3.2
258  **/
259 guint
gtk_css_section_get_end_line(const GtkCssSection * section)260 gtk_css_section_get_end_line (const GtkCssSection *section)
261 {
262   gtk_internal_return_val_if_fail (section != NULL, 0);
263 
264   if (section->parser)
265     return _gtk_css_parser_get_line (section->parser);
266   else
267     return section->end_line;
268 }
269 
270 /**
271  * gtk_css_section_get_end_position:
272  * @section: the section
273  *
274  * Returns the offset in bytes from the start of the current line
275  * returned via gtk_css_section_get_end_line().
276  * This value may change in future invocations of this function if
277  * @section is not yet parsed completely. This will for example
278  * happen in the GtkCssProvider::parsing-error signal.
279  * The end position and line may be identical to the start
280  * position and line for sections which failed to parse anything
281  * successfully.
282  *
283  * Returns: the offset in bytes from the start of the line.
284  *
285  * Since: 3.2
286  **/
287 guint
gtk_css_section_get_end_position(const GtkCssSection * section)288 gtk_css_section_get_end_position (const GtkCssSection *section)
289 {
290   gtk_internal_return_val_if_fail (section != NULL, 0);
291 
292   if (section->parser)
293     return _gtk_css_parser_get_position (section->parser);
294   else
295     return section->end_position;
296 }
297 
298 void
_gtk_css_section_print(const GtkCssSection * section,GString * string)299 _gtk_css_section_print (const GtkCssSection  *section,
300                         GString              *string)
301 {
302   if (section->file)
303     {
304       GFileInfo *info;
305 
306       info = g_file_query_info (section->file, G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME, 0, NULL, NULL);
307 
308       if (info)
309         {
310           g_string_append (string, g_file_info_get_display_name (info));
311           g_object_unref (info);
312         }
313       else
314         {
315           g_string_append (string, "<broken file>");
316         }
317     }
318   else
319     {
320       g_string_append (string, "<data>");
321     }
322 
323   g_string_append_printf (string, ":%u:%u",
324                           gtk_css_section_get_end_line (section) + 1,
325                           gtk_css_section_get_end_position (section));
326 }
327 
328 char *
_gtk_css_section_to_string(const GtkCssSection * section)329 _gtk_css_section_to_string (const GtkCssSection *section)
330 {
331   GString *string;
332 
333   gtk_internal_return_val_if_fail (section != NULL, NULL);
334 
335   string = g_string_new (NULL);
336   _gtk_css_section_print (section, string);
337 
338   return g_string_free (string, FALSE);
339 }
340