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