1/* GTK - The GIMP Toolkit
2 * Copyright (C) 1998-2002 James Henstridge <james@daa.com.au>
3 * Copyright (C) 2006-2007 Async Open Source,
4 * Johan Dahlin <jdahlin@async.com.br>,
5 * Henrique Romano <henrique@async.com.br>
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21/**
22 * GtkBuilder:
23 *
24 * A `GtkBuilder` reads XML descriptions of a user interface and
25 * instantiates the described objects.
26 *
27 * To create a `GtkBuilder` from a user interface description, call
28 * [ctor@Gtk.Builder.new_from_file], [ctor@Gtk.Builder.new_from_resource]
29 * or [ctor@Gtk.Builder.new_from_string].
30 *
31 * In the (unusual) case that you want to add user interface
32 * descriptions from multiple sources to the same `GtkBuilder` you can
33 * call [ctor@Gtk.Builder.new] to get an empty builder and populate it by
34 * (multiple) calls to [method@Gtk.Builder.add_from_file],
35 * [method@Gtk.Builder.add_from_resource] or
36 * [method@Gtk.Builder.add_from_string].
37 *
38 * A `GtkBuilder` holds a reference to all objects that it has constructed
39 * and drops these references when it is finalized. This finalization can
40 * cause the destruction of non-widget objects or widgets which are not
41 * contained in a toplevel window. For toplevel windows constructed by a
42 * builder, it is the responsibility of the user to call
43 * [method@Gtk.Window.destroy] to get rid of them and all the widgets
44 * they contain.
45 *
46 * The functions [method@Gtk.Builder.get_object] and
47 * [method@Gtk.Builder.get_objects] can be used to access the widgets in
48 * the interface by the names assigned to them inside the UI description.
49 * Toplevel windows returned by these functions will stay around until the
50 * user explicitly destroys them with [method@Gtk.Window.destroy]. Other
51 * widgets will either be part of a larger hierarchy constructed by the
52 * builder (in which case you should not have to worry about their lifecycle),
53 * or without a parent, in which case they have to be added to some container
54 * to make use of them. Non-widget objects need to be reffed with
55 * g_object_ref() to keep them beyond the lifespan of the builder.
56 *
57 * # GtkBuilder UI Definitions
58 *
59 * `GtkBuilder` parses textual descriptions of user interfaces which are
60 * specified in XML format. We refer to these descriptions as “GtkBuilder
61 * UI definitions” or just “UI definitions” if the context is clear.
62 *
63 * The toplevel element is `<interface>`. It optionally takes a “domain”
64 * attribute, which will make the builder look for translated strings
65 * using `dgettext()` in the domain specified. This can also be done by
66 * calling [method@Gtk.Builder.set_translation_domain] on the builder.
67 *
68 * Objects are described by `<object>` elements, which can contain
69 * `<property>` elements to set properties, `<signal>` elements which
70 * connect signals to handlers, and `<child>` elements, which describe
71 * child objects (most often widgets inside a container, but also e.g.
72 * actions in an action group, or columns in a tree model). A `<child>`
73 * element contains an `<object>` element which describes the child object.
74 *
75 * The target toolkit version(s) are described by `<requires>` elements,
76 * the “lib” attribute specifies the widget library in question (currently
77 * the only supported value is “gtk”) and the “version” attribute specifies
78 * the target version in the form “`<major>`.`<minor>`”. `GtkBuilder` will
79 * error out if the version requirements are not met.
80 *
81 * Typically, the specific kind of object represented by an `<object>`
82 * element is specified by the “class” attribute. If the type has not
83 * been loaded yet, GTK tries to find the `get_type()` function from the
84 * class name by applying heuristics. This works in most cases, but if
85 * necessary, it is possible to specify the name of the `get_type()`
86 * function explicitly with the "type-func" attribute.
87 *
88 * Objects may be given a name with the “id” attribute, which allows the
89 * application to retrieve them from the builder with
90 * [method@Gtk.Builder.get_object]. An id is also necessary to use the
91 * object as property value in other parts of the UI definition. GTK
92 * reserves ids starting and ending with `___` (three consecutive
93 * underscores) for its own purposes.
94 *
95 * Setting properties of objects is pretty straightforward with the
96 * `<property>` element: the “name” attribute specifies the name of the
97 * property, and the content of the element specifies the value.
98 * If the “translatable” attribute is set to a true value, GTK uses
99 * `gettext()` (or `dgettext()` if the builder has a translation domain set)
100 * to find a translation for the value. This happens before the value
101 * is parsed, so it can be used for properties of any type, but it is
102 * probably most useful for string properties. It is also possible to
103 * specify a context to disambiguate short strings, and comments which
104 * may help the translators.
105 *
106 * `GtkBuilder` can parse textual representations for the most common
107 * property types: characters, strings, integers, floating-point numbers,
108 * booleans (strings like “TRUE”, “t”, “yes”, “y”, “1” are interpreted
109 * as %TRUE, strings like “FALSE”, “f”, “no”, “n”, “0” are interpreted
110 * as %FALSE), enumerations (can be specified by their name, nick or
111 * integer value), flags (can be specified by their name, nick, integer
112 * value, optionally combined with “|”, e.g.
113 * “GTK_INPUT_HINT_EMOJI|GTK_INPUT_HINT_LOWERCASE”)
114 * and colors (in a format understood by [method@Gdk.RGBA.parse]).
115 *
116 * `GVariant`s can be specified in the format understood by
117 * g_variant_parse(), and pixbufs can be specified as a filename of an
118 * image file to load.
119 *
120 * Objects can be referred to by their name and by default refer to
121 * objects declared in the local XML fragment and objects exposed via
122 * [method@Gtk.Builder.expose_object]. In general, `GtkBuilder` allows
123 * forward references to objects — declared in the local XML; an object
124 * doesn’t have to be constructed before it can be referred to. The
125 * exception to this rule is that an object has to be constructed before
126 * it can be used as the value of a construct-only property.
127 *
128 * It is also possible to bind a property value to another object's
129 * property value using the attributes "bind-source" to specify the
130 * source object of the binding, and optionally, "bind-property" and
131 * "bind-flags" to specify the source property and source binding flags
132 * respectively. Internally, `GtkBuilder` implements this using `GBinding`
133 * objects. For more information see g_object_bind_property().
134 *
135 * Sometimes it is necessary to refer to widgets which have implicitly
136 * been constructed by GTK as part of a composite widget, to set
137 * properties on them or to add further children (e.g. the content area
138 * of a `GtkDialog`). This can be achieved by setting the “internal-child”
139 * property of the `<child>` element to a true value. Note that `GtkBuilder`
140 * still requires an `<object>` element for the internal child, even if it
141 * has already been constructed.
142 *
143 * A number of widgets have different places where a child can be added
144 * (e.g. tabs vs. page content in notebooks). This can be reflected in
145 * a UI definition by specifying the “type” attribute on a `<child>`
146 * The possible values for the “type” attribute are described in the
147 * sections describing the widget-specific portions of UI definitions.
148 *
149 * # Signal handlers and function pointers
150 *
151 * Signal handlers are set up with the `<signal>` element. The “name”
152 * attribute specifies the name of the signal, and the “handler” attribute
153 * specifies the function to connect to the signal.
154 * The remaining attributes, “after”, “swapped” and “object”, have the
155 * same meaning as the corresponding parameters of the
156 * g_signal_connect_object() or g_signal_connect_data() functions. A
157 * “last_modification_time” attribute is also allowed, but it does not
158 * have a meaning to the builder.
159 *
160 * If you rely on `GModule` support to lookup callbacks in the symbol table,
161 * the following details should be noted:
162 *
163 * When compiling applications for Windows, you must declare signal callbacks
164 * with %G_MODULE_EXPORT, or they will not be put in the symbol table.
165 * On Linux and Unix, this is not necessary; applications should instead
166 * be compiled with the -Wl,--export-dynamic `CFLAGS`, and linked against
167 * `gmodule-export-2.0`.
168 *
169 * # A GtkBuilder UI Definition
170 *
171 * ```xml
172 * <interface>
173 * <object class="GtkDialog" id="dialog1">
174 * <child internal-child="content_area">
175 * <object class="GtkBox" id="vbox1">
176 * <child internal-child="action_area">
177 * <object class="GtkBox" id="hbuttonbox1">
178 * <child>
179 * <object class="GtkButton" id="ok_button">
180 * <property name="label" translatable="yes">_Ok</property>
181 * <property name="use-underline">True</property>
182 * <signal name="clicked" handler="ok_button_clicked"/>
183 * </object>
184 * </child>
185 * </object>
186 * </child>
187 * </object>
188 * </child>
189 * </object>
190 * </interface>
191 * ```
192 *
193 * Beyond this general structure, several object classes define their
194 * own XML DTD fragments for filling in the ANY placeholders in the DTD
195 * above. Note that a custom element in a <child> element gets parsed by
196 * the custom tag handler of the parent object, while a custom element in
197 * an <object> element gets parsed by the custom tag handler of the object.
198 *
199 * These XML fragments are explained in the documentation of the
200 * respective objects.
201 *
202 * A `<template>` tag can be used to define a widget class’s components.
203 * See the [GtkWidget documentation](class.Widget.html#building-composite-widgets-from-template-xml) for details.
204 */
205
206#include "config.h"
207#include <errno.h> /* errno */
208#include <stdlib.h>
209#include <string.h> /* strlen */
210
211#include "gtkbuilderprivate.h"
212
213#include "gtkbuildableprivate.h"
214#include "gtkbuilderlistitemfactory.h"
215#include "gtkbuilderscopeprivate.h"
216#include "gtkdebug.h"
217#include "gtkexpression.h"
218#include "gtkmain.h"
219#include "gtkicontheme.h"
220#include "gtkintl.h"
221#include "gtkprivate.h"
222#include "gtkshortcutactionprivate.h"
223#include "gtkshortcuttrigger.h"
224#include "gtktestutils.h"
225#include "gtktypebuiltins.h"
226#include "gtkicontheme.h"
227#include "gtkiconthemeprivate.h"
228#include "gtkdebug.h"
229
230
231static void gtk_builder_finalize (GObject *object);
232static void gtk_builder_set_property (GObject *object,
233 guint prop_id,
234 const GValue *value,
235 GParamSpec *pspec);
236static void gtk_builder_get_property (GObject *object,
237 guint prop_id,
238 GValue *value,
239 GParamSpec *pspec);
240
241enum {
242 PROP_0,
243 PROP_CURRENT_OBJECT,
244 PROP_SCOPE,
245 PROP_TRANSLATION_DOMAIN,
246 LAST_PROP
247};
248
249static GParamSpec *builder_props[LAST_PROP];
250
251struct _GtkBuilder
252{
253 GObject parent_instance;
254};
255
256struct _GtkBuilderClass
257{
258 GObjectClass parent_class;
259};
260
261typedef struct
262{
263 char *domain;
264 GHashTable *objects;
265 GSList *delayed_properties;
266 GPtrArray *signals;
267 GSList *bindings;
268 char *filename;
269 char *resource_prefix;
270 GType template_type;
271 GObject *current_object;
272 GtkBuilderScope *scope;
273} GtkBuilderPrivate;
274
275G_DEFINE_TYPE_WITH_PRIVATE (GtkBuilder, gtk_builder, G_TYPE_OBJECT)
276
277static void
278gtk_builder_dispose (GObject *object)
279{
280 GtkBuilderPrivate *priv = gtk_builder_get_instance_private (GTK_BUILDER (object));
281
282 g_clear_object (&priv->current_object);
283 g_clear_object (&priv->scope);
284
285 G_OBJECT_CLASS (gtk_builder_parent_class)->dispose (object);
286}
287
288static void
289gtk_builder_class_init (GtkBuilderClass *klass)
290{
291 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
292
293 gobject_class->dispose = gtk_builder_dispose;
294 gobject_class->finalize = gtk_builder_finalize;
295 gobject_class->set_property = gtk_builder_set_property;
296 gobject_class->get_property = gtk_builder_get_property;
297
298 /**
299 * GtkBuilder:translation-domain: (attributes org.gtk.Property.get=gtk_builder_get_translation_domain org.gtk.Property.set=gtk_builder_set_translation_domain)
300 *
301 * The translation domain used when translating property values that
302 * have been marked as translatable.
303 *
304 * If the translation domain is %NULL, `GtkBuilder` uses gettext(),
305 * otherwise g_dgettext().
306 */
307 builder_props[PROP_TRANSLATION_DOMAIN] =
308 g_param_spec_string (name: "translation-domain",
309 P_("Translation Domain"),
310 P_("The translation domain used by gettext"),
311 NULL,
312 GTK_PARAM_READWRITE);
313
314 /**
315 * GtkBuilder:current-object: (attributes org.gtk.Property.get=gtk_builder_get_current_object org.gtk.Property.set=gtk_builder_set_current_object)
316 *
317 * The object the builder is evaluating for.
318 */
319 builder_props[PROP_CURRENT_OBJECT] =
320 g_param_spec_object (name: "current-object",
321 P_("Current object"),
322 P_("The object the builder is evaluating for"),
323 G_TYPE_OBJECT,
324 GTK_PARAM_READWRITE);
325
326 /**
327 * GtkBuilder:scope: (attributes org.gtk.Property.get=gtk_builder_get_scope org.gtk.Property.set=gtk_builder_set_scope)
328 *
329 * The scope the builder is operating in
330 */
331 builder_props[PROP_SCOPE] =
332 g_param_spec_object (name: "scope",
333 P_("Scope"),
334 P_("The scope the builder is operating in"),
335 GTK_TYPE_BUILDER_SCOPE,
336 GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT);
337
338 g_object_class_install_properties (oclass: gobject_class, n_pspecs: LAST_PROP, pspecs: builder_props);
339}
340
341static void
342gtk_builder_init (GtkBuilder *builder)
343{
344 GtkBuilderPrivate *priv = gtk_builder_get_instance_private (self: builder);
345
346 priv->domain = NULL;
347 priv->objects = g_hash_table_new_full (hash_func: g_str_hash, key_equal_func: g_str_equal,
348 key_destroy_func: g_free, value_destroy_func: g_object_unref);
349}
350
351
352/*
353 * GObject virtual methods
354 */
355
356static void
357gtk_builder_finalize (GObject *object)
358{
359 GtkBuilderPrivate *priv = gtk_builder_get_instance_private (GTK_BUILDER (object));
360
361 g_free (mem: priv->domain);
362 g_free (mem: priv->filename);
363 g_free (mem: priv->resource_prefix);
364
365#ifdef G_ENABLE_DEBUG
366 if (GTK_DEBUG_CHECK (BUILDER_OBJECTS))
367 {
368 GHashTableIter iter;
369 gpointer key, value;
370
371 g_hash_table_iter_init (iter: &iter, hash_table: priv->objects);
372 while (g_hash_table_iter_next (iter: &iter, key: &key, value: &value))
373 {
374 if (G_OBJECT (value)->ref_count == 1)
375 g_message ("builder: %s with id %s unused",
376 G_OBJECT_TYPE_NAME (value), (const char *)key);
377 }
378 }
379#endif
380
381 g_hash_table_destroy (hash_table: priv->objects);
382 if (priv->signals)
383 g_ptr_array_free (array: priv->signals, TRUE);
384
385 G_OBJECT_CLASS (gtk_builder_parent_class)->finalize (object);
386}
387
388static void
389gtk_builder_set_property (GObject *object,
390 guint prop_id,
391 const GValue *value,
392 GParamSpec *pspec)
393{
394 GtkBuilder *builder = GTK_BUILDER (object);
395
396 switch (prop_id)
397 {
398 case PROP_CURRENT_OBJECT:
399 gtk_builder_set_current_object (builder, current_object: g_value_get_object (value));
400 break;
401
402 case PROP_SCOPE:
403 gtk_builder_set_scope (builder, scope: g_value_get_object (value));
404 break;
405
406 case PROP_TRANSLATION_DOMAIN:
407 gtk_builder_set_translation_domain (builder, domain: g_value_get_string (value));
408 break;
409
410 default:
411 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
412 break;
413 }
414}
415
416static void
417gtk_builder_get_property (GObject *object,
418 guint prop_id,
419 GValue *value,
420 GParamSpec *pspec)
421{
422 GtkBuilder *builder = GTK_BUILDER (object);
423 GtkBuilderPrivate *priv = gtk_builder_get_instance_private (self: builder);
424
425 switch (prop_id)
426 {
427 case PROP_CURRENT_OBJECT:
428 g_value_set_object (value, v_object: priv->current_object);
429 break;
430
431 case PROP_SCOPE:
432 g_value_set_object (value, v_object: priv->scope);
433 break;
434
435 case PROP_TRANSLATION_DOMAIN:
436 g_value_set_string (value, v_string: priv->domain);
437 break;
438
439 default:
440 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
441 break;
442 }
443}
444
445/*
446 * GtkBuilder virtual methods
447 */
448
449typedef struct
450{
451 char *object;
452 GParamSpec *pspec;
453 char *value;
454 int line;
455 int col;
456} DelayedProperty;
457
458typedef struct
459{
460 GPtrArray *names;
461 GArray *values;
462} ObjectProperties;
463
464
465static void
466object_properties_init (ObjectProperties *self)
467{
468 self->names = NULL;
469 self->values = NULL;
470}
471
472static void
473object_properties_destroy (ObjectProperties *self)
474{
475 if (self == NULL)
476 return;
477
478 if (self->names)
479 g_ptr_array_unref (array: self->names);
480
481 if (self->values)
482 g_array_unref (array: self->values);
483}
484
485static void
486object_properties_add (ObjectProperties *self,
487 const char *name,
488 const GValue *value)
489{
490 if (!self->names)
491 {
492 self->names = g_ptr_array_sized_new (reserved_size: 8);
493 self->values = g_array_sized_new (FALSE, FALSE, element_size: sizeof (GValue), reserved_size: 8);
494 g_array_set_clear_func (array: self->values, clear_func: (GDestroyNotify) g_value_unset);
495 }
496
497 g_ptr_array_add (array: self->names, data: (char *) name);
498 g_array_append_vals (array: self->values, data: value, len: 1);
499
500 g_assert (self->names->len == self->values->len);
501}
502
503static const char *
504object_properties_get_name (const ObjectProperties *self,
505 guint idx)
506{
507 g_assert (self->names);
508
509 return g_ptr_array_index (self->names, idx);
510}
511
512static GValue *
513object_properties_get_value (const ObjectProperties *self,
514 guint idx)
515{
516 g_assert (self->values);
517
518 return &g_array_index (self->values, GValue, idx);
519}
520
521static void
522gtk_builder_get_parameters (GtkBuilder *builder,
523 GType object_type,
524 const char *object_name,
525 GPtrArray *properties,
526 GParamFlags filter_flags,
527 ObjectProperties *parameters,
528 ObjectProperties *filtered_parameters)
529{
530 GtkBuilderPrivate *priv = gtk_builder_get_instance_private (self: builder);
531 DelayedProperty *property;
532 GError *error = NULL;
533
534 if (!properties)
535 return;
536
537 for (guint i = 0; i < properties->len; i++)
538 {
539 PropertyInfo *prop = g_ptr_array_index (properties, i);
540 const char *property_name = prop->pspec->name;
541 GValue property_value = G_VALUE_INIT;
542 ObjectProperties *params;
543
544 if (prop->applied)
545 continue;
546
547 if ((prop->pspec->flags & filter_flags) != 0)
548 params = filtered_parameters;
549 else
550 params = parameters;
551
552 if (!params)
553 continue;
554
555 if (prop->value)
556 {
557 g_value_init (value: &property_value, G_PARAM_SPEC_VALUE_TYPE (prop->pspec));
558
559 if (G_PARAM_SPEC_VALUE_TYPE (prop->pspec) == GTK_TYPE_EXPRESSION)
560 gtk_value_set_expression (value: &property_value, expression: prop->value);
561 else
562 g_assert_not_reached ();
563 }
564 else if (prop->bound && (!prop->text || prop->text->len == 0))
565 {
566 /* Ignore properties with a binding and no value since they are
567 * only there for to express the binding.
568 */
569 continue;
570 }
571 else if (G_IS_PARAM_SPEC_OBJECT (prop->pspec) &&
572 (G_PARAM_SPEC_VALUE_TYPE (prop->pspec) != GDK_TYPE_PIXBUF) &&
573 (G_PARAM_SPEC_VALUE_TYPE (prop->pspec) != GDK_TYPE_TEXTURE) &&
574 (G_PARAM_SPEC_VALUE_TYPE (prop->pspec) != GDK_TYPE_PAINTABLE) &&
575 (G_PARAM_SPEC_VALUE_TYPE (prop->pspec) != GTK_TYPE_SHORTCUT_TRIGGER) &&
576 (G_PARAM_SPEC_VALUE_TYPE (prop->pspec) != GTK_TYPE_SHORTCUT_ACTION) &&
577 (G_PARAM_SPEC_VALUE_TYPE (prop->pspec) != G_TYPE_FILE))
578 {
579 GObject *object = g_hash_table_lookup (hash_table: priv->objects,
580 g_strstrip (prop->text->str));
581
582 if (object)
583 {
584 g_value_init (value: &property_value, G_OBJECT_TYPE (object));
585 g_value_set_object (value: &property_value, v_object: object);
586 }
587 else
588 {
589 if (prop->pspec->flags & G_PARAM_CONSTRUCT_ONLY)
590 {
591 g_warning ("Failed to get construct only property "
592 "%s of %s with value '%s'",
593 prop->pspec->name, object_name, prop->text->str);
594 continue;
595 }
596 /* Delay setting property */
597
598 prop->applied = TRUE;
599
600 property = g_slice_new (DelayedProperty);
601 property->pspec = prop->pspec;
602 property->object = g_strdup (str: object_name);
603 property->value = g_strdup (str: prop->text->str);
604 property->line = prop->line;
605 property->col = prop->col;
606 priv->delayed_properties = g_slist_prepend (list: priv->delayed_properties,
607 data: property);
608 continue;
609 }
610 }
611 else if (!gtk_builder_value_from_string (builder, pspec: prop->pspec,
612 string: prop->text->str,
613 value: &property_value,
614 error: &error))
615 {
616 g_warning ("Failed to set property %s.%s to %s: %s",
617 g_type_name (object_type), prop->pspec->name, prop->text->str,
618 error->message);
619 g_error_free (error);
620 error = NULL;
621 continue;
622 }
623
624 /* At this point, property_value has been set, and we need to either
625 * copy it to one of the two arrays, or unset it.
626 */
627 g_assert (G_IS_VALUE (&property_value));
628 object_properties_add (self: params, name: property_name, value: &property_value);
629 prop->applied = TRUE;
630 }
631}
632
633static const char *
634object_get_id (GObject *object)
635{
636 if (GTK_IS_BUILDABLE (object))
637 return gtk_buildable_get_buildable_id (GTK_BUILDABLE (object));
638 else
639 return g_object_get_data (object, key: "gtk-builder-id");
640}
641
642static GObject *
643gtk_builder_get_internal_child (GtkBuilder *builder,
644 ObjectInfo *info,
645 const char *childname,
646 GError **error)
647{
648 GObject *obj = NULL;
649
650 while (!obj)
651 {
652 if (!info->parent)
653 break;
654
655 info = (ObjectInfo*)((ChildInfo*)info->parent)->parent;
656 if (!info)
657 break;
658
659 GTK_NOTE (BUILDER,
660 g_message ("Trying to get internal child %s from %s",
661 childname, object_get_id (info->object)));
662
663 if (GTK_IS_BUILDABLE (info->object))
664 obj = gtk_buildable_get_internal_child (GTK_BUILDABLE (info->object),
665 builder,
666 childname);
667 };
668
669 if (!obj)
670 {
671 g_set_error (err: error,
672 GTK_BUILDER_ERROR,
673 code: GTK_BUILDER_ERROR_INVALID_VALUE,
674 format: "Unknown internal child: %s", childname);
675 }
676 return obj;
677}
678
679static inline void
680object_set_id (GObject *object,
681 const char *id)
682{
683 if (GTK_IS_BUILDABLE (object))
684 gtk_buildable_set_buildable_id (GTK_BUILDABLE (object), id);
685 else
686 g_object_set_data_full (object, key: "gtk-builder-id", data: g_strdup (str: id), destroy: g_free);
687}
688
689void
690_gtk_builder_add_object (GtkBuilder *builder,
691 const char *id,
692 GObject *object)
693{
694 GtkBuilderPrivate *priv = gtk_builder_get_instance_private (self: builder);
695
696 object_set_id (object, id);
697 g_hash_table_insert (hash_table: priv->objects, key: g_strdup (str: id), g_object_ref (object));
698}
699
700void
701gtk_builder_take_bindings (GtkBuilder *builder,
702 GObject *target,
703 GSList *bindings)
704{
705 GtkBuilderPrivate *priv = gtk_builder_get_instance_private (self: builder);
706 GSList *l;
707
708 for (l = bindings; l; l = l->next)
709 {
710 CommonInfo *common_info = l->data;
711
712 if (common_info->tag_type == TAG_BINDING)
713 {
714 BindingInfo *info = l->data;
715 info->target = target;
716 }
717 else if (common_info->tag_type == TAG_BINDING_EXPRESSION)
718 {
719 BindingExpressionInfo *info = l->data;
720 info->target = target;
721 }
722 else
723 {
724 g_assert_not_reached ();
725 }
726 }
727
728 priv->bindings = g_slist_concat (list1: priv->bindings, list2: bindings);
729}
730
731static void
732ensure_special_construct_parameters (GtkBuilder *builder,
733 GType object_type,
734 ObjectProperties *construct_parameters)
735{
736 GtkBuilderPrivate *priv = gtk_builder_get_instance_private (self: builder);
737 GValue value = G_VALUE_INIT;
738
739 if (g_type_is_a (type: object_type, GTK_TYPE_BUILDER_LIST_ITEM_FACTORY))
740 {
741 g_value_init (value: &value, GTK_TYPE_BUILDER_SCOPE);
742 g_value_set_object (value: &value, v_object: priv->scope);
743 object_properties_add (self: construct_parameters, name: "scope", value: &value);
744 }
745}
746
747GObject *
748_gtk_builder_construct (GtkBuilder *builder,
749 ObjectInfo *info,
750 GError **error)
751{
752 GtkBuilderPrivate *priv = gtk_builder_get_instance_private (self: builder);
753 ObjectProperties parameters, construct_parameters;
754 GObject *obj;
755 int i;
756 GParamFlags param_filter_flags;
757
758 g_assert (info->type != G_TYPE_INVALID);
759
760 if (priv->template_type != 0 &&
761 g_type_is_a (type: info->type, is_a_type: priv->template_type))
762 {
763 g_set_error (err: error,
764 GTK_BUILDER_ERROR,
765 code: GTK_BUILDER_ERROR_OBJECT_TYPE_REFUSED,
766 format: "Refused to build object of type '%s' because it "
767 "conforms to the template type '%s', avoiding infinite recursion.",
768 g_type_name (type: info->type), g_type_name (type: priv->template_type));
769 return NULL;
770 }
771
772 /* If there is a manual constructor (like UIManager), or if this is a
773 * reference to an internal child, then we filter out construct-only
774 * and warn that they cannot be set.
775 *
776 * Otherwise if we are calling g_object_new_with_properties(), we want
777 * to pass both G_PARAM_CONSTRUCT and G_PARAM_CONSTRUCT_ONLY to the
778 * object's constructor.
779 *
780 * Passing all construct properties to g_object_new_with_properties()
781 * slightly improves performance as the construct properties will only
782 * be set once.
783 */
784 if (info->constructor ||
785 (info->parent &&
786 info->parent->tag_type == TAG_CHILD &&
787 ((ChildInfo*)info->parent)->internal_child != NULL))
788 param_filter_flags = G_PARAM_CONSTRUCT_ONLY;
789 else
790 param_filter_flags = G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY;
791
792 object_properties_init (self: &parameters);
793 object_properties_init (self: &construct_parameters);
794
795 gtk_builder_get_parameters (builder, object_type: info->type,
796 object_name: info->id,
797 properties: info->properties,
798 filter_flags: param_filter_flags,
799 parameters: &parameters,
800 filtered_parameters: &construct_parameters);
801
802 if (info->constructor)
803 {
804 GObject *constructor;
805
806 constructor = g_hash_table_lookup (hash_table: priv->objects, key: info->constructor);
807 if (constructor == NULL)
808 {
809 g_set_error (err: error,
810 GTK_BUILDER_ERROR,
811 code: GTK_BUILDER_ERROR_INVALID_VALUE,
812 format: "Unknown object constructor for %s: %s",
813 info->id,
814 info->constructor);
815 object_properties_destroy (self: &parameters);
816 object_properties_destroy (self: &construct_parameters);
817 return NULL;
818 }
819 obj = gtk_buildable_construct_child (GTK_BUILDABLE (constructor),
820 builder,
821 name: info->id);
822 g_assert (obj != NULL);
823 if (construct_parameters.names->len > 0)
824 g_warning ("Can't pass in construct-only parameters to %s", info->id);
825 }
826 else if (info->parent &&
827 info->parent->tag_type == TAG_CHILD &&
828 ((ChildInfo*)info->parent)->internal_child != NULL)
829 {
830 char *childname = ((ChildInfo*)info->parent)->internal_child;
831 obj = gtk_builder_get_internal_child (builder, info, childname, error);
832 if (!obj)
833 {
834 object_properties_destroy (self: &parameters);
835 object_properties_destroy (self: &construct_parameters);
836 return NULL;
837 }
838 if (construct_parameters.names)
839 g_warning ("Can't pass in construct-only parameters to %s", childname);
840 g_object_ref (obj);
841 }
842 else
843 {
844 ensure_special_construct_parameters (builder, object_type: info->type, construct_parameters: &construct_parameters);
845
846 if (construct_parameters.names)
847 obj = g_object_new_with_properties (object_type: info->type,
848 n_properties: construct_parameters.names->len,
849 names: (const char **) construct_parameters.names->pdata,
850 values: (GValue *) construct_parameters.values->data);
851 else
852 obj = g_object_new (object_type: info->type, NULL);
853
854 /* No matter what, make sure we have a reference.
855 *
856 * If it's an initially unowned object, sink it.
857 * If it's not initially unowned then we have the reference already.
858 *
859 * In the case that this is a window it will be sunk already and
860 * this is effectively a call to g_object_ref(). That's what
861 * we want.
862 */
863 if (G_IS_INITIALLY_UNOWNED (obj))
864 g_object_ref_sink (obj);
865
866 GTK_NOTE (BUILDER,
867 g_message ("created %s of type %s", info->id, g_type_name (info->type)));
868 }
869 object_properties_destroy (self: &construct_parameters);
870
871 if (parameters.names)
872 {
873 GtkBuildableIface *iface = NULL;
874 gboolean custom_set_property = FALSE;
875 GtkBuildable *buildable = NULL;
876
877 if (GTK_IS_BUILDABLE (obj))
878 {
879 buildable = GTK_BUILDABLE (obj);
880 iface = GTK_BUILDABLE_GET_IFACE (obj);
881 if (iface->set_buildable_property)
882 custom_set_property = TRUE;
883 }
884
885 if (custom_set_property)
886 {
887 for (i = 0; i < parameters.names->len; i++)
888 {
889 const char *name = object_properties_get_name (self: &parameters, idx: i);
890 const GValue *value = object_properties_get_value (self: &parameters, idx: i);
891
892 iface->set_buildable_property (buildable, builder, name, value);
893#ifdef G_ENABLE_DEBUG
894 if (GTK_DEBUG_CHECK (BUILDER))
895 {
896 char *str = g_strdup_value_contents (value);
897 g_message ("set %s: %s = %s", info->id, name, str);
898 g_free (mem: str);
899 }
900#endif
901 }
902 }
903 else
904 {
905 g_object_setv (object: obj,
906 n_properties: parameters.names->len,
907 names: (const char **) parameters.names->pdata,
908 values: (GValue *) parameters.values->data);
909#ifdef G_ENABLE_DEBUG
910 if (GTK_DEBUG_CHECK (BUILDER))
911 {
912 for (i = 0; i < parameters.names->len; i++)
913 {
914 const char *name = object_properties_get_name (self: &parameters, idx: i);
915 const GValue *value = object_properties_get_value (self: &parameters, idx: i);
916 char *str = g_strdup_value_contents (value);
917 g_message ("set %s: %s = %s", info->id, name, str);
918 g_free (mem: str);
919 }
920 }
921#endif
922 }
923 }
924
925 object_properties_destroy (self: &parameters);
926
927 /* put it in the hash table. */
928 _gtk_builder_add_object (builder, id: info->id, object: obj);
929
930 /* we already own a reference to obj. */
931 g_object_unref (object: obj);
932
933 return obj;
934}
935
936void
937_gtk_builder_apply_properties (GtkBuilder *builder,
938 ObjectInfo *info,
939 GError **error)
940{
941 ObjectProperties parameters;
942
943 g_assert (info->object != NULL);
944 g_assert (info->type != G_TYPE_INVALID);
945
946 object_properties_init (self: &parameters);
947
948 /* Fetch all properties that are not construct-only */
949 gtk_builder_get_parameters (builder, object_type: info->type,
950 object_name: info->id,
951 properties: info->properties,
952 filter_flags: G_PARAM_CONSTRUCT_ONLY,
953 parameters: &parameters, NULL);
954
955 if (parameters.names)
956 {
957 GtkBuildableIface *iface = NULL;
958 GtkBuildable *buildable = NULL;
959 gboolean custom_set_property = FALSE;
960 int i;
961
962 if (GTK_IS_BUILDABLE (info->object))
963 {
964 buildable = GTK_BUILDABLE (info->object);
965 iface = GTK_BUILDABLE_GET_IFACE (info->object);
966 if (iface->set_buildable_property)
967 custom_set_property = TRUE;
968 }
969
970 if (custom_set_property)
971 {
972 for (i = 0; i < parameters.names->len; i++)
973 {
974 const char *name = object_properties_get_name (self: &parameters, idx: i);
975 const GValue *value = object_properties_get_value (self: &parameters, idx: i);
976 iface->set_buildable_property (buildable, builder, name, value);
977#ifdef G_ENABLE_DEBUG
978 if (GTK_DEBUG_CHECK (BUILDER))
979 {
980 char *str = g_strdup_value_contents (value);
981 g_message ("set %s: %s = %s", info->id, name, str);
982 g_free (mem: str);
983 }
984#endif
985 }
986 }
987 else
988 {
989 g_object_setv (object: info->object,
990 n_properties: parameters.names->len,
991 names: (const char **) parameters.names->pdata,
992 values: (GValue *) parameters.values->data);
993#ifdef G_ENABLE_DEBUG
994 if (GTK_DEBUG_CHECK (BUILDER))
995 {
996 for (i = 0; i < parameters.names->len; i++)
997 {
998 const char *name = object_properties_get_name (self: &parameters, idx: i);
999 const GValue *value = object_properties_get_value (self: &parameters, idx: i);
1000 char *str = g_strdup_value_contents (value);
1001 g_message ("set %s: %s = %s", info->id, name, str);
1002 g_free (mem: str);
1003 }
1004 }
1005#endif
1006 }
1007 }
1008
1009 object_properties_destroy (self: &parameters);
1010}
1011
1012void
1013_gtk_builder_add (GtkBuilder *builder,
1014 ChildInfo *child_info)
1015{
1016 GObject *object;
1017 GObject *parent;
1018
1019 /* Internal children are already added
1020 * Also prevent us from being called twice.
1021 */
1022 if (!child_info ||
1023 child_info->internal_child ||
1024 child_info->added)
1025 return;
1026
1027 object = child_info->object;
1028 if (!object)
1029 return;
1030
1031 if (!child_info->parent)
1032 {
1033 g_warning ("%s: Not adding, No parent", object_get_id (object));
1034 return;
1035 }
1036
1037 g_assert (object != NULL);
1038
1039 parent = ((ObjectInfo*)child_info->parent)->object;
1040
1041 GTK_NOTE (BUILDER,
1042 g_message ("adding %s to %s", object_get_id (object), object_get_id (parent)));
1043
1044 if (G_IS_LIST_STORE (ptr: parent))
1045 {
1046 if (child_info->type != NULL)
1047 {
1048 GTK_BUILDER_WARN_INVALID_CHILD_TYPE (parent, child_info->type);
1049 }
1050 else
1051 {
1052 g_list_store_append (store: G_LIST_STORE (ptr: parent), item: object);
1053 }
1054 }
1055 else
1056 {
1057 g_assert (GTK_IS_BUILDABLE (parent));
1058 gtk_buildable_add_child (GTK_BUILDABLE (parent), builder, child: object,
1059 type: child_info->type);
1060 }
1061
1062 child_info->added = TRUE;
1063}
1064
1065void
1066_gtk_builder_add_signals (GtkBuilder *builder,
1067 GPtrArray *signals)
1068{
1069 GtkBuilderPrivate *priv = gtk_builder_get_instance_private (self: builder);
1070
1071 if (G_UNLIKELY (!priv->signals))
1072 priv->signals = g_ptr_array_new_with_free_func (element_free_func: (GDestroyNotify)_free_signal_info);
1073
1074 g_ptr_array_extend_and_steal (array_to_extend: priv->signals, array: signals);
1075}
1076
1077static gboolean
1078gtk_builder_apply_delayed_properties (GtkBuilder *builder,
1079 GError **error)
1080{
1081 GtkBuilderPrivate *priv = gtk_builder_get_instance_private (self: builder);
1082 GSList *l, *props;
1083 gboolean result = TRUE;
1084
1085 /* take the list over from the builder->priv.
1086 *
1087 * g_slist_reverse does not copy the list, so the list now
1088 * belongs to us (and we free it at the end of this function).
1089 */
1090 props = g_slist_reverse (list: priv->delayed_properties);
1091 priv->delayed_properties = NULL;
1092
1093 for (l = props; l; l = l->next)
1094 {
1095 DelayedProperty *property = l->data;
1096 GObject *object, *obj;
1097
1098 if (result)
1099 {
1100 object = g_hash_table_lookup (hash_table: priv->objects, key: property->object);
1101 g_assert (object != NULL);
1102
1103 obj = gtk_builder_lookup_object (builder, name: property->value, line: property->line, col: property->col, error);
1104 if (obj)
1105 g_object_set (object, first_property_name: property->pspec->name, obj, NULL);
1106 else
1107 result = FALSE;
1108 }
1109
1110 g_free (mem: property->value);
1111 g_free (mem: property->object);
1112 g_slice_free (DelayedProperty, property);
1113 }
1114 g_slist_free (list: props);
1115
1116 return result;
1117}
1118
1119static inline gboolean
1120gtk_builder_create_bindings (GtkBuilder *builder,
1121 GError **error)
1122{
1123 GtkBuilderPrivate *priv = gtk_builder_get_instance_private (self: builder);
1124 GSList *l;
1125 gboolean result = TRUE;
1126
1127 for (l = priv->bindings; l; l = l->next)
1128 {
1129 CommonInfo *common_info = l->data;
1130
1131 if (common_info->tag_type == TAG_BINDING)
1132 {
1133 BindingInfo *info = l->data;
1134 GObject *source;
1135
1136 source = gtk_builder_lookup_object (builder, name: info->source, line: info->line, col: info->col, error);
1137 if (source)
1138 g_object_bind_property (source, source_property: info->source_property,
1139 target: info->target, target_property: info->target_pspec->name,
1140 flags: info->flags);
1141 else
1142 error = NULL;
1143
1144 _free_binding_info (info, NULL);
1145 }
1146 else if (common_info->tag_type == TAG_BINDING_EXPRESSION)
1147 {
1148 BindingExpressionInfo *info = l->data;
1149 GtkExpression *expression;
1150 GObject *object;
1151
1152 if (info->object_name)
1153 {
1154 object = gtk_builder_lookup_object (builder, name: info->object_name, line: info->line, col: info->col, error);
1155 if (object == NULL)
1156 {
1157 error = NULL;
1158 result = FALSE;
1159 }
1160 }
1161 else if (priv->current_object)
1162 {
1163 object = priv->current_object;
1164 }
1165 else
1166 {
1167 object = info->target;
1168 }
1169
1170 if (object)
1171 {
1172 expression = expression_info_construct (builder, info: info->expr, error);
1173 if (expression == NULL)
1174 {
1175 g_prefix_error (err: error, format: "%s:%d:%d: ", priv->filename, info->line, info->col);
1176 error = NULL;
1177 result = FALSE;
1178 }
1179 else
1180 {
1181 gtk_expression_bind (self: expression, target: info->target, property: info->target_pspec->name, this_: object);
1182 }
1183 }
1184
1185 free_binding_expression_info (info);
1186 }
1187 else
1188 g_assert_not_reached ();
1189 }
1190
1191 g_slist_free (list: priv->bindings);
1192 priv->bindings = NULL;
1193 return result;
1194}
1195
1196/**
1197 * gtk_builder_new:
1198 *
1199 * Creates a new empty builder object.
1200 *
1201 * This function is only useful if you intend to make multiple calls
1202 * to [method@Gtk.Builder.add_from_file], [method@Gtk.Builder.add_from_resource]
1203 * or [method@Gtk.Builder.add_from_string] in order to merge multiple UI
1204 * descriptions into a single builder.
1205 *
1206 * Returns: a new (empty) `GtkBuilder` object
1207 */
1208GtkBuilder *
1209gtk_builder_new (void)
1210{
1211 return g_object_new (GTK_TYPE_BUILDER, NULL);
1212}
1213
1214/**
1215 * gtk_builder_add_from_file:
1216 * @builder: a `GtkBuilder`
1217 * @filename: (type filename): the name of the file to parse
1218 * @error: (nullable): return location for an error
1219 *
1220 * Parses a file containing a UI definition and merges it with
1221 * the current contents of @builder.
1222 *
1223 * This function is useful if you need to call
1224 * [method@Gtk.Builder.set_current_object]) to add user data to
1225 * callbacks before loading GtkBuilder UI. Otherwise, you probably
1226 * want [ctor@Gtk.Builder.new_from_file] instead.
1227 *
1228 * If an error occurs, 0 will be returned and @error will be assigned a
1229 * `GError` from the `GTK_BUILDER_ERROR`, `G_MARKUP_ERROR` or `G_FILE_ERROR`
1230 * domains.
1231 *
1232 * It’s not really reasonable to attempt to handle failures of this
1233 * call. You should not use this function with untrusted files (ie:
1234 * files that are not part of your application). Broken `GtkBuilder`
1235 * files can easily crash your program, and it’s possible that memory
1236 * was leaked leading up to the reported failure. The only reasonable
1237 * thing to do when an error is detected is to call `g_error()`.
1238 *
1239 * Returns: %TRUE on success, %FALSE if an error occurred
1240 */
1241gboolean
1242gtk_builder_add_from_file (GtkBuilder *builder,
1243 const char *filename,
1244 GError **error)
1245{
1246 GtkBuilderPrivate *priv = gtk_builder_get_instance_private (self: builder);
1247 char *buffer;
1248 gsize length;
1249 GError *tmp_error;
1250
1251 g_return_val_if_fail (GTK_IS_BUILDER (builder), 0);
1252 g_return_val_if_fail (filename != NULL, 0);
1253 g_return_val_if_fail (error == NULL || *error == NULL, 0);
1254
1255 tmp_error = NULL;
1256
1257 if (!g_file_get_contents (filename, contents: &buffer, length: &length, error: &tmp_error))
1258 {
1259 g_propagate_error (dest: error, src: tmp_error);
1260 return FALSE;
1261 }
1262
1263 g_free (mem: priv->filename);
1264 g_free (mem: priv->resource_prefix);
1265 priv->filename = g_strdup (str: filename);
1266 priv->resource_prefix = NULL;
1267
1268 _gtk_builder_parser_parse_buffer (builder, filename,
1269 buffer, length: (gssize)length,
1270 NULL,
1271 error: &tmp_error);
1272
1273 g_free (mem: buffer);
1274
1275 if (tmp_error != NULL)
1276 {
1277 g_propagate_error (dest: error, src: tmp_error);
1278 return FALSE;
1279 }
1280
1281 return TRUE;
1282}
1283
1284/**
1285 * gtk_builder_add_objects_from_file:
1286 * @builder: a `GtkBuilder`
1287 * @filename: (type filename): the name of the file to parse
1288 * @object_ids: (array zero-terminated=1) (element-type utf8): nul-terminated array of objects to build
1289 * @error: (nullable): return location for an error
1290 *
1291 * Parses a file containing a UI definition building only the
1292 * requested objects and merges them with the current contents
1293 * of @builder.
1294 *
1295 * Upon errors, 0 will be returned and @error will be assigned a
1296 * `GError` from the %GTK_BUILDER_ERROR, %G_MARKUP_ERROR or %G_FILE_ERROR
1297 * domain.
1298 *
1299 * If you are adding an object that depends on an object that is not
1300 * its child (for instance a `GtkTreeView` that depends on its
1301 * `GtkTreeModel`), you have to explicitly list all of them in @object_ids.
1302 *
1303 * Returns: %TRUE on success, %FALSE if an error occurred
1304 */
1305gboolean
1306gtk_builder_add_objects_from_file (GtkBuilder *builder,
1307 const char *filename,
1308 const char **object_ids,
1309 GError **error)
1310{
1311 GtkBuilderPrivate *priv = gtk_builder_get_instance_private (self: builder);
1312 char *buffer;
1313 gsize length;
1314 GError *tmp_error;
1315
1316 g_return_val_if_fail (GTK_IS_BUILDER (builder), 0);
1317 g_return_val_if_fail (filename != NULL, 0);
1318 g_return_val_if_fail (object_ids != NULL && object_ids[0] != NULL, 0);
1319 g_return_val_if_fail (error == NULL || *error == NULL, 0);
1320
1321 tmp_error = NULL;
1322
1323 if (!g_file_get_contents (filename, contents: &buffer, length: &length, error: &tmp_error))
1324 {
1325 g_propagate_error (dest: error, src: tmp_error);
1326 return 0;
1327 }
1328
1329 g_free (mem: priv->filename);
1330 g_free (mem: priv->resource_prefix);
1331 priv->filename = g_strdup (str: filename);
1332 priv->resource_prefix = NULL;
1333
1334 _gtk_builder_parser_parse_buffer (builder, filename,
1335 buffer, length: (gssize)length,
1336 requested_objs: object_ids,
1337 error: &tmp_error);
1338
1339 g_free (mem: buffer);
1340
1341 if (tmp_error != NULL)
1342 {
1343 g_propagate_error (dest: error, src: tmp_error);
1344 return FALSE;
1345 }
1346
1347 return TRUE;
1348}
1349
1350/**
1351 * gtk_builder_extend_with_template:
1352 * @builder: a `GtkBuilder`
1353 * @object: the object that is being extended
1354 * @template_type: the type that the template is for
1355 * @buffer: the string to parse
1356 * @length: the length of @buffer (may be -1 if @buffer is nul-terminated)
1357 * @error: (nullable): return location for an error
1358 *
1359 * Main private entry point for building composite components
1360 * from template XML.
1361 *
1362 * This is exported purely to let `gtk-builder-tool` validate
1363 * templates, applications have no need to call this function.
1364 *
1365 * Returns: A positive value on success, 0 if an error occurred
1366 */
1367gboolean
1368gtk_builder_extend_with_template (GtkBuilder *builder,
1369 GObject *object,
1370 GType template_type,
1371 const char *buffer,
1372 gssize length,
1373 GError **error)
1374{
1375 GtkBuilderPrivate *priv = gtk_builder_get_instance_private (self: builder);
1376 GError *tmp_error;
1377 char *filename;
1378
1379 g_return_val_if_fail (GTK_IS_BUILDER (builder), 0);
1380 g_return_val_if_fail (G_IS_OBJECT (object), 0);
1381 g_return_val_if_fail (g_type_name (template_type) != NULL, 0);
1382 g_return_val_if_fail (g_type_is_a (G_OBJECT_TYPE (object), template_type), 0);
1383 g_return_val_if_fail (buffer && buffer[0], 0);
1384
1385 tmp_error = NULL;
1386
1387 g_free (mem: priv->filename);
1388 g_free (mem: priv->resource_prefix);
1389 priv->filename = g_strdup (str: ".");
1390 priv->resource_prefix = NULL;
1391 priv->template_type = template_type;
1392
1393 filename = g_strconcat (string1: "<", g_type_name (type: template_type), " template>", NULL);
1394 gtk_builder_expose_object (builder, name: g_type_name (type: template_type), object);
1395 _gtk_builder_parser_parse_buffer (builder, filename,
1396 buffer, length,
1397 NULL,
1398 error: &tmp_error);
1399 g_free (mem: filename);
1400
1401 if (tmp_error != NULL)
1402 {
1403 g_propagate_error (dest: error, src: tmp_error);
1404 return FALSE;
1405 }
1406
1407 return TRUE;
1408}
1409
1410/**
1411 * gtk_builder_add_from_resource:
1412 * @builder: a `GtkBuilder`
1413 * @resource_path: the path of the resource file to parse
1414 * @error: (nullable): return location for an erro
1415 *
1416 * Parses a resource file containing a UI definition
1417 * and merges it with the current contents of @builder.
1418 *
1419 * This function is useful if you need to call
1420 * [method@Gtk.Builder.set_current_object] to add user data to
1421 * callbacks before loading GtkBuilder UI. Otherwise, you probably
1422 * want [ctor@Gtk.Builder.new_from_resource] instead.
1423 *
1424 * If an error occurs, 0 will be returned and @error will be assigned a
1425 * `GError` from the %GTK_BUILDER_ERROR, %G_MARKUP_ERROR or %G_RESOURCE_ERROR
1426 * domain.
1427 *
1428 * It’s not really reasonable to attempt to handle failures of this
1429 * call. The only reasonable thing to do when an error is detected is
1430 * to call g_error().
1431 *
1432 * Returns: %TRUE on success, %FALSE if an error occurred
1433 */
1434gboolean
1435gtk_builder_add_from_resource (GtkBuilder *builder,
1436 const char *resource_path,
1437 GError **error)
1438{
1439 GtkBuilderPrivate *priv = gtk_builder_get_instance_private (self: builder);
1440 GError *tmp_error;
1441 GBytes *data;
1442 char *filename_for_errors;
1443 char *slash;
1444
1445 g_return_val_if_fail (GTK_IS_BUILDER (builder), 0);
1446 g_return_val_if_fail (resource_path != NULL, 0);
1447 g_return_val_if_fail (error == NULL || *error == NULL, 0);
1448
1449 tmp_error = NULL;
1450
1451 data = g_resources_lookup_data (path: resource_path, lookup_flags: 0, error: &tmp_error);
1452 if (data == NULL)
1453 {
1454 g_propagate_error (dest: error, src: tmp_error);
1455 return 0;
1456 }
1457
1458 g_free (mem: priv->filename);
1459 g_free (mem: priv->resource_prefix);
1460 priv->filename = g_strdup (str: ".");
1461
1462 slash = strrchr (s: resource_path, c: '/');
1463 if (slash != NULL)
1464 priv->resource_prefix = g_strndup (str: resource_path, n: slash - resource_path + 1);
1465 else
1466 priv->resource_prefix = g_strdup (str: "/");
1467
1468 filename_for_errors = g_strconcat (string1: "<resource>", resource_path, NULL);
1469
1470 _gtk_builder_parser_parse_buffer (builder, filename: filename_for_errors,
1471 buffer: g_bytes_get_data (bytes: data, NULL), length: g_bytes_get_size (bytes: data),
1472 NULL,
1473 error: &tmp_error);
1474
1475 g_free (mem: filename_for_errors);
1476 g_bytes_unref (bytes: data);
1477
1478 if (tmp_error != NULL)
1479 {
1480 g_propagate_error (dest: error, src: tmp_error);
1481 return FALSE;
1482 }
1483
1484 return TRUE;
1485}
1486
1487/**
1488 * gtk_builder_add_objects_from_resource:
1489 * @builder: a `GtkBuilder`
1490 * @resource_path: the path of the resource file to parse
1491 * @object_ids: (array zero-terminated=1) (element-type utf8): nul-terminated array of objects to build
1492 * @error: (nullable): return location for an error
1493 *
1494 * Parses a resource file containing a UI definition, building
1495 * only the requested objects and merges them with the current
1496 * contents of @builder.
1497 *
1498 * Upon errors, 0 will be returned and @error will be assigned a
1499 * `GError` from the %GTK_BUILDER_ERROR, %G_MARKUP_ERROR or %G_RESOURCE_ERROR
1500 * domain.
1501 *
1502 * If you are adding an object that depends on an object that is not
1503 * its child (for instance a `GtkTreeView` that depends on its
1504 * `GtkTreeModel`), you have to explicitly list all of them in @object_ids.
1505 *
1506 * Returns: %TRUE on success, %FALSE if an error occurred
1507 */
1508gboolean
1509gtk_builder_add_objects_from_resource (GtkBuilder *builder,
1510 const char *resource_path,
1511 const char **object_ids,
1512 GError **error)
1513{
1514 GtkBuilderPrivate *priv = gtk_builder_get_instance_private (self: builder);
1515 GError *tmp_error;
1516 GBytes *data;
1517 char *filename_for_errors;
1518 char *slash;
1519
1520 g_return_val_if_fail (GTK_IS_BUILDER (builder), 0);
1521 g_return_val_if_fail (resource_path != NULL, 0);
1522 g_return_val_if_fail (object_ids != NULL && object_ids[0] != NULL, 0);
1523 g_return_val_if_fail (error == NULL || *error == NULL, 0);
1524
1525 tmp_error = NULL;
1526
1527 data = g_resources_lookup_data (path: resource_path, lookup_flags: 0, error: &tmp_error);
1528 if (data == NULL)
1529 {
1530 g_propagate_error (dest: error, src: tmp_error);
1531 return FALSE;
1532 }
1533
1534 g_free (mem: priv->filename);
1535 g_free (mem: priv->resource_prefix);
1536 priv->filename = g_strdup (str: ".");
1537
1538 slash = strrchr (s: resource_path, c: '/');
1539 if (slash != NULL)
1540 priv->resource_prefix = g_strndup (str: resource_path, n: slash - resource_path + 1);
1541 else
1542 priv->resource_prefix = g_strdup (str: "/");
1543
1544 filename_for_errors = g_strconcat (string1: "<resource>", resource_path, NULL);
1545
1546 _gtk_builder_parser_parse_buffer (builder, filename: filename_for_errors,
1547 buffer: g_bytes_get_data (bytes: data, NULL), length: g_bytes_get_size (bytes: data),
1548 requested_objs: object_ids,
1549 error: &tmp_error);
1550 g_free (mem: filename_for_errors);
1551 g_bytes_unref (bytes: data);
1552
1553 if (tmp_error != NULL)
1554 {
1555 g_propagate_error (dest: error, src: tmp_error);
1556 return FALSE;
1557 }
1558
1559 return TRUE;
1560}
1561
1562/**
1563 * gtk_builder_add_from_string:
1564 * @builder: a `GtkBuilder`
1565 * @buffer: the string to parse
1566 * @length: the length of @buffer (may be -1 if @buffer is nul-terminated)
1567 * @error: (nullable): return location for an error
1568 *
1569 * Parses a string containing a UI definition and merges it
1570 * with the current contents of @builder.
1571 *
1572 * This function is useful if you need to call
1573 * [method@Gtk.Builder.set_current_object] to add user data to
1574 * callbacks before loading `GtkBuilder` UI. Otherwise, you probably
1575 * want [ctor@Gtk.Builder.new_from_string] instead.
1576 *
1577 * Upon errors %FALSE will be returned and @error will be assigned a
1578 * `GError` from the %GTK_BUILDER_ERROR, %G_MARKUP_ERROR or
1579 * %G_VARIANT_PARSE_ERROR domain.
1580 *
1581 * It’s not really reasonable to attempt to handle failures of this
1582 * call. The only reasonable thing to do when an error is detected is
1583 * to call g_error().
1584 *
1585 * Returns: %TRUE on success, %FALSE if an error occurred
1586 */
1587gboolean
1588gtk_builder_add_from_string (GtkBuilder *builder,
1589 const char *buffer,
1590 gssize length,
1591 GError **error)
1592{
1593 GtkBuilderPrivate *priv = gtk_builder_get_instance_private (self: builder);
1594 GError *tmp_error;
1595
1596 g_return_val_if_fail (GTK_IS_BUILDER (builder), 0);
1597 g_return_val_if_fail (buffer != NULL, 0);
1598 g_return_val_if_fail (error == NULL || *error == NULL, 0);
1599
1600 tmp_error = NULL;
1601
1602 g_free (mem: priv->filename);
1603 g_free (mem: priv->resource_prefix);
1604 priv->filename = g_strdup (str: ".");
1605 priv->resource_prefix = NULL;
1606
1607 _gtk_builder_parser_parse_buffer (builder, filename: "<input>",
1608 buffer, length,
1609 NULL,
1610 error: &tmp_error);
1611 if (tmp_error != NULL)
1612 {
1613 g_propagate_error (dest: error, src: tmp_error);
1614 return FALSE;
1615 }
1616
1617 return TRUE;
1618}
1619
1620/**
1621 * gtk_builder_add_objects_from_string:
1622 * @builder: a `GtkBuilder`
1623 * @buffer: the string to parse
1624 * @length: the length of @buffer (may be -1 if @buffer is nul-terminated)
1625 * @object_ids: (array zero-terminated=1) (element-type utf8): nul-terminated array of objects to build
1626 * @error: (nullable): return location for an error
1627 *
1628 * Parses a string containing a UI definition, building only the
1629 * requested objects and merges them with the current contents of
1630 * @builder.
1631 *
1632 * Upon errors %FALSE will be returned and @error will be assigned a
1633 * `GError` from the %GTK_BUILDER_ERROR or %G_MARKUP_ERROR domain.
1634 *
1635 * If you are adding an object that depends on an object that is not
1636 * its child (for instance a `GtkTreeView` that depends on its
1637 * `GtkTreeModel`), you have to explicitly list all of them in @object_ids.
1638 *
1639 * Returns: %TRUE on success, %FALSE if an error occurred
1640 */
1641gboolean
1642gtk_builder_add_objects_from_string (GtkBuilder *builder,
1643 const char *buffer,
1644 gssize length,
1645 const char **object_ids,
1646 GError **error)
1647{
1648 GtkBuilderPrivate *priv = gtk_builder_get_instance_private (self: builder);
1649 GError *tmp_error;
1650
1651 g_return_val_if_fail (GTK_IS_BUILDER (builder), 0);
1652 g_return_val_if_fail (buffer != NULL, 0);
1653 g_return_val_if_fail (object_ids != NULL && object_ids[0] != NULL, 0);
1654 g_return_val_if_fail (error == NULL || *error == NULL, 0);
1655
1656 tmp_error = NULL;
1657
1658 g_free (mem: priv->filename);
1659 g_free (mem: priv->resource_prefix);
1660 priv->filename = g_strdup (str: ".");
1661 priv->resource_prefix = NULL;
1662
1663 _gtk_builder_parser_parse_buffer (builder, filename: "<input>",
1664 buffer, length,
1665 requested_objs: object_ids,
1666 error: &tmp_error);
1667
1668 if (tmp_error != NULL)
1669 {
1670 g_propagate_error (dest: error, src: tmp_error);
1671 return FALSE;
1672 }
1673
1674 return TRUE;
1675}
1676
1677/**
1678 * gtk_builder_get_object:
1679 * @builder: a `GtkBuilder`
1680 * @name: name of object to get
1681 *
1682 * Gets the object named @name.
1683 *
1684 * Note that this function does not increment the reference count
1685 * of the returned object.
1686 *
1687 * Returns: (nullable) (transfer none): the object named @name
1688 */
1689GObject *
1690gtk_builder_get_object (GtkBuilder *builder,
1691 const char *name)
1692{
1693 GtkBuilderPrivate *priv = gtk_builder_get_instance_private (self: builder);
1694
1695 g_return_val_if_fail (GTK_IS_BUILDER (builder), NULL);
1696 g_return_val_if_fail (name != NULL, NULL);
1697
1698 return g_hash_table_lookup (hash_table: priv->objects, key: name);
1699}
1700
1701/**
1702 * gtk_builder_get_objects:
1703 * @builder: a `GtkBuilder`
1704 *
1705 * Gets all objects that have been constructed by @builder.
1706 *
1707 * Note that this function does not increment the reference
1708 * counts of the returned objects.
1709 *
1710 * Returns: (element-type GObject) (transfer container): a
1711 * newly-allocated `GSList` containing all the objects
1712 * constructed by the `GtkBuilder instance`. It should be
1713 * freed by g_slist_free()
1714 */
1715GSList *
1716gtk_builder_get_objects (GtkBuilder *builder)
1717{
1718 GtkBuilderPrivate *priv = gtk_builder_get_instance_private (self: builder);
1719 GSList *objects = NULL;
1720 GObject *object;
1721 GHashTableIter iter;
1722
1723 g_return_val_if_fail (GTK_IS_BUILDER (builder), NULL);
1724
1725 g_hash_table_iter_init (iter: &iter, hash_table: priv->objects);
1726 while (g_hash_table_iter_next (iter: &iter, NULL, value: (gpointer *)&object))
1727 objects = g_slist_prepend (list: objects, data: object);
1728
1729 return g_slist_reverse (list: objects);
1730}
1731
1732/**
1733 * gtk_builder_set_translation_domain: (attributes org.gtk.Method.set_property=translation-domain)
1734 * @builder: a `GtkBuilder`
1735 * @domain: (nullable): the translation domain
1736 *
1737 * Sets the translation domain of @builder.
1738 */
1739void
1740gtk_builder_set_translation_domain (GtkBuilder *builder,
1741 const char *domain)
1742{
1743 GtkBuilderPrivate *priv = gtk_builder_get_instance_private (self: builder);
1744 char *new_domain;
1745
1746 g_return_if_fail (GTK_IS_BUILDER (builder));
1747
1748 new_domain = g_strdup (str: domain);
1749 g_free (mem: priv->domain);
1750 priv->domain = new_domain;
1751
1752 g_object_notify_by_pspec (G_OBJECT (builder), pspec: builder_props[PROP_TRANSLATION_DOMAIN]);
1753}
1754
1755/**
1756 * gtk_builder_get_translation_domain: (attributes org.gtk.Method.get_property=translation-domain)
1757 * @builder: a `GtkBuilder`
1758 *
1759 * Gets the translation domain of @builder.
1760 *
1761 * Returns: (transfer none) (nullable): the translation domain
1762 */
1763const char *
1764gtk_builder_get_translation_domain (GtkBuilder *builder)
1765{
1766 GtkBuilderPrivate *priv = gtk_builder_get_instance_private (self: builder);
1767
1768 g_return_val_if_fail (GTK_IS_BUILDER (builder), NULL);
1769
1770 return priv->domain;
1771}
1772
1773/**
1774 * gtk_builder_expose_object:
1775 * @builder: a `GtkBuilder`
1776 * @name: the name of the object exposed to the builder
1777 * @object: the object to expose
1778 *
1779 * Add @object to the @builder object pool so it can be
1780 * referenced just like any other object built by builder.
1781 */
1782void
1783gtk_builder_expose_object (GtkBuilder *builder,
1784 const char *name,
1785 GObject *object)
1786{
1787 GtkBuilderPrivate *priv = gtk_builder_get_instance_private (self: builder);
1788
1789 g_return_if_fail (GTK_IS_BUILDER (builder));
1790 g_return_if_fail (name && name[0]);
1791 g_return_if_fail (!g_hash_table_contains (priv->objects, name));
1792
1793 object_set_id (object, id: name);
1794 g_hash_table_insert (hash_table: priv->objects,
1795 key: g_strdup (str: name),
1796 g_object_ref (object));
1797}
1798
1799/**
1800 * gtk_builder_get_current_object: (attributes org.gtk.Method.get_property=current-object)
1801 * @builder: a `GtkBuilder`
1802 *
1803 * Gets the current object set via gtk_builder_set_current_object().
1804 *
1805 * Returns: (nullable) (transfer none): the current object
1806 */
1807GObject *
1808gtk_builder_get_current_object (GtkBuilder *builder)
1809{
1810 GtkBuilderPrivate *priv = gtk_builder_get_instance_private (self: builder);
1811
1812 g_return_val_if_fail (GTK_IS_BUILDER (builder), NULL);
1813
1814 return priv->current_object;
1815}
1816
1817/**
1818 * gtk_builder_set_current_object: (attributes org.gtk.Method.set_property=current-object)
1819 * @builder: a `GtkBuilder`
1820 * @current_object: (nullable) (transfer none): the new current object
1821 *
1822 * Sets the current object for the @builder.
1823 *
1824 * The current object can be thought of as the `this` object that the
1825 * builder is working for and will often be used as the default object
1826 * when an object is optional.
1827 *
1828 * [method@Gtk.Widget.init_template] for example will set the current
1829 * object to the widget the template is inited for. For functions like
1830 * [ctor@Gtk.Builder.new_from_resource], the current object will be %NULL.
1831 */
1832void
1833gtk_builder_set_current_object (GtkBuilder *builder,
1834 GObject *current_object)
1835{
1836 GtkBuilderPrivate *priv = gtk_builder_get_instance_private (self: builder);
1837
1838 g_return_if_fail (GTK_IS_BUILDER (builder));
1839 g_return_if_fail (current_object || G_IS_OBJECT (current_object));
1840
1841 if (!g_set_object (&priv->current_object, current_object))
1842 return;
1843
1844 g_object_notify_by_pspec (G_OBJECT (builder), pspec: builder_props[PROP_CURRENT_OBJECT]);
1845}
1846
1847/**
1848 * gtk_builder_get_scope: (attributes org.gtk.Method.get_property=scope)
1849 * @builder: a `GtkBuilder`
1850 *
1851 * Gets the scope in use that was set via gtk_builder_set_scope().
1852 *
1853 * Returns: (transfer none): the current scope
1854 */
1855GtkBuilderScope *
1856gtk_builder_get_scope (GtkBuilder *builder)
1857{
1858 GtkBuilderPrivate *priv = gtk_builder_get_instance_private (self: builder);
1859
1860 g_return_val_if_fail (GTK_IS_BUILDER (builder), NULL);
1861
1862 return priv->scope;
1863}
1864
1865/**
1866 * gtk_builder_set_scope: (attributes org.gtk.Method.set_property=scope)
1867 * @builder: a `GtkBuilder`
1868 * @scope: (nullable) (transfer none): the scope to use
1869 *
1870 * Sets the scope the builder should operate in.
1871 *
1872 * If @scope is %NULL, a new [class@Gtk.BuilderCScope] will be created.
1873 */
1874void
1875gtk_builder_set_scope (GtkBuilder *builder,
1876 GtkBuilderScope *scope)
1877{
1878 GtkBuilderPrivate *priv = gtk_builder_get_instance_private (self: builder);
1879
1880 g_return_if_fail (GTK_IS_BUILDER (builder));
1881 g_return_if_fail (scope == NULL || GTK_IS_BUILDER_SCOPE (scope));
1882
1883 if (scope && priv->scope == scope)
1884 return;
1885
1886 g_clear_object (&priv->scope);
1887
1888 if (scope)
1889 priv->scope = g_object_ref (scope);
1890 else
1891 priv->scope = gtk_builder_cscope_new ();
1892
1893 g_object_notify_by_pspec (G_OBJECT (builder), pspec: builder_props[PROP_SCOPE]);
1894}
1895
1896static gboolean
1897gtk_builder_connect_signals (GtkBuilder *builder,
1898 GError **error)
1899{
1900 GtkBuilderPrivate *priv = gtk_builder_get_instance_private (self: builder);
1901 GObject *object;
1902 GObject *connect_object;
1903 gboolean result = TRUE;
1904
1905 if (!priv->signals ||
1906 priv->signals->len == 0)
1907 return TRUE;
1908
1909 for (guint i = 0; i < priv->signals->len; i++)
1910 {
1911 SignalInfo *signal = g_ptr_array_index (priv->signals, i);
1912 GClosure *closure;
1913
1914 g_assert (signal != NULL);
1915 g_assert (signal->id != 0);
1916
1917 object = g_hash_table_lookup (hash_table: priv->objects, key: signal->object_name);
1918 g_assert (object != NULL);
1919
1920 connect_object = NULL;
1921
1922 if (signal->connect_object_name)
1923 {
1924 connect_object = g_hash_table_lookup (hash_table: priv->objects,
1925 key: signal->connect_object_name);
1926 if (!connect_object)
1927 {
1928 g_set_error (err: error,
1929 GTK_BUILDER_ERROR, code: GTK_BUILDER_ERROR_INVALID_ID,
1930 format: "Could not lookup object %s on signal %s of object %s",
1931 signal->connect_object_name, g_signal_name (signal_id: signal->id),
1932 signal->object_name);
1933 break;
1934 }
1935 }
1936
1937 closure = gtk_builder_create_closure (builder,
1938 function_name: signal->handler,
1939 flags: signal->flags & G_CONNECT_SWAPPED ? TRUE : FALSE,
1940 object: connect_object,
1941 error);
1942
1943 if (closure == NULL)
1944 {
1945 result = false;
1946 break;
1947 }
1948
1949 g_signal_connect_closure_by_id (instance: object,
1950 signal_id: signal->id,
1951 detail: signal->detail,
1952 closure,
1953 after: signal->flags & G_CONNECT_AFTER ? TRUE : FALSE);
1954 }
1955
1956 g_ptr_array_free (array: priv->signals, TRUE);
1957 priv->signals = NULL;
1958
1959 return result;
1960}
1961
1962gboolean
1963_gtk_builder_finish (GtkBuilder *builder,
1964 GError **error)
1965{
1966 return gtk_builder_apply_delayed_properties (builder, error) &&
1967 gtk_builder_create_bindings (builder, error) &&
1968 gtk_builder_connect_signals (builder, error);
1969}
1970
1971/**
1972 * gtk_builder_value_from_string:
1973 * @builder: a `GtkBuilder`
1974 * @pspec: the `GParamSpec` for the property
1975 * @string: the string representation of the value
1976 * @value: (out): the `GValue` to store the result in
1977 * @error: (nullable): return location for an error
1978 *
1979 * Demarshals a value from a string.
1980 *
1981 * This function calls g_value_init() on the @value argument,
1982 * so it need not be initialised beforehand.
1983 *
1984 * Can handle char, uchar, boolean, int, uint, long,
1985 * ulong, enum, flags, float, double, string, `GdkRGBA` and
1986 * `GtkAdjustment` type values.
1987 *
1988 * Upon errors %FALSE will be returned and @error will be
1989 * assigned a `GError` from the %GTK_BUILDER_ERROR domain.
1990 *
1991 * Returns: %TRUE on success
1992 */
1993gboolean
1994gtk_builder_value_from_string (GtkBuilder *builder,
1995 GParamSpec *pspec,
1996 const char *string,
1997 GValue *value,
1998 GError **error)
1999{
2000 g_return_val_if_fail (GTK_IS_BUILDER (builder), FALSE);
2001 g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), FALSE);
2002 g_return_val_if_fail (string != NULL, FALSE);
2003 g_return_val_if_fail (value != NULL, FALSE);
2004 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
2005
2006 /*
2007 * GParamSpecUnichar has the internal type G_TYPE_UINT,
2008 * so we cannot handle this in the switch, do it separately
2009 */
2010 if (G_IS_PARAM_SPEC_UNICHAR (pspec))
2011 {
2012 gunichar c;
2013 g_value_init (value, G_TYPE_UINT);
2014 c = g_utf8_get_char_validated (p: string, max_len: -1);
2015 if (c != 0 && c != (gunichar)-1 && c != (gunichar)-2)
2016 g_value_set_uint (value, v_uint: c);
2017 return TRUE;
2018 }
2019
2020 /*
2021 * GParamSpecVariant can specify a GVariantType which can help with
2022 * parsing, so we need to take care of that here.
2023 */
2024 if (G_IS_PARAM_SPEC_VARIANT (pspec))
2025 {
2026 GParamSpecVariant *variant_pspec = G_PARAM_SPEC_VARIANT (pspec);
2027 const GVariantType *type;
2028 GVariant *variant;
2029
2030 g_value_init (value, G_TYPE_VARIANT);
2031
2032 /* The GVariant parser doesn't deal with indefinite types */
2033 if (g_variant_type_is_definite (type: variant_pspec->type))
2034 type = variant_pspec->type;
2035 else
2036 type = NULL;
2037
2038 variant = g_variant_parse (type, text: string, NULL, NULL, error);
2039 if (variant == NULL)
2040 return FALSE;
2041 g_value_take_variant (value, variant);
2042 return TRUE;
2043 }
2044
2045 return gtk_builder_value_from_string_type (builder,
2046 G_PARAM_SPEC_VALUE_TYPE (pspec),
2047 string, value, error);
2048}
2049
2050gboolean
2051_gtk_builder_boolean_from_string (const char *string,
2052 gboolean *value,
2053 GError **error)
2054{
2055 if (string[0] == '\0')
2056 goto error;
2057 else if (string[1] == '\0')
2058 {
2059 char c;
2060
2061 c = string[0];
2062 if (c == '1' ||
2063 c == 'y' || c == 't' ||
2064 c == 'Y' || c == 'T')
2065 *value = TRUE;
2066 else if (c == '0' ||
2067 c == 'n' || c == 'f' ||
2068 c == 'N' || c == 'F')
2069 *value = FALSE;
2070 else
2071 goto error;
2072 }
2073 else
2074 {
2075 if (g_ascii_strcasecmp (s1: string, s2: "true") == 0 ||
2076 g_ascii_strcasecmp (s1: string, s2: "yes") == 0)
2077 *value = TRUE;
2078 else if (g_ascii_strcasecmp (s1: string, s2: "false") == 0 ||
2079 g_ascii_strcasecmp (s1: string, s2: "no") == 0)
2080 *value = FALSE;
2081 else
2082 goto error;
2083 }
2084
2085 return TRUE;
2086
2087error:
2088 g_set_error (err: error,
2089 GTK_BUILDER_ERROR,
2090 code: GTK_BUILDER_ERROR_INVALID_VALUE,
2091 format: "Could not parse boolean '%s'",
2092 string);
2093 return FALSE;
2094}
2095
2096
2097/**
2098 * gtk_builder_value_from_string_type:
2099 * @builder: a `GtkBuilder`
2100 * @type: the `GType` of the value
2101 * @string: the string representation of the value
2102 * @value: (out): the `GValue` to store the result in
2103 * @error: (nullable): return location for an error
2104 *
2105 * Demarshals a value from a string.
2106 *
2107 * Unlike [method@Gtk.Builder.value_from_string], this function
2108 * takes a `GType` instead of `GParamSpec`.
2109 *
2110 * Calls g_value_init() on the @value argument, so it
2111 * need not be initialised beforehand.
2112 *
2113 * Upon errors %FALSE will be returned and @error will be
2114 * assigned a `GError` from the %GTK_BUILDER_ERROR domain.
2115 *
2116 * Returns: %TRUE on success
2117 */
2118gboolean
2119gtk_builder_value_from_string_type (GtkBuilder *builder,
2120 GType type,
2121 const char *string,
2122 GValue *value,
2123 GError **error)
2124{
2125 GtkBuilderPrivate *priv = gtk_builder_get_instance_private (self: builder);
2126 gboolean ret = TRUE;
2127
2128 g_return_val_if_fail (string != NULL, FALSE);
2129 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
2130
2131 g_value_init (value, g_type: type);
2132
2133 switch (G_TYPE_FUNDAMENTAL (type))
2134 {
2135 case G_TYPE_CHAR:
2136 g_value_set_schar (value, v_char: string[0]);
2137 break;
2138 case G_TYPE_UCHAR:
2139 g_value_set_uchar (value, v_uchar: (guchar)string[0]);
2140 break;
2141 case G_TYPE_BOOLEAN:
2142 {
2143 gboolean b;
2144
2145 if (!_gtk_builder_boolean_from_string (string, value: &b, error))
2146 {
2147 ret = FALSE;
2148 break;
2149 }
2150 g_value_set_boolean (value, v_boolean: b);
2151 break;
2152 }
2153 case G_TYPE_INT:
2154 case G_TYPE_LONG:
2155 case G_TYPE_INT64:
2156 {
2157 gint64 l;
2158 char *endptr = NULL;
2159
2160 errno = 0;
2161 l = g_ascii_strtoll (nptr: string, endptr: &endptr, base: 0);
2162 if (errno || endptr == string)
2163 {
2164 g_set_error (err: error,
2165 GTK_BUILDER_ERROR,
2166 code: GTK_BUILDER_ERROR_INVALID_VALUE,
2167 format: "Could not parse integer '%s'",
2168 string);
2169 ret = FALSE;
2170 break;
2171 }
2172 if (G_VALUE_HOLDS_INT (value))
2173 g_value_set_int (value, v_int: l);
2174 else if (G_VALUE_HOLDS_LONG (value))
2175 g_value_set_long (value, v_long: l);
2176 else
2177 g_value_set_int64 (value, v_int64: l);
2178 break;
2179 }
2180 case G_TYPE_UINT:
2181 case G_TYPE_ULONG:
2182 case G_TYPE_UINT64:
2183 {
2184 guint64 ul;
2185 char *endptr = NULL;
2186 errno = 0;
2187 ul = g_ascii_strtoull (nptr: string, endptr: &endptr, base: 0);
2188 if (errno || endptr == string)
2189 {
2190 g_set_error (err: error,
2191 GTK_BUILDER_ERROR,
2192 code: GTK_BUILDER_ERROR_INVALID_VALUE,
2193 format: "Could not parse unsigned integer '%s'",
2194 string);
2195 ret = FALSE;
2196 break;
2197 }
2198 if (G_VALUE_HOLDS_UINT (value))
2199 g_value_set_uint (value, v_uint: ul);
2200 else if (G_VALUE_HOLDS_ULONG (value))
2201 g_value_set_ulong (value, v_ulong: ul);
2202 else
2203 g_value_set_uint64 (value, v_uint64: ul);
2204 break;
2205 }
2206 case G_TYPE_ENUM:
2207 {
2208 int enum_value;
2209 if (!_gtk_builder_enum_from_string (type, string, enum_value: &enum_value, error))
2210 {
2211 ret = FALSE;
2212 break;
2213 }
2214 g_value_set_enum (value, v_enum: enum_value);
2215 break;
2216 }
2217 case G_TYPE_FLAGS:
2218 {
2219 guint flags_value;
2220
2221 if (!_gtk_builder_flags_from_string (type, string, value: &flags_value, error))
2222 {
2223 ret = FALSE;
2224 break;
2225 }
2226 g_value_set_flags (value, v_flags: flags_value);
2227 break;
2228 }
2229 case G_TYPE_FLOAT:
2230 case G_TYPE_DOUBLE:
2231 {
2232 double d;
2233 char *endptr = NULL;
2234 errno = 0;
2235 d = g_ascii_strtod (nptr: string, endptr: &endptr);
2236 if (errno || endptr == string)
2237 {
2238 g_set_error (err: error,
2239 GTK_BUILDER_ERROR,
2240 code: GTK_BUILDER_ERROR_INVALID_VALUE,
2241 format: "Could not parse double '%s'",
2242 string);
2243 ret = FALSE;
2244 break;
2245 }
2246 if (G_VALUE_HOLDS_FLOAT (value))
2247 g_value_set_float (value, v_float: d);
2248 else
2249 g_value_set_double (value, v_double: d);
2250 break;
2251 }
2252 case G_TYPE_STRING:
2253 g_value_set_string (value, v_string: string);
2254 break;
2255 case G_TYPE_VARIANT:
2256 {
2257 GVariant *variant;
2258
2259 variant = g_variant_parse (NULL, text: string, NULL, NULL, error);
2260 if (value != NULL)
2261 g_value_take_variant (value, variant);
2262 else
2263 ret = FALSE;
2264 }
2265 break;
2266 case G_TYPE_BOXED:
2267 if (G_VALUE_HOLDS (value, GDK_TYPE_RGBA))
2268 {
2269 GdkRGBA rgba = { 0 };
2270
2271 if (gdk_rgba_parse (rgba: &rgba, spec: string))
2272 g_value_set_boxed (value, v_boxed: &rgba);
2273 else
2274 {
2275 g_set_error (err: error,
2276 GTK_BUILDER_ERROR,
2277 code: GTK_BUILDER_ERROR_INVALID_VALUE,
2278 format: "Could not parse RGBA color '%s'",
2279 string);
2280 ret = FALSE;
2281 }
2282 }
2283 else if (G_VALUE_HOLDS (value, GDK_TYPE_CONTENT_FORMATS))
2284 {
2285 GdkContentFormats *formats;
2286
2287 formats = gdk_content_formats_parse (string);
2288 if (formats)
2289 g_value_take_boxed (value, v_boxed: formats);
2290 else
2291 {
2292 g_set_error (err: error,
2293 GTK_BUILDER_ERROR,
2294 code: GTK_BUILDER_ERROR_INVALID_VALUE,
2295 format: "Could not parse GdkContentFormats '%s'",
2296 string);
2297 ret = FALSE;
2298 }
2299 }
2300 else if (G_VALUE_HOLDS (value, GSK_TYPE_TRANSFORM))
2301 {
2302 GskTransform *transform;
2303
2304 if (gsk_transform_parse (string, out_transform: &transform))
2305 g_value_take_boxed (value, v_boxed: transform);
2306 else
2307 {
2308 g_set_error (err: error,
2309 GTK_BUILDER_ERROR,
2310 code: GTK_BUILDER_ERROR_INVALID_VALUE,
2311 format: "Could not parse transform '%s'",
2312 string);
2313 ret = FALSE;
2314 }
2315 }
2316 else if (G_VALUE_HOLDS (value, G_TYPE_STRV))
2317 {
2318 char **vector = g_strsplit (string, delimiter: "\n", max_tokens: 0);
2319 g_value_take_boxed (value, v_boxed: vector);
2320 }
2321 else if (G_VALUE_HOLDS (value, G_TYPE_BYTES))
2322 {
2323 g_value_take_boxed (value, v_boxed: g_bytes_new (data: string, size: strlen (s: string)));
2324 }
2325 else
2326 {
2327 g_set_error (err: error,
2328 GTK_BUILDER_ERROR,
2329 code: GTK_BUILDER_ERROR_INVALID_VALUE,
2330 format: "Could not parse '%s' as a %s",
2331 string, G_VALUE_TYPE_NAME (value));
2332 ret = FALSE;
2333 }
2334 break;
2335 case G_TYPE_OBJECT:
2336 case G_TYPE_INTERFACE:
2337 if (G_VALUE_HOLDS (value, GDK_TYPE_PAINTABLE) ||
2338 G_VALUE_HOLDS (value, GDK_TYPE_TEXTURE))
2339 {
2340 GObject *object = g_hash_table_lookup (hash_table: priv->objects, key: string);
2341 char *filename;
2342 GError *tmp_error = NULL;
2343 GdkTexture *texture = NULL;
2344
2345 if (object)
2346 {
2347 if (g_type_is_a (G_OBJECT_TYPE (object), G_VALUE_TYPE (value)))
2348 {
2349 g_value_set_object (value, v_object: object);
2350 return TRUE;
2351 }
2352 else
2353 {
2354 g_set_error (err: error,
2355 GTK_BUILDER_ERROR,
2356 code: GTK_BUILDER_ERROR_INVALID_VALUE,
2357 format: "Could not load image '%s': "
2358 " '%s' is already used as object id for a %s",
2359 string, string, G_OBJECT_TYPE_NAME (object));
2360 return FALSE;
2361 }
2362 }
2363
2364 filename = _gtk_builder_get_resource_path (builder, string);
2365 if (filename != NULL)
2366 {
2367 texture = gdk_texture_new_from_resource (resource_path: filename);
2368 }
2369 else
2370 {
2371 GFile *file;
2372
2373 filename = _gtk_builder_get_absolute_filename (builder, string);
2374 file = g_file_new_for_path (path: filename);
2375 texture = gdk_texture_new_from_file (file, error: &tmp_error);
2376 g_object_unref (object: file);
2377 }
2378
2379 g_free (mem: filename);
2380
2381 if (!texture)
2382 {
2383 g_warning ("Could not load image '%s': %s", string, tmp_error->message);
2384 g_error_free (error: tmp_error);
2385
2386 texture = gdk_texture_new_from_resource (IMAGE_MISSING_RESOURCE_PATH);
2387 }
2388
2389 g_value_take_object (value, v_object: texture);
2390
2391 ret = TRUE;
2392 }
2393 else if (G_VALUE_HOLDS (value, GDK_TYPE_PIXBUF))
2394 {
2395 char *filename;
2396 GError *tmp_error = NULL;
2397 GdkPixbuf *pixbuf = NULL;
2398 GObject *object;
2399
2400 object = g_hash_table_lookup (hash_table: priv->objects, key: string);
2401
2402 if (object)
2403 {
2404 if (g_type_is_a (G_OBJECT_TYPE (object), G_VALUE_TYPE (value)))
2405 {
2406 g_value_set_object (value, v_object: object);
2407 return TRUE;
2408 }
2409 else
2410 {
2411 g_set_error (err: error,
2412 GTK_BUILDER_ERROR,
2413 code: GTK_BUILDER_ERROR_INVALID_VALUE,
2414 format: "Could not load image '%s': "
2415 " '%s' is already used as object id for a %s",
2416 string, string, G_OBJECT_TYPE_NAME (object));
2417 return FALSE;
2418 }
2419 }
2420
2421 filename = _gtk_builder_get_resource_path (builder, string);
2422 if (filename != NULL)
2423 {
2424 GInputStream *stream = g_resources_open_stream (path: filename, lookup_flags: 0, error: &tmp_error);
2425 if (stream != NULL)
2426 {
2427 pixbuf = gdk_pixbuf_new_from_stream (stream, NULL, error: &tmp_error);
2428 g_object_unref (object: stream);
2429 }
2430 }
2431 else
2432 {
2433 filename = _gtk_builder_get_absolute_filename (builder, string);
2434 pixbuf = gdk_pixbuf_new_from_file (filename, error: &tmp_error);
2435 }
2436
2437 if (pixbuf == NULL)
2438 {
2439 g_warning ("Could not load image '%s': %s", string, tmp_error->message);
2440 g_error_free (error: tmp_error);
2441
2442 pixbuf = gdk_pixbuf_new_from_resource (IMAGE_MISSING_RESOURCE_PATH, NULL);
2443 }
2444
2445 g_value_take_object (value, v_object: pixbuf);
2446
2447 g_free (mem: filename);
2448
2449 ret = TRUE;
2450 }
2451 else if (G_VALUE_HOLDS (value, G_TYPE_FILE))
2452 {
2453 GFile *file;
2454
2455 if (g_hash_table_contains (hash_table: priv->objects, key: string))
2456 {
2457 g_set_error (err: error,
2458 GTK_BUILDER_ERROR,
2459 code: GTK_BUILDER_ERROR_INVALID_VALUE,
2460 format: "Could not create file '%s': "
2461 " '%s' is already used as object id",
2462 string, string);
2463 return FALSE;
2464 }
2465
2466 file = g_file_new_for_uri (uri: string);
2467 g_value_set_object (value, v_object: file);
2468 g_object_unref (G_OBJECT (file));
2469
2470 ret = TRUE;
2471 }
2472 else if (G_VALUE_HOLDS (value, GTK_TYPE_SHORTCUT_TRIGGER))
2473 {
2474 GtkShortcutTrigger *trigger = gtk_shortcut_trigger_parse_string (string);
2475
2476 if (trigger)
2477 g_value_take_object (value, v_object: trigger);
2478 else
2479 {
2480 g_set_error (err: error,
2481 GTK_BUILDER_ERROR,
2482 code: GTK_BUILDER_ERROR_INVALID_VALUE,
2483 format: "Could not parse shortcut trigger '%s'",
2484 string);
2485 ret = FALSE;
2486 }
2487 }
2488 else if (G_VALUE_HOLDS (value, GTK_TYPE_SHORTCUT_ACTION))
2489 {
2490 GtkShortcutAction *action = gtk_shortcut_action_parse_builder (builder, string, error);
2491
2492 /* Works for success and failure (NULL) case */
2493 g_value_take_object (value, v_object: action);
2494 }
2495 else
2496 {
2497 GObject *object = g_hash_table_lookup (hash_table: priv->objects, key: string);
2498
2499 if (object && g_value_type_compatible (G_OBJECT_TYPE (object), dest_type: type))
2500 {
2501 g_value_set_object (value, v_object: object);
2502 }
2503 else if (object)
2504 {
2505 g_set_error (err: error,
2506 GTK_BUILDER_ERROR,
2507 code: GTK_BUILDER_ERROR_INVALID_VALUE,
2508 format: "Object named \"%s\" is of type \"%s\" which is not compatible with expected type \%s\"",
2509 string, G_OBJECT_TYPE_NAME (object), g_type_name (type));
2510 ret = FALSE;
2511 }
2512 else
2513 {
2514 g_set_error (err: error,
2515 GTK_BUILDER_ERROR,
2516 code: GTK_BUILDER_ERROR_INVALID_VALUE,
2517 format: "No object named \"%s\"", string);
2518 ret = FALSE;
2519 }
2520 }
2521 break;
2522 case G_TYPE_POINTER:
2523 if (G_VALUE_HOLDS (value, G_TYPE_GTYPE))
2524 {
2525 GType resolved_type;
2526
2527 resolved_type = gtk_builder_get_type_from_name (builder, type_name: string);
2528 if (resolved_type == G_TYPE_INVALID)
2529 {
2530 g_set_error (err: error,
2531 GTK_BUILDER_ERROR,
2532 code: GTK_BUILDER_ERROR_INVALID_VALUE,
2533 format: "Unsupported GType '%s' for value of type 'GType'", string);
2534 return FALSE;
2535 }
2536 g_value_set_gtype (value, v_gtype: resolved_type);
2537
2538 ret = TRUE;
2539 }
2540 else
2541 ret = FALSE;
2542 break;
2543 default:
2544 ret = FALSE;
2545 break;
2546 }
2547
2548 /* Catch unassigned error for object types as well as any unsupported types.
2549 * While parsing GtkBuilder; object types are deserialized
2550 * without calling gtk_builder_value_from_string_type().
2551 */
2552 if (!ret && error && *error == NULL)
2553 g_set_error (err: error,
2554 GTK_BUILDER_ERROR,
2555 code: GTK_BUILDER_ERROR_INVALID_VALUE,
2556 format: "Unsupported GType '%s'", g_type_name (type));
2557
2558 return ret;
2559}
2560
2561gboolean
2562_gtk_builder_enum_from_string (GType type,
2563 const char *string,
2564 int *enum_value,
2565 GError **error)
2566{
2567 GEnumClass *eclass;
2568 GEnumValue *ev;
2569 char *endptr;
2570 int value;
2571 gboolean ret;
2572
2573 g_return_val_if_fail (G_TYPE_IS_ENUM (type), FALSE);
2574 g_return_val_if_fail (string != NULL, FALSE);
2575
2576 ret = TRUE;
2577
2578 endptr = NULL;
2579 errno = 0;
2580 value = g_ascii_strtoull (nptr: string, endptr: &endptr, base: 0);
2581 if (errno == 0 && endptr != string) /* parsed a number */
2582 *enum_value = value;
2583 else
2584 {
2585 eclass = g_type_class_ref (type);
2586 ev = g_enum_get_value_by_nick (enum_class: eclass, nick: string);
2587 if (!ev)
2588 ev = g_enum_get_value_by_name (enum_class: eclass, name: string);
2589
2590 if (ev)
2591 *enum_value = ev->value;
2592 else
2593 {
2594 g_set_error (err: error,
2595 GTK_BUILDER_ERROR,
2596 code: GTK_BUILDER_ERROR_INVALID_VALUE,
2597 format: "Could not parse enum: '%s'",
2598 string);
2599 ret = FALSE;
2600 }
2601
2602 g_type_class_unref (g_class: eclass);
2603 }
2604
2605 return ret;
2606}
2607
2608gboolean
2609_gtk_builder_flags_from_string (GType type,
2610 const char *string,
2611 guint *flags_value,
2612 GError **error)
2613{
2614 GFlagsClass *fclass;
2615 char *endptr, *prevptr;
2616 guint i, j, value;
2617 char *flagstr;
2618 GFlagsValue *fv;
2619 const char *flag;
2620 gunichar ch;
2621 gboolean eos, ret;
2622
2623 g_return_val_if_fail (G_TYPE_IS_FLAGS (type), FALSE);
2624 g_return_val_if_fail (string != 0, FALSE);
2625
2626 ret = TRUE;
2627
2628 endptr = NULL;
2629 errno = 0;
2630 value = g_ascii_strtoull (nptr: string, endptr: &endptr, base: 0);
2631 if (errno == 0 && endptr != string) /* parsed a number */
2632 *flags_value = value;
2633 else
2634 {
2635 fclass = g_type_class_ref (type);
2636
2637 flagstr = g_strdup (str: string);
2638 for (value = i = j = 0; ; i++)
2639 {
2640
2641 eos = flagstr[i] == '\0';
2642
2643 if (!eos && flagstr[i] != '|')
2644 continue;
2645
2646 flag = &flagstr[j];
2647 endptr = &flagstr[i];
2648
2649 if (!eos)
2650 {
2651 flagstr[i++] = '\0';
2652 j = i;
2653 }
2654
2655 /* trim spaces */
2656 for (;;)
2657 {
2658 ch = g_utf8_get_char (p: flag);
2659 if (!g_unichar_isspace (c: ch))
2660 break;
2661 flag = g_utf8_next_char (flag);
2662 }
2663
2664 while (endptr > flag)
2665 {
2666 prevptr = g_utf8_prev_char (p: endptr);
2667 ch = g_utf8_get_char (p: prevptr);
2668 if (!g_unichar_isspace (c: ch))
2669 break;
2670 endptr = prevptr;
2671 }
2672
2673 if (endptr > flag)
2674 {
2675 *endptr = '\0';
2676
2677 fv = NULL;
2678
2679 if (!fv)
2680 fv = g_flags_get_value_by_name (flags_class: fclass, name: flag);
2681
2682 if (!fv)
2683 fv = g_flags_get_value_by_nick (flags_class: fclass, nick: flag);
2684
2685 if (fv)
2686 value |= fv->value;
2687 else
2688 {
2689 g_set_error (err: error,
2690 GTK_BUILDER_ERROR,
2691 code: GTK_BUILDER_ERROR_INVALID_VALUE,
2692 format: "Unknown flag: '%s'",
2693 flag);
2694 ret = FALSE;
2695 break;
2696 }
2697 }
2698
2699 if (eos)
2700 {
2701 *flags_value = value;
2702 break;
2703 }
2704 }
2705
2706 g_free (mem: flagstr);
2707
2708 g_type_class_unref (g_class: fclass);
2709 }
2710
2711 return ret;
2712}
2713
2714/**
2715 * gtk_builder_get_type_from_name:
2716 * @builder: a `GtkBuilder`
2717 * @type_name: type name to lookup
2718 *
2719 * Looks up a type by name.
2720 *
2721 * This is using the virtual function that `GtkBuilder` has
2722 * for that purpose. This is mainly used when implementing
2723 * the `GtkBuildable` interface on a type.
2724 *
2725 * Returns: the `GType` found for @type_name or %G_TYPE_INVALID
2726 * if no type was found
2727 */
2728GType
2729gtk_builder_get_type_from_name (GtkBuilder *builder,
2730 const char *type_name)
2731{
2732 GtkBuilderPrivate *priv = gtk_builder_get_instance_private (self: builder);
2733 GType type;
2734
2735 g_return_val_if_fail (GTK_IS_BUILDER (builder), G_TYPE_INVALID);
2736 g_return_val_if_fail (type_name != NULL, G_TYPE_INVALID);
2737
2738 type = gtk_builder_scope_get_type_from_name (self: priv->scope, builder, type_name);
2739 if (type == G_TYPE_INVALID)
2740 return G_TYPE_INVALID;
2741
2742 if (G_TYPE_IS_CLASSED (type))
2743 g_type_class_unref (g_class: g_type_class_ref (type));
2744
2745 return type;
2746}
2747
2748GQuark
2749gtk_builder_error_quark (void)
2750{
2751 return g_quark_from_static_string (string: "gtk-builder-error-quark");
2752}
2753
2754char *
2755_gtk_builder_get_resource_path (GtkBuilder *builder, const char *string)
2756{
2757 GtkBuilderPrivate *priv = gtk_builder_get_instance_private (self: builder);
2758
2759 if (g_str_has_prefix (str: string, prefix: "resource:///"))
2760 return g_uri_unescape_string (escaped_string: string + 11, illegal_characters: "/");
2761
2762 if (g_path_is_absolute (file_name: string) ||
2763 priv->resource_prefix == NULL)
2764 return NULL;
2765
2766 return g_build_path (separator: "/", first_element: priv->resource_prefix, string, NULL);
2767}
2768
2769char *
2770_gtk_builder_get_absolute_filename (GtkBuilder *builder,
2771 const char *string)
2772{
2773 GtkBuilderPrivate *priv = gtk_builder_get_instance_private (self: builder);
2774 char *filename;
2775 char *dirname = NULL;
2776
2777 if (g_path_is_absolute (file_name: string))
2778 return g_strdup (str: string);
2779
2780 if (priv->filename &&
2781 strcmp (s1: priv->filename, s2: ".") != 0)
2782 {
2783 dirname = g_path_get_dirname (file_name: priv->filename);
2784
2785 if (strcmp (s1: dirname, s2: ".") == 0)
2786 {
2787 g_free (mem: dirname);
2788 dirname = g_get_current_dir ();
2789 }
2790 }
2791 else
2792 dirname = g_get_current_dir ();
2793
2794 filename = g_build_filename (first_element: dirname, string, NULL);
2795 g_free (mem: dirname);
2796
2797 return filename;
2798}
2799
2800GType
2801_gtk_builder_get_template_type (GtkBuilder *builder)
2802{
2803 GtkBuilderPrivate *priv = gtk_builder_get_instance_private (self: builder);
2804
2805 return priv->template_type;
2806}
2807
2808/**
2809 * gtk_builder_create_closure:
2810 * @builder: a `GtkBuilder`
2811 * @function_name: name of the function to look up
2812 * @flags: closure creation flags
2813 * @object: (nullable): Object to create the closure with
2814 * @error: (nullable): return location for an error
2815 *
2816 * Creates a closure to invoke the function called @function_name.
2817 *
2818 * This is using the create_closure() implementation of @builder's
2819 * [iface@Gtk.BuilderScope].
2820 *
2821 * If no closure could be created, %NULL will be returned and @error
2822 * will be set.
2823 *
2824 * Returns: (nullable): A new closure for invoking @function_name
2825 */
2826GClosure *
2827gtk_builder_create_closure (GtkBuilder *builder,
2828 const char *function_name,
2829 GtkBuilderClosureFlags flags,
2830 GObject *object,
2831 GError **error)
2832{
2833 GtkBuilderPrivate *priv = gtk_builder_get_instance_private (self: builder);
2834
2835 g_return_val_if_fail (GTK_IS_BUILDER (builder), NULL);
2836 g_return_val_if_fail (function_name, NULL);
2837 g_return_val_if_fail (object == NULL || G_IS_OBJECT (object), NULL);
2838 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
2839
2840 return gtk_builder_scope_create_closure (self: priv->scope, builder, function_name, flags, object, error);
2841}
2842
2843/**
2844 * gtk_builder_new_from_file: (constructor)
2845 * @filename: (type filename): filename of user interface description file
2846 *
2847 * Parses the UI definition in the file @filename.
2848 *
2849 * If there is an error opening the file or parsing the description then
2850 * the program will be aborted. You should only ever attempt to parse
2851 * user interface descriptions that are shipped as part of your program.
2852 *
2853 * Returns: (transfer full): a `GtkBuilder` containing the described interface
2854 */
2855GtkBuilder *
2856gtk_builder_new_from_file (const char *filename)
2857{
2858 GError *error = NULL;
2859 GtkBuilder *builder;
2860
2861 builder = gtk_builder_new ();
2862 if (!gtk_builder_add_from_file (builder, filename, error: &error))
2863 g_error ("failed to add UI from file %s: %s", filename, error->message);
2864
2865 return builder;
2866}
2867
2868/**
2869 * gtk_builder_new_from_resource: (constructor)
2870 * @resource_path: a `GResource` resource path
2871 *
2872 * Parses the UI definition at @resource_path.
2873 *
2874 * If there is an error locating the resource or parsing the
2875 * description, then the program will be aborted.
2876 *
2877 * Returns: (transfer full): a `GtkBuilder` containing the described interface
2878 */
2879GtkBuilder *
2880gtk_builder_new_from_resource (const char *resource_path)
2881{
2882 GError *error = NULL;
2883 GtkBuilder *builder;
2884
2885 builder = gtk_builder_new ();
2886 if (!gtk_builder_add_from_resource (builder, resource_path, error: &error))
2887 g_error ("failed to add UI from resource %s: %s", resource_path, error->message);
2888
2889 return builder;
2890}
2891
2892/**
2893 * gtk_builder_new_from_string: (constructor)
2894 * @string: a user interface (XML) description
2895 * @length: the length of @string, or -1
2896 *
2897 * Parses the UI definition in @string.
2898 *
2899 * If @string is %NULL-terminated, then @length should be -1.
2900 * If @length is not -1, then it is the length of @string.
2901 *
2902 * If there is an error parsing @string then the program will be
2903 * aborted. You should not attempt to parse user interface description
2904 * from untrusted sources.
2905 *
2906 * Returns: (transfer full): a `GtkBuilder` containing the interface described by @string
2907 */
2908GtkBuilder *
2909gtk_builder_new_from_string (const char *string,
2910 gssize length)
2911{
2912 GError *error = NULL;
2913 GtkBuilder *builder;
2914
2915 builder = gtk_builder_new ();
2916 if (!gtk_builder_add_from_string (builder, buffer: string, length, error: &error))
2917 g_error ("failed to add UI: %s", error->message);
2918
2919 return builder;
2920}
2921
2922/*< private >
2923 * _gtk_builder_prefix_error:
2924 * @builder: a `GtkBuilder`
2925 * @context: the `GtkBuildableParseContext`
2926 * @error: an error
2927 *
2928 * Calls g_prefix_error() to prepend a filename:line:column marker
2929 * to the given error. The filename is taken from @builder, and
2930 * the line and column are obtained by calling
2931 * g_markup_parse_context_get_position().
2932 *
2933 * This is intended to be called on errors returned by
2934 * g_markup_collect_attributes() in a start_element vfunc.
2935 */
2936void
2937_gtk_builder_prefix_error (GtkBuilder *builder,
2938 GtkBuildableParseContext *context,
2939 GError **error)
2940{
2941 GtkBuilderPrivate *priv = gtk_builder_get_instance_private (self: builder);
2942 int line, col;
2943
2944 gtk_buildable_parse_context_get_position (context, line_number: &line, char_number: &col);
2945 g_prefix_error (err: error, format: "%s:%d:%d ", priv->filename, line, col);
2946}
2947
2948/*< private >
2949 * _gtk_builder_error_unhandled_tag:
2950 * @builder: a `GtkBuilder`
2951 * @context: the `GtkBuildableParseContext`
2952 * @object: name of the object that is being handled
2953 * @element_name: name of the element whose start tag is being handled
2954 * @error: return location for the error
2955 *
2956 * Sets @error to a suitable error indicating that an @element_name
2957 * tag is not expected in the custom markup for @object.
2958 *
2959 * This is intended to be called in a start_element vfunc.
2960 */
2961void
2962_gtk_builder_error_unhandled_tag (GtkBuilder *builder,
2963 GtkBuildableParseContext *context,
2964 const char *object,
2965 const char *element_name,
2966 GError **error)
2967{
2968 GtkBuilderPrivate *priv = gtk_builder_get_instance_private (self: builder);
2969 int line, col;
2970
2971 gtk_buildable_parse_context_get_position (context, line_number: &line, char_number: &col);
2972 g_set_error (err: error,
2973 GTK_BUILDER_ERROR,
2974 code: GTK_BUILDER_ERROR_UNHANDLED_TAG,
2975 format: "%s:%d:%d Unsupported tag for %s: <%s>",
2976 priv->filename, line, col,
2977 object, element_name);
2978}
2979
2980/*< private >
2981 * @builder: a `GtkBuilder`
2982 * @context: the `GtkBuildableParseContext`
2983 * @parent_name: the name of the expected parent element
2984 * @error: return location for an error
2985 *
2986 * Checks that the parent element of the currently handled
2987 * start tag is @parent_name and set @error if it isn't.
2988 *
2989 * This is intended to be called in start_element vfuncs to
2990 * ensure that element nesting is as intended.
2991 *
2992 * Returns: %TRUE if @parent_name is the parent element
2993 */
2994gboolean
2995_gtk_builder_check_parent (GtkBuilder *builder,
2996 GtkBuildableParseContext *context,
2997 const char *parent_name,
2998 GError **error)
2999{
3000 GtkBuilderPrivate *priv = gtk_builder_get_instance_private (self: builder);
3001 GPtrArray *stack;
3002 int line, col;
3003 const char *parent;
3004 const char *element;
3005
3006 stack = gtk_buildable_parse_context_get_element_stack (context);
3007
3008 element = g_ptr_array_index (stack, stack->len - 1);
3009 parent = stack->len > 1 ? g_ptr_array_index (stack, stack->len - 2) : "";
3010
3011 if (g_str_equal (v1: parent_name, v2: parent) ||
3012 (g_str_equal (v1: parent_name, v2: "object") && g_str_equal (v1: parent, v2: "template")))
3013 return TRUE;
3014
3015 gtk_buildable_parse_context_get_position (context, line_number: &line, char_number: &col);
3016 g_set_error (err: error,
3017 GTK_BUILDER_ERROR,
3018 code: GTK_BUILDER_ERROR_INVALID_TAG,
3019 format: "%s:%d:%d Can't use <%s> here",
3020 priv->filename, line, col, element);
3021
3022 return FALSE;
3023}
3024
3025GObject *
3026gtk_builder_lookup_object (GtkBuilder *builder,
3027 const char *name,
3028 int line,
3029 int col,
3030 GError **error)
3031{
3032 GtkBuilderPrivate *priv = gtk_builder_get_instance_private (self: builder);
3033 GObject *obj;
3034
3035 obj = g_hash_table_lookup (hash_table: priv->objects, key: name);
3036 if (obj == NULL)
3037 {
3038 g_set_error (err: error,
3039 GTK_BUILDER_ERROR, code: GTK_BUILDER_ERROR_INVALID_ID,
3040 format: "%s:%d:%d Object with ID %s not found",
3041 priv->filename, line, col, name);
3042 }
3043
3044 return obj;
3045}
3046
3047/*< private >
3048 * @builder: a `GtkBuilder`
3049 * @name: object name to look up
3050 * @line: line number where @name was encountered
3051 * @col: column number where @name was encountered
3052 *
3053 * Looks up an object by name. Similar to gtk_builder_get_object(),
3054 * but sets an error if lookup fails during custom_tag_end,
3055 * custom_finished or parser_finished vfuncs.
3056 *
3057 * The reason for doing things this way is that these vfuncs don't
3058 * take a GError** parameter to return an error.
3059 *
3060 * Returns: the found object
3061 */
3062GObject *
3063_gtk_builder_lookup_object (GtkBuilder *builder,
3064 const char *name,
3065 int line,
3066 int col)
3067{
3068 GtkBuilderPrivate *priv = gtk_builder_get_instance_private (self: builder);
3069 GObject *obj;
3070 GError *error = NULL;
3071
3072 obj = g_hash_table_lookup (hash_table: priv->objects, key: name);
3073 error = (GError *) g_object_get_data (G_OBJECT (builder), key: "lookup-error");
3074
3075 if (!obj && !error)
3076 {
3077 g_set_error (err: &error,
3078 GTK_BUILDER_ERROR, code: GTK_BUILDER_ERROR_INVALID_ID,
3079 format: "%s:%d:%d Object with ID %s not found",
3080 priv->filename, line, col, name);
3081 g_object_set_data_full (G_OBJECT (builder), key: "lookup-error",
3082 data: error, destroy: (GDestroyNotify)g_error_free);
3083 }
3084
3085 return obj;
3086}
3087
3088/*< private >
3089 * _gtk_builder_lookup_failed:
3090 * @GtkBuilder: a `GtkBuilder`
3091 * @error: return location for error
3092 *
3093 * Finds whether any object lookups have failed.
3094 *
3095 * Returns: %TRUE if @error has been set
3096 */
3097gboolean
3098_gtk_builder_lookup_failed (GtkBuilder *builder,
3099 GError **error)
3100{
3101 GError *lookup_error;
3102
3103 lookup_error = (GError*) g_object_steal_data (G_OBJECT (builder), key: "lookup-error");
3104 if (lookup_error)
3105 {
3106 g_propagate_error (dest: error, src: lookup_error);
3107 return TRUE;
3108 }
3109
3110 return FALSE;
3111}
3112

source code of gtk/gtk/gtkbuilder.c