summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohan Dahlin <jdahlin@async.com.br>2007-06-15 17:53:46 +0000
committerJohan Dahlin <johan@src.gnome.org>2007-06-15 17:53:46 +0000
commit4d638bf0c15c363f2c28cafc1485cf4066885383 (patch)
tree5638874af2c1303cfb41c0e5f2db608af06355d0
parent49fc7e15ee345fbae8960dfc2c4437364f8acb50 (diff)
downloadgtk+-4d638bf0c15c363f2c28cafc1485cf4066885383.tar.gz
Add GtkBuilder, fixes #172535
2007-06-15 Johan Dahlin <jdahlin@async.com.br> * demos/gtk-demo/Makefile.am: * demos/gtk-demo/builder.c: (quit_activate), (about_activate), (do_builder): * demos/gtk-demo/demo.ui: * docs/reference/gtk/gtk-docs.sgml: * docs/reference/gtk/gtk-sections.txt: * docs/reference/gtk/gtk.types: * docs/reference/gtk/tmpl/gtkbuildable.sgml: * docs/reference/gtk/tmpl/gtkbuilder.sgml: * gtk/Makefile.am: * gtk/gtk.h: * gtk/gtk.symbols: * gtk/gtkaction.c: (gtk_action_buildable_init), (gtk_action_buildable_set_name), (gtk_action_buildable_get_name): * gtk/gtkactiongroup.c: (gtk_action_group_get_type), (gtk_action_group_buildable_init), (gtk_action_group_buildable_add), (gtk_action_group_buildable_set_name), (gtk_action_group_buildable_get_name): * gtk/gtkbuildable.c: (gtk_buildable_get_type), (gtk_buildable_set_name), (gtk_buildable_get_name), (gtk_buildable_add), (gtk_buildable_set_property), (gtk_buildable_parser_finished), (gtk_buildable_construct_child), (gtk_buildable_custom_tag_start), (gtk_buildable_custom_tag_end), (gtk_buildable_custom_finished), (gtk_buildable_get_internal_child): * gtk/gtkbuildable.h: * gtk/gtkbuilder.c: (gtk_builder_class_init), (gtk_builder_init), (gtk_builder_finalize), (gtk_builder_set_property), (gtk_builder_get_property), (_gtk_builder_resolve_type_lazily), (gtk_builder_real_get_type_from_name), (gtk_builder_get_parameters), (gtk_builder_get_internal_child), (_gtk_builder_construct), (_gtk_builder_add), (apply_delayed_properties), (_gtk_builder_finish), (gtk_builder_new), (gtk_builder_add_from_file), (gtk_builder_add_from_string), (gtk_builder_get_object), (object_add_to_list), (gtk_builder_get_objects), (gtk_builder_set_translation_domain), (gtk_builder_get_translation_domain), (gtk_builder_connect_signals_default), (gtk_builder_connect_signals), (gtk_builder_connect_signals_full), (gtk_builder_value_from_string), (gtk_builder_value_from_string_type), (_gtk_builder_enum_from_string), (_gtk_builder_flags_from_string), (gtk_builder_get_type_from_name), (gtk_builder_error_quark): * gtk/gtkbuilder.h: * gtk/gtkbuilderparser.c: (state_push), (state_peek), (state_pop), (error_missing_attribute), (error_invalid_attribute), (error_invalid_tag), (builder_construct), (parse_object), (free_object_info), (_get_type_by_symbol), (parse_child), (free_child_info), (parse_property), (free_property_info), (parse_signal), (_free_signal_info), (parse_interface), (create_subparser), (free_subparser), (subparser_start), (subparser_end), (parse_custom), (start_element), (end_element), (text), (_gtk_builder_parser_parse_buffer): * gtk/gtkbuilderprivate.h: * gtk/gtkcelllayout.c: (attributes_start_element), (attributes_text_element), (_gtk_cell_layout_buildable_custom_tag_start), (_gtk_cell_layout_buildable_custom_tag_end), (_gtk_cell_layout_buildable_add): * gtk/gtkcelllayout.h: * gtk/gtkcellview.c: (gtk_cell_view_buildable_init), (gtk_cell_view_buildable_custom_tag_start), (gtk_cell_view_buildable_custom_tag_end): * gtk/gtkcolorseldialog.c: (gtk_color_selection_dialog_buildable_interface_init), (gtk_color_selection_dialog_buildable_get_internal_child): * gtk/gtkcombobox.c: (gtk_combo_box_buildable_init), (gtk_combo_box_buildable_custom_tag_start), (gtk_combo_box_buildable_custom_tag_end): * gtk/gtkcomboboxentry.c: (gtk_combo_box_entry_buildable_interface_init), (gtk_combo_box_entry_buildable_get_internal_child): * gtk/gtkcontainer.c: (gtk_container_get_type), (gtk_container_buildable_init), (gtk_container_buildable_add), (gtk_container_buildable_set_child_property), (attributes_start_element), (attributes_text_element), (gtk_container_buildable_custom_tag_start), (gtk_container_buildable_custom_tag_end): * gtk/gtkdebug.h: * gtk/gtkdialog.c: (gtk_dialog_buildable_interface_init), (gtk_dialog_buildable_get_internal_child), (attributes_start_element), (attributes_text_element), (gtk_dialog_buildable_custom_tag_start), (gtk_dialog_buildable_custom_finished): * gtk/gtkentrycompletion.c: (gtk_entry_completion_buildable_init): * gtk/gtkexpander.c: (gtk_expander_buildable_add), (gtk_expander_buildable_init): * gtk/gtkfontsel.c: (gtk_font_selection_dialog_buildable_interface_init), (gtk_font_selection_dialog_buildable_get_internal_child): * gtk/gtkframe.c: (gtk_frame_buildable_init), (gtk_frame_buildable_add): * gtk/gtkiconview.c: (gtk_icon_view_buildable_init), (gtk_icon_view_buildable_custom_tag_start), (gtk_icon_view_buildable_custom_tag_end): * gtk/gtkliststore.c: (gtk_list_store_buildable_init), (list_store_start_element), (list_store_end_element), (list_store_text), (gtk_list_store_buildable_custom_tag_start), (gtk_list_store_buildable_custom_tag_end): * gtk/gtkmain.c: * gtk/gtknotebook.c: (gtk_notebook_buildable_init), (gtk_notebook_buildable_add): * gtk/gtksizegroup.c: (gtk_size_group_buildable_init), (size_group_start_element), (gtk_size_group_buildable_custom_tag_start), (gtk_size_group_buildable_custom_finished): * gtk/gtktreestore.c: (gtk_tree_store_buildable_init), (tree_model_start_element), (gtk_tree_store_buildable_custom_tag_start), (gtk_tree_store_buildable_custom_finished): * gtk/gtktreeview.c: (gtk_tree_view_buildable_init), (gtk_tree_view_buildable_add): * gtk/gtktreeviewcolumn.c: (gtk_tree_view_column_buildable_init): * gtk/gtkuimanager.c: (gtk_ui_manager_buildable_init), (gtk_ui_manager_buildable_add), (gtk_ui_manager_buildable_construct_child), (gtk_ui_manager_buildable_custom_tag_start), (gtk_ui_manager_buildable_custom_tag_end): * gtk/gtkwidget.c: (gtk_widget_get_type), (gtk_widget_buildable_interface_init), (gtk_widget_buildable_set_name), (gtk_widget_buildable_get_name), (gtk_widget_buildable_set_property), (gtk_widget_buildable_parser_finshed), (accel_group_start_element), (gtk_widget_buildable_custom_tag_start), (gtk_widget_buildable_custom_finshed): * gtk/gtkwindow.c: (gtk_window_buildable_interface_init), (gtk_window_buildable_set_property), (gtk_window_buildable_parser_finished): * tests/Makefile.am: * tests/buildertest.c: (builder_new_from_string), (test_parser), (signal_normal), (signal_after), (signal_object), (signal_object_after), (signal_first), (signal_second), (signal_extra), (signal_extra2), (test_connect_signals), (test_uimanager_simple), (test_domain), (test_translation), (test_sizegroup), (test_list_store), (test_tree_store), (test_types), (test_spin_button), (test_notebook), (test_construct_only_property), (test_children), (test_child_properties), (test_treeview_column), (test_icon_view), (test_combo_box), (test_combo_box_entry), (test_cell_view), (test_dialog), (test_accelerators), (test_widget), (main): Add GtkBuilder, fixes #172535 svn path=/trunk/; revision=18141
-rw-r--r--ChangeLog149
-rw-r--r--demos/gtk-demo/Makefile.am7
-rw-r--r--demos/gtk-demo/builder.c60
-rw-r--r--demos/gtk-demo/demo.ui227
-rw-r--r--docs/reference/gtk/gtk-docs.sgml8
-rw-r--r--docs/reference/gtk/gtk-sections.txt67
-rw-r--r--docs/reference/gtk/gtk.types2
-rw-r--r--docs/reference/gtk/tmpl/gtkbuildable.sgml151
-rw-r--r--docs/reference/gtk/tmpl/gtkbuilder.sgml181
-rw-r--r--gtk/Makefile.am6
-rw-r--r--gtk/gtk.h1
-rw-r--r--gtk/gtk.symbols36
-rw-r--r--gtk/gtkaction.c40
-rw-r--r--gtk/gtkactiongroup.c55
-rw-r--r--gtk/gtkbuildable.c372
-rw-r--r--gtk/gtkbuildable.h123
-rw-r--r--gtk/gtkbuilder.c1267
-rw-r--r--gtk/gtkbuilder.h122
-rw-r--r--gtk/gtkbuilderparser.c851
-rw-r--r--gtk/gtkbuilderprivate.h111
-rw-r--r--gtk/gtkcelllayout.c112
-rw-r--r--gtk/gtkcelllayout.h18
-rw-r--r--gtk/gtkcellview.c63
-rw-r--r--gtk/gtkcolorseldialog.c39
-rw-r--r--gtk/gtkcombobox.c60
-rw-r--r--gtk/gtkcomboboxentry.c27
-rw-r--r--gtk/gtkcontainer.c190
-rw-r--r--gtk/gtkdebug.h3
-rw-r--r--gtk/gtkdialog.c172
-rw-r--r--gtk/gtkentrycompletion.c16
-rw-r--r--gtk/gtkexpander.c34
-rw-r--r--gtk/gtkfontsel.c37
-rw-r--r--gtk/gtkframe.c32
-rw-r--r--gtk/gtkiconview.c61
-rw-r--r--gtk/gtkliststore.c276
-rw-r--r--gtk/gtkmain.c5
-rw-r--r--gtk/gtknotebook.c42
-rw-r--r--gtk/gtksizegroup.c123
-rw-r--r--gtk/gtktreestore.c133
-rw-r--r--gtk/gtktreeview.c28
-rw-r--r--gtk/gtktreeviewcolumn.c15
-rw-r--r--gtk/gtkuimanager.c118
-rw-r--r--gtk/gtkwidget.c203
-rw-r--r--gtk/gtkwindow.c50
-rw-r--r--tests/Makefile.am7
-rw-r--r--tests/buildertest.c1462
46 files changed, 7132 insertions, 30 deletions
diff --git a/ChangeLog b/ChangeLog
index 8e9869c709..d97a89f3d1 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,152 @@
+2007-06-15 Johan Dahlin <jdahlin@async.com.br>
+
+ reviewed by: Matthias Clasen
+
+ * demos/gtk-demo/Makefile.am:
+ * demos/gtk-demo/builder.c: (quit_activate), (about_activate),
+ (do_builder):
+ * demos/gtk-demo/demo.ui:
+ * docs/reference/gtk/gtk-docs.sgml:
+ * docs/reference/gtk/gtk-sections.txt:
+ * docs/reference/gtk/gtk.types:
+ * docs/reference/gtk/tmpl/gtkbuildable.sgml:
+ * docs/reference/gtk/tmpl/gtkbuilder.sgml:
+ * gtk/Makefile.am:
+ * gtk/gtk.h:
+ * gtk/gtk.symbols:
+ * gtk/gtkaction.c: (gtk_action_buildable_init),
+ (gtk_action_buildable_set_name), (gtk_action_buildable_get_name):
+ * gtk/gtkactiongroup.c: (gtk_action_group_get_type),
+ (gtk_action_group_buildable_init),
+ (gtk_action_group_buildable_add),
+ (gtk_action_group_buildable_set_name),
+ (gtk_action_group_buildable_get_name):
+ * gtk/gtkbuildable.c: (gtk_buildable_get_type),
+ (gtk_buildable_set_name), (gtk_buildable_get_name),
+ (gtk_buildable_add), (gtk_buildable_set_property),
+ (gtk_buildable_parser_finished), (gtk_buildable_construct_child),
+ (gtk_buildable_custom_tag_start), (gtk_buildable_custom_tag_end),
+ (gtk_buildable_custom_finished),
+ (gtk_buildable_get_internal_child):
+ * gtk/gtkbuildable.h:
+ * gtk/gtkbuilder.c: (gtk_builder_class_init), (gtk_builder_init),
+ (gtk_builder_finalize), (gtk_builder_set_property),
+ (gtk_builder_get_property), (_gtk_builder_resolve_type_lazily),
+ (gtk_builder_real_get_type_from_name),
+ (gtk_builder_get_parameters), (gtk_builder_get_internal_child),
+ (_gtk_builder_construct), (_gtk_builder_add),
+ (apply_delayed_properties), (_gtk_builder_finish),
+ (gtk_builder_new), (gtk_builder_add_from_file),
+ (gtk_builder_add_from_string), (gtk_builder_get_object),
+ (object_add_to_list), (gtk_builder_get_objects),
+ (gtk_builder_set_translation_domain),
+ (gtk_builder_get_translation_domain),
+ (gtk_builder_connect_signals_default),
+ (gtk_builder_connect_signals), (gtk_builder_connect_signals_full),
+ (gtk_builder_value_from_string),
+ (gtk_builder_value_from_string_type),
+ (_gtk_builder_enum_from_string), (_gtk_builder_flags_from_string),
+ (gtk_builder_get_type_from_name), (gtk_builder_error_quark):
+ * gtk/gtkbuilder.h:
+ * gtk/gtkbuilderparser.c: (state_push), (state_peek), (state_pop),
+ (error_missing_attribute), (error_invalid_attribute),
+ (error_invalid_tag), (builder_construct), (parse_object),
+ (free_object_info), (_get_type_by_symbol), (parse_child),
+ (free_child_info), (parse_property), (free_property_info),
+ (parse_signal), (_free_signal_info), (parse_interface),
+ (create_subparser), (free_subparser), (subparser_start),
+ (subparser_end), (parse_custom), (start_element), (end_element),
+ (text), (_gtk_builder_parser_parse_buffer):
+ * gtk/gtkbuilderprivate.h:
+ * gtk/gtkcelllayout.c: (attributes_start_element),
+ (attributes_text_element),
+ (_gtk_cell_layout_buildable_custom_tag_start),
+ (_gtk_cell_layout_buildable_custom_tag_end),
+ (_gtk_cell_layout_buildable_add):
+ * gtk/gtkcelllayout.h:
+ * gtk/gtkcellview.c: (gtk_cell_view_buildable_init),
+ (gtk_cell_view_buildable_custom_tag_start),
+ (gtk_cell_view_buildable_custom_tag_end):
+ * gtk/gtkcolorseldialog.c:
+ (gtk_color_selection_dialog_buildable_interface_init),
+ (gtk_color_selection_dialog_buildable_get_internal_child):
+ * gtk/gtkcombobox.c: (gtk_combo_box_buildable_init),
+ (gtk_combo_box_buildable_custom_tag_start),
+ (gtk_combo_box_buildable_custom_tag_end):
+ * gtk/gtkcomboboxentry.c:
+ (gtk_combo_box_entry_buildable_interface_init),
+ (gtk_combo_box_entry_buildable_get_internal_child):
+ * gtk/gtkcontainer.c: (gtk_container_get_type),
+ (gtk_container_buildable_init), (gtk_container_buildable_add),
+ (gtk_container_buildable_set_child_property),
+ (attributes_start_element), (attributes_text_element),
+ (gtk_container_buildable_custom_tag_start),
+ (gtk_container_buildable_custom_tag_end):
+ * gtk/gtkdebug.h:
+ * gtk/gtkdialog.c: (gtk_dialog_buildable_interface_init),
+ (gtk_dialog_buildable_get_internal_child),
+ (attributes_start_element), (attributes_text_element),
+ (gtk_dialog_buildable_custom_tag_start),
+ (gtk_dialog_buildable_custom_finished):
+ * gtk/gtkentrycompletion.c: (gtk_entry_completion_buildable_init):
+ * gtk/gtkexpander.c: (gtk_expander_buildable_add),
+ (gtk_expander_buildable_init):
+ * gtk/gtkfontsel.c:
+ (gtk_font_selection_dialog_buildable_interface_init),
+ (gtk_font_selection_dialog_buildable_get_internal_child):
+ * gtk/gtkframe.c: (gtk_frame_buildable_init),
+ (gtk_frame_buildable_add):
+ * gtk/gtkiconview.c: (gtk_icon_view_buildable_init),
+ (gtk_icon_view_buildable_custom_tag_start),
+ (gtk_icon_view_buildable_custom_tag_end):
+ * gtk/gtkliststore.c: (gtk_list_store_buildable_init),
+ (list_store_start_element), (list_store_end_element),
+ (list_store_text), (gtk_list_store_buildable_custom_tag_start),
+ (gtk_list_store_buildable_custom_tag_end):
+ * gtk/gtkmain.c:
+ * gtk/gtknotebook.c: (gtk_notebook_buildable_init),
+ (gtk_notebook_buildable_add):
+ * gtk/gtksizegroup.c: (gtk_size_group_buildable_init),
+ (size_group_start_element),
+ (gtk_size_group_buildable_custom_tag_start),
+ (gtk_size_group_buildable_custom_finished):
+ * gtk/gtktreestore.c: (gtk_tree_store_buildable_init),
+ (tree_model_start_element),
+ (gtk_tree_store_buildable_custom_tag_start),
+ (gtk_tree_store_buildable_custom_finished):
+ * gtk/gtktreeview.c: (gtk_tree_view_buildable_init),
+ (gtk_tree_view_buildable_add):
+ * gtk/gtktreeviewcolumn.c: (gtk_tree_view_column_buildable_init):
+ * gtk/gtkuimanager.c: (gtk_ui_manager_buildable_init),
+ (gtk_ui_manager_buildable_add),
+ (gtk_ui_manager_buildable_construct_child),
+ (gtk_ui_manager_buildable_custom_tag_start),
+ (gtk_ui_manager_buildable_custom_tag_end):
+ * gtk/gtkwidget.c: (gtk_widget_get_type),
+ (gtk_widget_buildable_interface_init),
+ (gtk_widget_buildable_set_name), (gtk_widget_buildable_get_name),
+ (gtk_widget_buildable_set_property),
+ (gtk_widget_buildable_parser_finshed), (accel_group_start_element),
+ (gtk_widget_buildable_custom_tag_start),
+ (gtk_widget_buildable_custom_finshed):
+ * gtk/gtkwindow.c: (gtk_window_buildable_interface_init),
+ (gtk_window_buildable_set_property),
+ (gtk_window_buildable_parser_finished):
+ * tests/Makefile.am:
+ * tests/buildertest.c: (builder_new_from_string), (test_parser),
+ (signal_normal), (signal_after), (signal_object),
+ (signal_object_after), (signal_first), (signal_second),
+ (signal_extra), (signal_extra2), (test_connect_signals),
+ (test_uimanager_simple), (test_domain), (test_translation),
+ (test_sizegroup), (test_list_store), (test_tree_store),
+ (test_types), (test_spin_button), (test_notebook),
+ (test_construct_only_property), (test_children),
+ (test_child_properties), (test_treeview_column), (test_icon_view),
+ (test_combo_box), (test_combo_box_entry), (test_cell_view),
+ (test_dialog), (test_accelerators), (test_widget), (main):
+
+ Add GtkBuilder, fixes #172535
+
2007-06-15 Hans Breuer <hans@breuer.org>
* gtk/makefile.msc.in tests/makefile.msc : updated
diff --git a/demos/gtk-demo/Makefile.am b/demos/gtk-demo/Makefile.am
index f043ee0f4e..ccd941a0b8 100644
--- a/demos/gtk-demo/Makefile.am
+++ b/demos/gtk-demo/Makefile.am
@@ -7,6 +7,7 @@ democodedir=$(datadir)/gtk-2.0/demo
demos = \
appwindow.c \
assistant.c \
+ builder.c \
button_box.c \
changedisplay.c \
clipboard.c \
@@ -60,7 +61,8 @@ bin_PROGRAMS = gtk-demo
BUILT_SOURCES = demos.h
EXTRA_DIST = \
- $(IMAGEFILES)
+ $(IMAGEFILES) \
+ demo.ui
demos.h: @REBUILD@ $(demos) geninclude.pl
(here=`pwd` ; cd $(srcdir) && $(PERL) $$here/geninclude.pl $(demos)) > demos.h
@@ -73,6 +75,7 @@ gtk_demo_SOURCES = \
gtk_demo_DEPENDENCIES = $(DEPS)
gtk_demo_LDADD = $(LDADDS)
+gtk_demo_LDFLAGS = -export-dynamic
IMAGEFILES= alphatest.png \
apple-red.png \
@@ -89,6 +92,6 @@ IMAGEFILES= alphatest.png \
gnu-keys.png \
gtk-logo-rgb.gif
-democode_DATA = $(demos) $(IMAGEFILES)
+democode_DATA = $(demos) $(IMAGEFILES) demo.ui
DISTCLEANFILES = demos.h
diff --git a/demos/gtk-demo/builder.c b/demos/gtk-demo/builder.c
new file mode 100644
index 0000000000..3363969945
--- /dev/null
+++ b/demos/gtk-demo/builder.c
@@ -0,0 +1,60 @@
+/* Builder
+ *
+ * Demonstrates an interface loaded from a XML description.
+ */
+
+#include <gtk/gtk.h>
+#include "demo-common.h"
+
+void
+quit_activate (GtkAction *action)
+{
+}
+
+void
+about_activate (GtkAction *action)
+{
+ GtkWidget *about_dlg;
+
+ about_dlg = gtk_about_dialog_new ();
+ gtk_about_dialog_set_name (GTK_ABOUT_DIALOG (about_dlg), "GtkBuilder demo");
+ gtk_dialog_run (GTK_DIALOG (about_dlg));
+ gtk_widget_destroy (about_dlg);
+}
+
+GtkWidget *
+do_builder (GtkWidget *do_widget)
+{
+ static GtkWidget *window = NULL;
+ GtkBuilder *builder;
+ GError *err = NULL;
+ gchar *filename;
+
+ if (!window)
+ {
+ builder = gtk_builder_new ();
+ filename = demo_find_file ("demo.ui", NULL);
+ gtk_builder_add_from_file (builder, filename, &err);
+ g_free (filename);
+ if (err)
+ {
+ g_error ("ERROR: %s\n", err->message);
+ return NULL;
+ }
+ gtk_builder_connect_signals (builder, NULL);
+ window = GTK_WIDGET (gtk_builder_get_object (builder, "window1"));
+ }
+
+ if (!GTK_WIDGET_VISIBLE (window))
+ {
+ gtk_widget_show_all (window);
+ }
+ else
+ {
+ gtk_widget_destroy (window);
+ window = NULL;
+ }
+
+
+ return window;
+}
diff --git a/demos/gtk-demo/demo.ui b/demos/gtk-demo/demo.ui
new file mode 100644
index 0000000000..9830ed96c8
--- /dev/null
+++ b/demos/gtk-demo/demo.ui
@@ -0,0 +1,227 @@
+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
+<interface>
+ <object class="GtkListStore" id="liststore1">
+ <columns>
+ <column type="gchararray"/>
+ <column type="gchararray"/>
+ <column type="gint"/>
+ </columns>
+ <data>
+ <row>
+ <col id="0">John</col>
+ <col id="1">Doe</col>
+ <col id="2">25</col>
+ </row>
+ <row>
+ <col id="0">Mary</col>
+ <col id="1">Dole</col>
+ <col id="2">50</col>
+ </row>
+ </data>
+ </object>
+ <object class="GtkUIManager" id="uimanager">
+ <child>
+ <object class="GtkActionGroup" id="DefaultActions">
+ <child>
+ <object class="GtkAction" id="Copy">
+ <property name="name">Copy</property>
+ <property name="tooltip" translatable="yes">Copy selected object into the clipboard</property>
+ <property name="stock_id">gtk-copy</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkAction" id="Cut">
+ <property name="name">Cut</property>
+ <property name="tooltip" translatable="yes">Cut selected object into the clipboard</property>
+ <property name="stock_id">gtk-cut</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkAction" id="EditMenu">
+ <property name="name">EditMenu</property>
+ <property name="label" translatable="yes">_Edit</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkAction" id="FileMenu">
+ <property name="name">FileMenu</property>
+ <property name="label" translatable="yes">_File</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkAction" id="New">
+ <property name="name">New</property>
+ <property name="tooltip" translatable="yes">Create a new file</property>
+ <property name="stock_id">gtk-new</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkAction" id="Open">
+ <property name="name">Open</property>
+ <property name="tooltip" translatable="yes">Open a file</property>
+ <property name="stock_id">gtk-open</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkAction" id="Paste">
+ <property name="name">Paste</property>
+ <property name="tooltip" translatable="yes">Paste object from the Clipboard</property>
+ <property name="stock_id">gtk-paste</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkAction" id="Quit">
+ <property name="name">Quit</property>
+ <property name="tooltip" translatable="yes">Quit the program</property>
+ <property name="stock_id">gtk-quit</property>
+ <signal handler="quit_activate" name="activate"/>
+ </object>
+ </child>
+ <child>
+ <object class="GtkAction" id="Save">
+ <property name="name">Save</property>
+ <property name="is_important">True</property>
+ <property name="tooltip" translatable="yes">Save a file</property>
+ <property name="stock_id">gtk-save</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkAction" id="SaveAs">
+ <property name="name">SaveAs</property>
+ <property name="tooltip" translatable="yes">Save with a different name</property>
+ <property name="stock_id">gtk-save-as</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkAction" id="HelpMenu">
+ <property name="name">Help</property>
+ <property name="label" translatable="yes">_Help</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkAction" id="About">
+ <property name="name">About</property>
+ <property name="stock_id">gtk-about</property>
+ <signal handler="about_activate" name="activate"/>
+ </object>
+ </child>
+ </object>
+ </child>
+ <ui>
+ <menubar name="menubar1">
+ <menu action="FileMenu" name="FileMenu">
+ <menuitem action="New" name="New"/>
+ <menuitem action="Open" name="Open"/>
+ <menuitem action="Save" name="Save"/>
+ <menuitem action="SaveAs" name="SaveAs"/>
+ <separator/>
+ <menuitem action="Quit" name="Quit"/>
+ </menu>
+ <menu action="EditMenu">
+ <menuitem action="Copy" name="Copy"/>
+ <menuitem action="Cut" name="Cut"/>
+ <menuitem action="Paste" name="Paste"/>
+ </menu>
+ <menu action="HelpMenu" name="HelpMenu">
+ <menuitem action="About" name="About"/>
+ </menu>
+ </menubar>
+ <toolbar name="toolbar1">
+ <toolitem action="New" name="New"/>
+ <toolitem action="Open" name="Open"/>
+ <toolitem action="Save" name="Save"/>
+ <separator/>
+ <toolitem action="Copy" name="Copy"/>
+ <toolitem action="Cut" name="Cut"/>
+ <toolitem action="Paste" name="Paste"/>
+ </toolbar>
+ </ui>
+ </object>
+
+ <object class="GtkWindow" id="window1">
+ <property name="default_height">250</property>
+ <property name="default_width">440</property>
+ <signal name="destroy" handler="gtk_widget_destroyed"/>
+ <child>
+ <object class="GtkVBox" id="vbox1">
+ <property name="visible">True</property>
+ <child>
+ <object constructor="uimanager" class="GtkMenuBar" id="menubar1">
+ <property name="visible">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ <child>
+ <object constructor="uimanager" class="GtkToolbar" id="toolbar1">
+ <property name="visible">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow" id="scrolledwindow1">
+ <property name="hscrollbar_policy">automatic</property>
+ <property name="shadow_type">in</property>
+ <property name="visible">True</property>
+ <property name="vscrollbar_policy">automatic</property>
+ <child>
+ <object class="GtkTreeView" id="treeview1">
+ <property name="visible">True</property>
+ <property name="model">liststore1</property>
+ <child>
+ <object class="GtkTreeViewColumn" id="column1">
+ <property name="title">Name</property>
+ <child>
+ <object class="GtkCellRendererText" id="renderer1"/>
+ <attributes>
+ <attribute name="text">0</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn" id="column2">
+ <property name="title">Surname</property>
+ <child>
+ <object class="GtkCellRendererText" id="renderer2"/>
+ <attributes>
+ <attribute name="text">1</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn" id="column3">
+ <property name="title">Age</property>
+ <child>
+ <object class="GtkCellRendererText" id="renderer3"/>
+ <attributes>
+ <attribute name="text">2</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkStatusbar" id="statusbar1">
+ <property name="visible">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/docs/reference/gtk/gtk-docs.sgml b/docs/reference/gtk/gtk-docs.sgml
index dfa7bd4cda..f50d843836 100644
--- a/docs/reference/gtk/gtk-docs.sgml
+++ b/docs/reference/gtk/gtk-docs.sgml
@@ -14,6 +14,8 @@
<!ENTITY GtkBin SYSTEM "xml/gtkbin.xml">
<!ENTITY GtkBox SYSTEM "xml/gtkbox.xml">
<!ENTITY GtkButton SYSTEM "xml/gtkbutton.xml">
+<!ENTITY GtkBuildable SYSTEM "xml/gtkbuildable.xml">
+<!ENTITY GtkBuilder SYSTEM "xml/gtkbuilder.xml">
<!ENTITY GtkCalendar SYSTEM "xml/gtkcalendar.xml">
<!ENTITY GtkCheckButton SYSTEM "xml/gtkcheckbutton.xml">
<!ENTITY GtkCheckMenuItem SYSTEM "xml/gtkcheckmenuitem.xml">
@@ -588,6 +590,12 @@ that is, GUI components such as #GtkButton or #GtkTextView.
&GtkRecentFilter;
</chapter>
+ <chapter id="Builder">
+ <title>Interface builder</title>
+ &GtkBuildable;
+ &GtkBuilder;
+ </chapter>
+
<chapter id="DeprecatedObjects">
<title>Deprecated</title>
&GtkCList;
diff --git a/docs/reference/gtk/gtk-sections.txt b/docs/reference/gtk/gtk-sections.txt
index 5aed8ff235..b41ab7e3b2 100644
--- a/docs/reference/gtk/gtk-sections.txt
+++ b/docs/reference/gtk/gtk-sections.txt
@@ -432,6 +432,73 @@ gtk_box_get_type
</SECTION>
<SECTION>
+<FILE>gtkvscrollbar</FILE>
+<TITLE>GtkVScrollbar</TITLE>
+GtkVScrollbar
+gtk_vscrollbar_new
+<SUBSECTION Standard>
+GTK_VSCROLLBAR
+GTK_IS_VSCROLLBAR
+GTK_TYPE_VSCROLLBAR
+gtk_vscrollbar_get_type
+GTK_VSCROLLBAR_CLASS
+GTK_IS_VSCROLLBAR_CLASS
+GTK_VSCROLLBAR_GET_CLASS
+</SECTION>
+
+<SECTION>
+<FILE>gtkbuildable</FILE>
+GtkBuildable
+GtkBuildableIface
+gtk_buildable_set_name
+gtk_buildable_get_name
+gtk_buildable_add
+gtk_buildable_set_property
+gtk_buildable_construct_child
+gtk_buildable_custom_tag_start
+gtk_buildable_custom_tag_end
+gtk_buildable_custom_finished
+gtk_buildable_parser_finished
+gtk_buildable_get_internal_child
+<SUBSECTION Standard>
+GTK_BUILDABLE
+GTK_IS_BUILDABLE
+GTK_TYPE_BUILDABLE
+gtk_buildable_get_type
+GTK_BUILDABLE_CLASS
+GTK_BUILDABLE_GET_IFACE
+</SECTION>
+
+<SECTION>
+<FILE>gtkbuilder</FILE>
+<TITLE>GtkBuilder</TITLE>
+GtkBuilder
+GtkBuilderConnectFunc
+gtk_builder_new
+gtk_builder_add_from_file
+gtk_builder_add_from_string
+gtk_builder_get_object
+gtk_builder_get_objects
+gtk_builder_connect_signals
+gtk_builder_connect_signals_full
+gtk_builder_set_translation_domain
+gtk_builder_get_translation_domain
+gtk_builder_get_type_from_name
+gtk_builder_value_from_string
+gtk_builder_value_from_string_type
+GTK_BUILDER_WARN_INVALID_CHILD_TYPE
+<SUBSECTION Standard>
+GTK_BUILDER
+GTK_IS_BUILDER
+GTK_TYPE_BUILDER
+GTK_BUILDER_CLASS
+GTK_IS_BUILDER_CLASS
+GTK_BUILDER_GET_CLASS
+<SUBSECTION Private>
+gtk_builder_get_type
+</SECTION>
+
+<SECTION>
<FILE>gtkbutton</FILE>
<TITLE>GtkButton</TITLE>
GtkButton
diff --git a/docs/reference/gtk/gtk.types b/docs/reference/gtk/gtk.types
index 5ad47ff551..fde19eae17 100644
--- a/docs/reference/gtk/gtk.types
+++ b/docs/reference/gtk/gtk.types
@@ -18,6 +18,8 @@ gtk_aspect_frame_get_type
gtk_assistant_get_type
gtk_bin_get_type
gtk_box_get_type
+gtk_builder_get_type
+gtk_buildable_get_type
gtk_button_box_get_type
gtk_button_get_type
gtk_calendar_get_type
diff --git a/docs/reference/gtk/tmpl/gtkbuildable.sgml b/docs/reference/gtk/tmpl/gtkbuildable.sgml
new file mode 100644
index 0000000000..8080455758
--- /dev/null
+++ b/docs/reference/gtk/tmpl/gtkbuildable.sgml
@@ -0,0 +1,151 @@
+<!-- ##### SECTION Title ##### -->
+GtkBuildable
+
+<!-- ##### SECTION Short_Description ##### -->
+SHORT
+
+<!-- ##### SECTION Long_Description ##### -->
+<para>
+LONG
+</para>
+
+<!-- ##### SECTION See_Also ##### -->
+<para>
+SEE ALSO
+</para>
+
+<!-- ##### SECTION Stability_Level ##### -->
+
+
+<!-- ##### STRUCT GtkBuildable ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### STRUCT GtkBuildableIface ##### -->
+<para>
+
+</para>
+
+@g_iface:
+@set_name:
+@get_name:
+@add:
+@set_property:
+@construct_child:
+@custom_tag_start:
+@custom_tag_end:
+@custom_finished:
+@parser_finished:
+@get_internal_child:
+
+<!-- ##### FUNCTION gtk_buildable_set_name ##### -->
+<para>
+
+</para>
+
+@buildable:
+@name:
+
+
+<!-- ##### FUNCTION gtk_buildable_get_name ##### -->
+<para>
+
+</para>
+
+@buildable:
+@Returns:
+
+
+<!-- ##### FUNCTION gtk_buildable_add ##### -->
+<para>
+
+</para>
+
+@buildable:
+@builder:
+@child:
+@type:
+
+
+<!-- ##### FUNCTION gtk_buildable_set_property ##### -->
+<para>
+
+</para>
+
+@buildable:
+@builder:
+@name:
+@value:
+
+
+<!-- ##### FUNCTION gtk_buildable_construct_child ##### -->
+<para>
+
+</para>
+
+@buildable:
+@builder:
+@name:
+@Returns:
+
+
+<!-- ##### FUNCTION gtk_buildable_custom_tag_start ##### -->
+<para>
+
+</para>
+
+@buildable:
+@builder:
+@child:
+@tagname:
+@parser:
+@data:
+@Returns:
+
+
+<!-- ##### FUNCTION gtk_buildable_custom_tag_end ##### -->
+<para>
+
+</para>
+
+@buildable:
+@builder:
+@child:
+@tagname:
+@data:
+
+
+<!-- ##### FUNCTION gtk_buildable_custom_finished ##### -->
+<para>
+
+</para>
+
+@buildable:
+@builder:
+@child:
+@tagname:
+@data:
+
+
+<!-- ##### FUNCTION gtk_buildable_parser_finished ##### -->
+<para>
+
+</para>
+
+@buildable:
+@builder:
+
+
+<!-- ##### FUNCTION gtk_buildable_get_internal_child ##### -->
+<para>
+
+</para>
+
+@buildable:
+@builder:
+@childname:
+@Returns:
+
+
diff --git a/docs/reference/gtk/tmpl/gtkbuilder.sgml b/docs/reference/gtk/tmpl/gtkbuilder.sgml
new file mode 100644
index 0000000000..34b8a2da88
--- /dev/null
+++ b/docs/reference/gtk/tmpl/gtkbuilder.sgml
@@ -0,0 +1,181 @@
+<!-- ##### SECTION Title ##### -->
+GtkBuilder
+
+<!-- ##### SECTION Short_Description ##### -->
+Build an interface from a UI definition description.
+
+<!-- ##### SECTION Long_Description ##### -->
+<para>
+This object represents an `instantiation' of an UI definition description.
+When one of these objects is created, the XML file is read, and the
+interface is created. The GtkBuilder object then provides an interface
+for accessing the widgets in the interface by the names assigned to
+them inside the UI description.
+
+The GtkBuilder object can also be used to connect handlers to the named
+signals in the description. GtkBuilder also provides an interface by
+which it can look up the signal handler names in the program's symbol
+table and automatically connect as many handlers up as it can that way.
+</para>
+
+<!-- ##### SECTION See_Also ##### -->
+<para>
+SEE ALSO
+</para>
+
+<!-- ##### SECTION Stability_Level ##### -->
+
+
+<!-- ##### STRUCT GtkBuilder ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### ARG GtkBuilder:translation-domain ##### -->
+<para>
+
+</para>
+
+<!-- ##### USER_FUNCTION GtkBuilderConnectFunc ##### -->
+<para>
+
+</para>
+
+@builder:
+@object:
+@signal_name:
+@handler_name:
+@connect_object:
+@flags:
+@user_data:
+
+
+<!-- ##### FUNCTION gtk_builder_new ##### -->
+<para>
+
+</para>
+
+@Returns:
+
+
+<!-- ##### FUNCTION gtk_builder_add_from_file ##### -->
+<para>
+
+</para>
+
+@builder:
+@filename:
+@error:
+@Returns:
+
+
+<!-- ##### FUNCTION gtk_builder_add_from_string ##### -->
+<para>
+
+</para>
+
+@builder:
+@buffer:
+@length:
+@error:
+@Returns:
+
+
+<!-- ##### FUNCTION gtk_builder_get_object ##### -->
+<para>
+
+</para>
+
+@builder:
+@name:
+@Returns:
+
+
+<!-- ##### FUNCTION gtk_builder_get_objects ##### -->
+<para>
+
+</para>
+
+@builder:
+@Returns:
+
+
+<!-- ##### FUNCTION gtk_builder_connect_signals ##### -->
+<para>
+
+</para>
+
+@builder:
+@user_data:
+
+
+<!-- ##### FUNCTION gtk_builder_connect_signals_full ##### -->
+<para>
+
+</para>
+
+@builder:
+@func:
+@user_data:
+
+
+<!-- ##### FUNCTION gtk_builder_set_translation_domain ##### -->
+<para>
+
+</para>
+
+@builder:
+@domain:
+
+
+<!-- ##### FUNCTION gtk_builder_get_translation_domain ##### -->
+<para>
+
+</para>
+
+@builder:
+@Returns:
+
+
+<!-- ##### FUNCTION gtk_builder_get_type_from_name ##### -->
+<para>
+
+</para>
+
+@builder:
+@typename:
+@Returns:
+
+
+<!-- ##### FUNCTION gtk_builder_value_from_string ##### -->
+<para>
+
+</para>
+
+@pspec:
+@string:
+@value:
+@Returns:
+
+
+<!-- ##### FUNCTION gtk_builder_value_from_string_type ##### -->
+<para>
+
+</para>
+
+@type:
+@string:
+@value:
+@Returns:
+
+
+<!-- ##### MACRO GTK_BUILDER_WARN_INVALID_CHILD_TYPE ##### -->
+<para>
+
+</para>
+
+@object:
+@type:
+
+
diff --git a/gtk/Makefile.am b/gtk/Makefile.am
index a1acb56cdc..92a78b8537 100644
--- a/gtk/Makefile.am
+++ b/gtk/Makefile.am
@@ -143,6 +143,9 @@ gtk_public_h_sources = \
gtkbin.h \
gtkbindings.h \
gtkbox.h \
+ gtkbuilder.h \
+ gtkbuildable.h \
+ gtkbuilderprivate.h \
gtkbutton.h \
gtkcalendar.h \
gtkcelleditable.h \
@@ -405,6 +408,9 @@ gtk_base_c_sources = \
gtkbin.c \
gtkbindings.c \
gtkbox.c \
+ gtkbuildable.c \
+ gtkbuilder.c \
+ gtkbuilderparser.c \
gtkbutton.c \
gtkcalendar.c \
gtkcelleditable.c \
diff --git a/gtk/gtk.h b/gtk/gtk.h
index 1e9436fb5f..70f04b7984 100644
--- a/gtk/gtk.h
+++ b/gtk/gtk.h
@@ -45,6 +45,7 @@
#include <gtk/gtkbin.h>
#include <gtk/gtkbindings.h>
#include <gtk/gtkbox.h>
+#include <gtk/gtkbuildable.h>
#include <gtk/gtkbutton.h>
#include <gtk/gtkcalendar.h>
#include <gtk/gtkcelllayout.h>
diff --git a/gtk/gtk.symbols b/gtk/gtk.symbols
index 4cff2b5640..0ad3de6148 100644
--- a/gtk/gtk.symbols
+++ b/gtk/gtk.symbols
@@ -254,6 +254,7 @@ gtk_arg_flags_get_type G_GNUC_CONST
gtk_arrow_type_get_type G_GNUC_CONST
gtk_assistant_page_type_get_type G_GNUC_CONST
gtk_attach_options_get_type G_GNUC_CONST
+gtk_builder_error_get_type G_GNUC_CONST
gtk_button_action_get_type G_GNUC_CONST
gtk_buttons_type_get_type G_GNUC_CONST
gtk_calendar_display_options_get_type G_GNUC_CONST
@@ -420,6 +421,41 @@ gtk_box_set_spacing
#endif
#endif
+#if IN_HEADER(__GTK_BUILDABLE_H__)
+#if IN_FILE(__GTK_BUILDABLE_C__)
+gtk_buildable_add
+gtk_buildable_construct_child
+gtk_buildable_custom_tag_start
+gtk_buildable_custom_tag_end
+gtk_buildable_custom_finished
+gtk_buildable_get_internal_child
+gtk_buildable_get_name
+gtk_buildable_get_type G_GNUC_CONST
+gtk_buildable_parser_finished
+gtk_buildable_set_name
+gtk_buildable_set_property
+#endif
+#endif
+
+#if IN_HEADER(__GTK_BUILDER_H__)
+#if IN_FILE(__GTK_BUILDER_C__)
+gtk_builder_add_from_file
+gtk_builder_add_from_string
+gtk_builder_error_quark
+gtk_builder_get_object
+gtk_builder_get_objects
+gtk_builder_get_translation_domain
+gtk_builder_get_type G_GNUC_CONST
+gtk_builder_get_type_from_name
+gtk_builder_new
+gtk_builder_set_translation_domain
+gtk_builder_connect_signals
+gtk_builder_connect_signals_full
+gtk_builder_value_from_string
+gtk_builder_value_from_string_type
+#endif
+#endif
+
#if IN_HEADER(__GTK_BUTTON_BOX_H__)
#if IN_FILE(__GTK_BUTTON_BOX_C__)
#ifndef GTK_DISABLE_DEPRECATED
diff --git a/gtk/gtkaction.c b/gtk/gtkaction.c
index eb8173ef8b..f1b161820e 100644
--- a/gtk/gtkaction.c
+++ b/gtk/gtkaction.c
@@ -46,6 +46,7 @@
#include "gtktoolbutton.h"
#include "gtktoolbar.h"
#include "gtkprivate.h"
+#include "gtkbuildable.h"
#include "gtkalias.h"
@@ -107,14 +108,22 @@ enum
PROP_ACTION_GROUP
};
+/* GtkBuildable */
+static void gtk_action_buildable_init (GtkBuildableIface *iface);
+static void gtk_action_buildable_set_name (GtkBuildable *buildable,
+ const gchar *name);
+static const gchar* gtk_action_buildable_get_name (GtkBuildable *buildable);
+
+G_DEFINE_TYPE_WITH_CODE (GtkAction, gtk_action, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
+ gtk_action_buildable_init))
+
static GQuark accel_path_id = 0;
static GQuark quark_gtk_action_proxy = 0;
static const gchar accel_path_key[] = "GtkAction::accel_path";
static const gchar gtk_action_proxy_key[] = "gtk-action";
-G_DEFINE_TYPE (GtkAction, gtk_action, G_TYPE_OBJECT)
-
static void gtk_action_finalize (GObject *object);
static void gtk_action_set_property (GObject *object,
guint prop_id,
@@ -378,6 +387,33 @@ gtk_action_init (GtkAction *action)
action->private_data->proxies = NULL;
}
+static void
+gtk_action_buildable_init (GtkBuildableIface *iface)
+{
+ iface->set_name = gtk_action_buildable_set_name;
+ iface->get_name = gtk_action_buildable_get_name;
+}
+
+static void
+gtk_action_buildable_set_name (GtkBuildable *buildable,
+ const gchar *name)
+{
+ gchar *tmp;
+ GtkAction *action = GTK_ACTION (buildable);
+
+ tmp = action->private_data->name;
+ action->private_data->name = g_strdup (name);
+ g_free (tmp);
+}
+
+static const gchar *
+gtk_action_buildable_get_name (GtkBuildable *buildable)
+{
+ GtkAction *action = GTK_ACTION (buildable);
+
+ return action->private_data->name;
+}
+
/**
* gtk_action_new:
* @name: A unique name for the action
diff --git a/gtk/gtkactiongroup.c b/gtk/gtkactiongroup.c
index 26243f3197..c976b46e11 100644
--- a/gtk/gtkactiongroup.c
+++ b/gtk/gtkactiongroup.c
@@ -31,6 +31,7 @@
#include <config.h>
#include "gtkactiongroup.h"
+#include "gtkbuildable.h"
#include "gtkiconfactory.h"
#include "gtkicontheme.h"
#include "gtkstock.h"
@@ -87,6 +88,15 @@ static void gtk_action_group_get_property (GObject *object,
static GtkAction *gtk_action_group_real_get_action (GtkActionGroup *self,
const gchar *name);
+/* GtkBuildable */
+static void gtk_action_group_buildable_init (GtkBuildableIface *iface);
+static void gtk_action_group_buildable_add (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *type);
+static void gtk_action_group_buildable_set_name (GtkBuildable *buildable,
+ const gchar *name);
+static const gchar* gtk_action_group_buildable_get_name (GtkBuildable *buildable);
GType
gtk_action_group_get_type (void)
@@ -108,10 +118,20 @@ gtk_action_group_get_type (void)
(GInstanceInitFunc) gtk_action_group_init,
};
+ static const GInterfaceInfo buildable_info =
+ {
+ (GInterfaceInitFunc) gtk_action_group_buildable_init,
+ NULL,
+ NULL
+ };
+
type = g_type_register_static (G_TYPE_OBJECT, I_("GtkActionGroup"),
&type_info, 0);
- }
+ g_type_add_interface_static (type,
+ GTK_TYPE_BUILDABLE,
+ &buildable_info);
+ }
return type;
}
@@ -272,6 +292,39 @@ gtk_action_group_init (GtkActionGroup *self)
self->private_data->translate_notify = NULL;
}
+static void
+gtk_action_group_buildable_init (GtkBuildableIface *iface)
+{
+ iface->add = gtk_action_group_buildable_add;
+ iface->set_name = gtk_action_group_buildable_set_name;
+ iface->get_name = gtk_action_group_buildable_get_name;
+}
+
+static void
+gtk_action_group_buildable_add (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *type)
+{
+ gtk_action_group_add_action (GTK_ACTION_GROUP (buildable),
+ GTK_ACTION (child));
+}
+
+static void
+gtk_action_group_buildable_set_name (GtkBuildable *buildable,
+ const gchar *name)
+{
+ GtkActionGroup *self = GTK_ACTION_GROUP (buildable);
+ self->private_data->name = g_strdup (name);
+}
+
+static const gchar *
+gtk_action_group_buildable_get_name (GtkBuildable *buildable)
+{
+ GtkActionGroup *self = GTK_ACTION_GROUP (buildable);
+ return self->private_data->name;
+}
+
/**
* gtk_action_group_new:
* @name: the name of the action group.
diff --git a/gtk/gtkbuildable.c b/gtk/gtkbuildable.c
new file mode 100644
index 0000000000..ee3934ec27
--- /dev/null
+++ b/gtk/gtkbuildable.c
@@ -0,0 +1,372 @@
+/* gtkbuildable.c
+ * Copyright (C) 2006-2007 Async Open Source,
+ * Johan Dahlin <jdahlin@async.com.br>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+#include <config.h>
+#include "gtkbuildable.h"
+#include "gtktypeutils.h"
+#include "gtkintl.h"
+#include "gtkalias.h"
+
+GType
+gtk_buildable_get_type (void)
+{
+ static GType buildable_type = 0;
+
+ if (!buildable_type)
+ buildable_type =
+ g_type_register_static_simple (G_TYPE_INTERFACE, I_("GtkBuildable"),
+ sizeof (GtkBuildableIface),
+ NULL, 0, NULL, 0);
+
+ return buildable_type;
+}
+
+/**
+ * gtk_buildable_set_name:
+ * @buildable: a #GtkBuildable
+ * @name: name to set
+ *
+ * Sets the name of the buildable object, it's used to synchronize the name
+ * if the object already has it's own concept of name.
+ *
+ * #GtkWidget implements this to map the buildable name to the widget name
+ *
+ * Since: 2.12
+ **/
+void
+gtk_buildable_set_name (GtkBuildable *buildable,
+ const gchar *name)
+{
+ GtkBuildableIface *iface;
+
+ g_return_if_fail (GTK_IS_BUILDABLE (buildable));
+ g_return_if_fail (name != NULL);
+
+ iface = GTK_BUILDABLE_GET_IFACE (buildable);
+
+ if (iface->set_name)
+ (* iface->set_name) (buildable, name);
+ else
+ g_object_set_data_full (G_OBJECT (buildable),
+ "gtk-builder-name",
+ g_strdup (name),
+ g_free);
+}
+
+/**
+ * gtk_buildable_get_name:
+ * @buildable: a #GtkBuildable
+ *
+ * Returns: the buildable name, the name which was set in
+ * the <link linkend="BUILDER-UI">GtkBuilder UI definition</link> used to
+ * construct the @buildable.
+ *
+ * #GtkWidget implements this to map the buildable name to the widget name
+ *
+ * Since: 2.12
+ **/
+const gchar *
+gtk_buildable_get_name (GtkBuildable *buildable)
+{
+ GtkBuildableIface *iface;
+
+ g_return_val_if_fail (GTK_IS_BUILDABLE (buildable), NULL);
+
+ iface = GTK_BUILDABLE_GET_IFACE (buildable);
+
+ if (iface->get_name)
+ return (* iface->get_name) (buildable);
+ else
+ return (const gchar*)g_object_get_data (G_OBJECT (buildable),
+ "gtk-builder-name");
+}
+
+/**
+ * gtk_buildable_add:
+ * @buildable: a #GtkBuildable
+ * @builder: a #GtkBuilder
+ * @child: child to add
+ * @type: kind of child or %NULL
+ *
+ * Add a child to a buildable. type is an optional string
+ * describing how the child should be added.
+ *
+ * #GtkContainer implements this to be able to add a child widget
+ * to the container. #GtkNotebook uses the @type to distinguish between
+ * page labels (@type = "page-label") and normal children.
+ *
+ * Since: 2.12
+ **/
+void
+gtk_buildable_add (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *type)
+{
+ GtkBuildableIface *iface;
+
+ g_return_if_fail (GTK_IS_BUILDABLE (buildable));
+ g_return_if_fail (GTK_IS_BUILDER (builder));
+
+ iface = GTK_BUILDABLE_GET_IFACE (buildable);
+ g_return_if_fail (iface->add != NULL);
+
+ (* iface->add) (buildable, builder, child, type);
+}
+
+/**
+ * gtk_buildable_set_property:
+ * @buildable: a #GtkBuildable
+ * @builder: a #GtkBuilder
+ * @name: name of property
+ * @value: value of property
+ *
+ * Sets the property name @name to @value on the buildable object @buildable
+ * which is created by the @builder.
+ *
+ * This is optional to implement and is normally not needed.
+ * g_object_set_property() is used as a fallback.
+ *
+ * #GtkWindow implements this to delay showing (::visible) itself until
+ * the whole interface is fully created.
+ *
+ * Since: 2.12
+ **/
+void
+gtk_buildable_set_property (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ const gchar *name,
+ const GValue *value)
+{
+ GtkBuildableIface *iface;
+
+ g_return_if_fail (GTK_IS_BUILDABLE (buildable));
+ g_return_if_fail (GTK_IS_BUILDER (builder));
+ g_return_if_fail (name != NULL);
+ g_return_if_fail (value != NULL);
+
+ iface = GTK_BUILDABLE_GET_IFACE (buildable);
+ if (iface->set_property)
+ (* iface->set_property) (buildable, builder, name, value);
+ else
+ g_object_set_property (G_OBJECT (buildable), name, value);
+}
+
+/**
+ * gtk_buildable_parser_finished:
+ * @buildable: a #GtkBuildable
+ * @builder: a #GtkBuilder
+ *
+ * Finish the parsing of a <link linkend="BUILDER-UI">GtkBuilder UI definition</link>
+ * snippet. Note that this will be called once for each time gtk_builder_add_from_file or
+ * gtk_builder_add_from_string is called on a builder.
+ *
+ * #GtkWindow implements this to delay showing (::visible) itself until
+ * the whole interface is fully created.
+ *
+ * Since: 2.12
+ **/
+void
+gtk_buildable_parser_finished (GtkBuildable *buildable,
+ GtkBuilder *builder)
+{
+ GtkBuildableIface *iface;
+
+ g_return_if_fail (GTK_IS_BUILDABLE (buildable));
+ g_return_if_fail (GTK_IS_BUILDER (builder));
+
+ iface = GTK_BUILDABLE_GET_IFACE (buildable);
+ if (iface->parser_finished)
+ (* iface->parser_finished) (buildable, builder);
+}
+
+/**
+ * gtk_buildable_construct_child
+ * @buildable: A #GtkBuildable
+ * @builder: #GtkBuilder used to construct this object
+ * @name: name of child to construct
+ *
+ * Construct a child of @buildable with the name @name.
+ *
+ * #GtkUIManager implements this to reference to a widget created in a &lt;ui&gt; tag
+ * which is outside of the normal <link linkend="BUILDER-UI">GtkBuilder UI definition</link>
+ * object hierarchy.
+ *
+ * Since: 2.12
+ **/
+GObject *
+gtk_buildable_construct_child (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ const gchar *name)
+{
+ GtkBuildableIface *iface;
+
+ g_return_val_if_fail (GTK_IS_BUILDABLE (buildable), NULL);
+ g_return_val_if_fail (GTK_IS_BUILDER (builder), NULL);
+ g_return_val_if_fail (name != NULL, NULL);
+
+ iface = GTK_BUILDABLE_GET_IFACE (buildable);
+ g_return_val_if_fail (iface->construct_child != NULL, NULL);
+
+ return (* iface->construct_child) (buildable, builder, name);
+}
+
+/**
+ * gtk_buildable_custom_tag_start
+ * @buildable: a #GtkBuildable
+ * @builder: a #GtkBuilder used to construct this object
+ * @child: child object or %NULL for non-child tags
+ * @tagname: name of tag
+ * @parser: a #GMarkupParser structure
+ * @data: user data that will be passed in to parser functions
+ *
+ * This is called when an unknown tag under &lt;child&gt; tag is found.
+ *
+ * Called when an unknown tag is present under a &lt;child&gt; tag.
+ * If the buildable implementation wishes to handle the tag it should
+ * return %TRUE and fill in the @parser structure. Remember to either
+ * implement custom_tag_end or custom_tag_finish to free
+ * the user data allocated here.
+ *
+ * #GtkWidget implements this and parsers all &lt;accelerator&gt; tags to
+ * keyboard accelerators.
+ * #GtkContainer implements this to map properties defined under
+ * &lt;packing&gt; tag to child properties.
+ *
+ * Returns: %TRUE if a object has a custom implementation, %FALSE
+ * if it doesn't.
+ *
+ * Since: 2.12
+ **/
+gboolean
+gtk_buildable_custom_tag_start (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *tagname,
+ GMarkupParser *parser,
+ gpointer *data)
+{
+ GtkBuildableIface *iface;
+
+ g_return_val_if_fail (GTK_IS_BUILDABLE (buildable), FALSE);
+ g_return_val_if_fail (GTK_IS_BUILDER (builder), FALSE);
+ g_return_val_if_fail (tagname != NULL, FALSE);
+
+ iface = GTK_BUILDABLE_GET_IFACE (buildable);
+ g_return_val_if_fail (iface->custom_tag_start != NULL, FALSE);
+
+ return (* iface->custom_tag_start) (buildable, builder, child,
+ tagname, parser, data);
+}
+
+/**
+ * gtk_buildable_custom_tag_end
+ * @buildable: A #GtkBuildable
+ * @builder: #GtkBuilder used to construct this object
+ * @child: child object or %NULL for non-child tags
+ * @tagname: name of tag
+ * @data: user data that will be passed in to parser functions
+ *
+ * This is called for each custom tag handled by the buildable.
+ * It will be called when the end of the tag is reached.
+ *
+ * Since: 2.12
+ **/
+void
+gtk_buildable_custom_tag_end (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *tagname,
+ gpointer *data)
+{
+ GtkBuildableIface *iface;
+
+ g_return_if_fail (GTK_IS_BUILDABLE (buildable));
+ g_return_if_fail (GTK_IS_BUILDER (builder));
+ g_return_if_fail (tagname != NULL);
+
+ iface = GTK_BUILDABLE_GET_IFACE (buildable);
+ if (iface->custom_tag_end)
+ (* iface->custom_tag_end) (buildable, builder, child, tagname, data);
+}
+
+/**
+ * gtk_buildable_custom_finished:
+ * @buildable: a #GtkBuildable
+ * @builder: a #GtkBuilder
+ * @child: child object or %NULL for non-child tags
+ * @tagname: the name of the tag
+ * @data: user data created in custom_tag_start
+ *
+ * This is similar to gtk_buildable_parser_finished() but is
+ * called once for each custom tag handled by the @buildable.
+ *
+ * Since: 2.12
+ **/
+void
+gtk_buildable_custom_finished (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *tagname,
+ gpointer data)
+{
+ GtkBuildableIface *iface;
+
+ g_return_if_fail (GTK_IS_BUILDABLE (buildable));
+ g_return_if_fail (GTK_IS_BUILDER (builder));
+
+ iface = GTK_BUILDABLE_GET_IFACE (buildable);
+ if (iface->custom_finished)
+ (* iface->custom_finished) (buildable, builder, child, tagname, data);
+}
+
+/**
+ * gtk_buildable_get_internal_child
+ * @buildable: a #GtkBuildable
+ * @builder: a #GtkBuilder
+ * @childname: name of child
+ *
+ * Get the internal child called @child of the @buildable object.
+ *
+ * Return: the internal child of the buildable object
+ *
+ * Since: 2.12
+ **/
+GObject *
+gtk_buildable_get_internal_child (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ const gchar *childname)
+{
+ GtkBuildableIface *iface;
+
+ g_return_val_if_fail (GTK_IS_BUILDABLE (buildable), NULL);
+ g_return_val_if_fail (GTK_IS_BUILDER (builder), NULL);
+ g_return_val_if_fail (childname != NULL, NULL);
+
+ iface = GTK_BUILDABLE_GET_IFACE (buildable);
+ if (!iface->get_internal_child)
+ return NULL;
+
+ return (* iface->get_internal_child) (buildable, builder, childname);
+}
+
+#define __GTK_BUILDABLE_C__
+#include "gtkaliasdef.c"
diff --git a/gtk/gtkbuildable.h b/gtk/gtkbuildable.h
new file mode 100644
index 0000000000..397e4e8745
--- /dev/null
+++ b/gtk/gtkbuildable.h
@@ -0,0 +1,123 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 2006-2007 Async Open Source,
+ * Johan Dahlin <jdahlin@async.com.br>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GTK_BUILDABLE_H__
+#define __GTK_BUILDABLE_H__
+
+#include <glib/gmarkup.h>
+#include <gtk/gtkbuilder.h>
+#include <gtk/gtktypeutils.h>
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_BUILDABLE (gtk_buildable_get_type ())
+#define GTK_BUILDABLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_BUILDABLE, GtkBuildable))
+#define GTK_BUILDABLE_CLASS(obj) (G_TYPE_CHECK_CLASS_CAST ((obj), GTK_TYPE_BUILDABLE, GtkBuildableIface))
+#define GTK_IS_BUILDABLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_BUILDABLE))
+#define GTK_BUILDABLE_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), GTK_TYPE_BUILDABLE, GtkBuildableIface))
+
+typedef struct _GtkBuildable GtkBuildable; /* Dummy typedef */
+typedef struct _GtkBuildableIface GtkBuildableIface;
+
+struct _GtkBuildableIface
+{
+ GTypeInterface g_iface;
+
+ /* virtual table */
+ void (* set_name) (GtkBuildable *buildable,
+ const gchar *name);
+ const gchar * (* get_name) (GtkBuildable *buildable);
+ void (* add) (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *type);
+ void (* set_property) (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ const gchar *name,
+ const GValue *value);
+ GObject * (* construct_child) (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ const gchar *name);
+ gboolean (* custom_tag_start) (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *tagname,
+ GMarkupParser *parser,
+ gpointer *data);
+ void (* custom_tag_end) (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *tagname,
+ gpointer *data);
+ void (* custom_finished) (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *tagname,
+ gpointer data);
+ void (* parser_finished) (GtkBuildable *buildable,
+ GtkBuilder *builder);
+
+ GObject * (* get_internal_child) (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ const gchar *childname);
+};
+
+
+GType gtk_buildable_get_type (void) G_GNUC_CONST;
+
+void gtk_buildable_set_name (GtkBuildable *buildable,
+ const gchar *name);
+const gchar * gtk_buildable_get_name (GtkBuildable *buildable);
+void gtk_buildable_add (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *type);
+void gtk_buildable_set_property (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ const gchar *name,
+ const GValue *value);
+GObject * gtk_buildable_construct_child (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ const gchar *name);
+gboolean gtk_buildable_custom_tag_start (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *tagname,
+ GMarkupParser *parser,
+ gpointer *data);
+void gtk_buildable_custom_tag_end (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *tagname,
+ gpointer *data);
+void gtk_buildable_custom_finished (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *tagname,
+ gpointer data);
+void gtk_buildable_parser_finished (GtkBuildable *buildable,
+ GtkBuilder *builder);
+GObject * gtk_buildable_get_internal_child (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ const gchar *childname);
+
+G_END_DECLS
+
+#endif /* __GTK_BUILDABLE_H__ */
diff --git a/gtk/gtkbuilder.c b/gtk/gtkbuilder.c
new file mode 100644
index 0000000000..a4017c3ce4
--- /dev/null
+++ b/gtk/gtkbuilder.c
@@ -0,0 +1,1267 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 1998-2002 James Henstridge <james@daa.com.au>
+ * Copyright (C) 2006-2007 Async Open Source,
+ * Johan Dahlin <jdahlin@async.com.br>,
+ * Henrique Romano <henrique@async.com.br>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <config.h>
+#include <ctype.h> /* tolower, toupper */
+#include <errno.h> /* errno */
+#include <stdlib.h> /* strtol, strtoul */
+#include <string.h> /* strlen */
+
+#include "gtkbuilder.h"
+#include "gtkbuildable.h"
+#include "gtkbuilderprivate.h"
+#include "gtkmain.h"
+#include "gtkintl.h"
+#include "gtkprivate.h"
+#include "gtktypebuiltins.h"
+#include "gtkalias.h"
+
+static void gtk_builder_class_init (GtkBuilderClass *klass);
+static void gtk_builder_init (GtkBuilder *builder);
+static void gtk_builder_finalize (GObject *object);
+static void gtk_builder_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void gtk_builder_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec);
+static GType gtk_builder_real_get_type_from_name (GtkBuilder *builder,
+ const char *typename);
+static gint _gtk_builder_enum_from_string (GType type, const char *string);
+
+
+enum {
+ PROP_0,
+ PROP_TRANSLATION_DOMAIN,
+};
+
+struct _GtkBuilderPrivate
+{
+ gchar *domain;
+ GHashTable *objects;
+ GHashTable *delayed_properties;
+ GSList *signals;
+ gchar *current_toplevel;
+};
+
+G_DEFINE_TYPE (GtkBuilder, gtk_builder, G_TYPE_OBJECT)
+
+static void
+gtk_builder_class_init (GtkBuilderClass *klass)
+{
+ GObjectClass *gobject_class;
+
+ gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->finalize = gtk_builder_finalize;
+ gobject_class->set_property = gtk_builder_set_property;
+ gobject_class->get_property = gtk_builder_get_property;
+
+ klass->get_type_from_name = gtk_builder_real_get_type_from_name;
+
+ g_object_class_install_property (gobject_class,
+ PROP_TRANSLATION_DOMAIN,
+ g_param_spec_string ("translation-domain",
+ P_("Translation Domain"),
+ P_("The translation domain used by gettext"),
+ NULL,
+ GTK_PARAM_READWRITE));
+
+ g_type_class_add_private (gobject_class, sizeof (GtkBuilderPrivate));
+}
+
+static void
+gtk_builder_init (GtkBuilder *builder)
+{
+ builder->priv = G_TYPE_INSTANCE_GET_PRIVATE (builder, GTK_TYPE_BUILDER,
+ GtkBuilderPrivate);
+ builder->priv->domain = NULL;
+ builder->priv->objects = g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, NULL);
+ builder->priv->delayed_properties = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free, NULL);
+}
+
+
+/*
+ * GObject virtual methods
+ */
+
+static void
+gtk_builder_finalize (GObject *object)
+{
+ GtkBuilder *builder = GTK_BUILDER (object);
+
+ g_free (builder->priv->domain);
+
+ g_free (builder->priv->current_toplevel);
+ g_hash_table_destroy (builder->priv->delayed_properties);
+ builder->priv->delayed_properties = NULL;
+ g_slist_foreach (builder->priv->signals, (GFunc)_free_signal_info, NULL);
+ g_slist_free (builder->priv->signals);
+ g_hash_table_destroy (builder->priv->objects);
+}
+
+static void
+gtk_builder_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GtkBuilder *builder = GTK_BUILDER (object);
+
+ switch (prop_id)
+ {
+ case PROP_TRANSLATION_DOMAIN:
+ gtk_builder_set_translation_domain (builder, g_value_get_string (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gtk_builder_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GtkBuilder *builder = GTK_BUILDER (object);
+
+ switch (prop_id)
+ {
+ case PROP_TRANSLATION_DOMAIN:
+ g_value_set_string (value, builder->priv->domain);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+
+/*
+ * Try to map a type name to a _get_type function
+ * and call it, eg:
+ *
+ * GtkWindow -> gtk_window_get_type
+ * GtkHBox -> gtk_hbox_get_type
+ * GtkUIManager -> gtk_ui_manager_get_type
+ *
+ */
+static GType
+_gtk_builder_resolve_type_lazily (const gchar *name)
+{
+ static GModule *module = NULL;
+ GTypeGetFunc func;
+ GString *symbol_name = g_string_new ("");
+ char c, *symbol;
+ int i;
+ GType gtype = G_TYPE_INVALID;
+
+ if (!module)
+ module = g_module_open (NULL, 0);
+
+ for (i = 0; name[i] != '\0'; i++)
+ {
+ c = name[i];
+ /* skip if uppercase, first or previous is uppercase */
+ if ((c == toupper (c) &&
+ i > 0 && name[i-1] != toupper (name[i-1])) ||
+ (i > 2 && name[i] == toupper (name[i]) &&
+ name[i-1] == toupper (name[i-1]) &&
+ name[i-2] == toupper (name[i-2])))
+ g_string_append_c (symbol_name, '_');
+ g_string_append_c (symbol_name, tolower (c));
+ }
+ g_string_append (symbol_name, "_get_type");
+
+ symbol = g_string_free (symbol_name, FALSE);
+
+ if (g_module_symbol (module, symbol, (gpointer)&func))
+ gtype = func ();
+
+ g_free (symbol);
+
+ return gtype;
+}
+
+/*
+ * GtkBuilder virtual methods
+ */
+
+static GType
+gtk_builder_real_get_type_from_name (GtkBuilder *builder, const char *typename)
+{
+ GType gtype;
+
+ gtype = g_type_from_name (typename);
+ if (gtype != G_TYPE_INVALID)
+ return gtype;
+
+ return _gtk_builder_resolve_type_lazily (typename);
+}
+
+typedef struct
+{
+ gchar *object;
+ gchar *name;
+ gchar *value;
+} DelayedProperty;
+
+static void
+gtk_builder_get_parameters (GtkBuilder *builder,
+ GType object_type,
+ const gchar *object_name,
+ GSList *properties,
+ GArray **parameters,
+ GArray **construct_parameters)
+{
+ GSList *l;
+ GParamSpec *pspec;
+ GObjectClass *oclass;
+ DelayedProperty *property;
+
+ oclass = g_type_class_ref (object_type);
+ g_assert (oclass != NULL);
+
+ *parameters = g_array_new (FALSE, FALSE, sizeof (GParameter));
+ *construct_parameters = g_array_new (FALSE, FALSE, sizeof (GParameter));
+
+ for (l = properties; l; l = l->next)
+ {
+ PropertyInfo *prop = (PropertyInfo*)l->data;
+ GParameter parameter = { NULL };
+
+ pspec = g_object_class_find_property (G_OBJECT_CLASS (oclass),
+ prop->name);
+ if (!pspec)
+ {
+ g_warning ("Unknown property: %s.%s\n",
+ g_type_name (object_type), prop->name);
+ continue;
+ }
+
+ parameter.name = prop->name;
+
+ if (G_IS_PARAM_SPEC_OBJECT (pspec))
+ {
+ if (pspec->flags & G_PARAM_CONSTRUCT_ONLY)
+ {
+ GObject *object;
+ object = gtk_builder_get_object (builder, prop->data);
+ if (!object)
+ {
+ g_warning ("failed to get constuct only property %s of %s "
+ "with value `%s'",
+ prop->name, object_name, prop->data);
+ continue;
+ }
+ g_value_init (&parameter.value, G_OBJECT_TYPE (object));
+ g_value_set_object (&parameter.value, g_object_ref (object));
+ }
+ else
+ {
+ GSList *delayed_properties;
+
+ delayed_properties = g_hash_table_lookup (builder->priv->delayed_properties,
+ builder->priv->current_toplevel);
+ property = g_slice_new (DelayedProperty);
+ property->object = g_strdup (object_name);
+ property->name = g_strdup (prop->name);
+ property->value = g_strdup (prop->data);
+ delayed_properties = g_slist_prepend (delayed_properties, property);
+ g_hash_table_insert (builder->priv->delayed_properties,
+ g_strdup (builder->priv->current_toplevel),
+ delayed_properties);
+ continue;
+ }
+ }
+ else if (!gtk_builder_value_from_string (pspec, prop->data, &parameter.value))
+ {
+ g_warning ("failed to set property %s.%s to %s",
+ g_type_name (object_type), prop->name, prop->data);
+ continue;
+ }
+
+ if (pspec->flags & G_PARAM_CONSTRUCT_ONLY)
+ g_array_append_val (*construct_parameters, parameter);
+ else
+ g_array_append_val (*parameters, parameter);
+ }
+
+ g_type_class_unref (oclass);
+}
+
+static GObject *
+gtk_builder_get_internal_child (GtkBuilder *builder,
+ ObjectInfo *info,
+ const gchar *childname)
+{
+ GObject *obj = NULL;
+
+ while (!obj)
+ {
+ if (!info->parent)
+ break;
+
+ info = (ObjectInfo*)((ChildInfo*)info->parent)->parent;
+ if (!info)
+ break;
+
+ GTK_NOTE (BUILDER,
+ g_print ("Trying to get internal child %s from %s\n",
+ childname,
+ gtk_buildable_get_name (GTK_BUILDABLE (info->object))));
+
+ if (GTK_IS_BUILDABLE (info->object))
+ obj = gtk_buildable_get_internal_child (GTK_BUILDABLE (info->object),
+ builder,
+ childname);
+ };
+
+ if (!obj)
+ g_error ("Unknown internal child: %s\n", childname);
+
+ return obj;
+}
+
+GObject *
+_gtk_builder_construct (GtkBuilder *builder,
+ ObjectInfo *info)
+{
+ GArray *parameters, *construct_parameters;
+ GType object_type;
+ GObject *obj;
+ int i;
+ GtkBuildableIface *iface;
+ gboolean custom_set_property;
+ GtkBuildable *buildable;
+
+ g_assert (info->class_name != NULL);
+ object_type = gtk_builder_get_type_from_name (builder, info->class_name);
+ if (object_type == G_TYPE_INVALID)
+ g_error ("Invalid type: %s", info->class_name);
+
+ gtk_builder_get_parameters (builder, object_type,
+ info->id,
+ info->properties,
+ &parameters,
+ &construct_parameters);
+
+ if (info->constructor)
+ {
+ GObject *constructor;
+
+ constructor = gtk_builder_get_object (builder, info->constructor);
+ if (constructor == NULL)
+ g_error ("Unknown constructor for %s: %s\n", info->id,
+ info->constructor);
+
+ obj = gtk_buildable_construct_child (GTK_BUILDABLE (constructor),
+ builder,
+ info->id);
+ g_assert (obj != NULL);
+ if (construct_parameters->len)
+ g_warning ("Can't pass in construct-only parameters to %s", info->id);
+
+ }
+ else if (info->parent && ((ChildInfo*)info->parent)->internal_child != NULL)
+ {
+ gchar *childname = ((ChildInfo*)info->parent)->internal_child;
+ obj = gtk_builder_get_internal_child (builder, info, childname);
+ if (construct_parameters->len)
+ g_warning ("Can't pass in construct-only parameters to %s", childname);
+ }
+ else
+ {
+ obj = g_object_newv (object_type,
+ construct_parameters->len,
+ (GParameter *)construct_parameters->data);
+
+ GTK_NOTE (BUILDER,
+ g_print ("created %s of type %s\n", info->id, info->class_name));
+
+ for (i = 0; i < construct_parameters->len; i++)
+ {
+ GParameter *param = &g_array_index (construct_parameters,
+ GParameter, i);
+ g_value_unset (&param->value);
+ }
+ }
+ g_array_free (construct_parameters, TRUE);
+
+ custom_set_property = FALSE;
+ buildable = NULL;
+ iface = NULL;
+ if (GTK_IS_BUILDABLE (obj))
+ {
+ buildable = GTK_BUILDABLE (obj);
+ iface = GTK_BUILDABLE_GET_IFACE (obj);
+ if (iface->set_property)
+ custom_set_property = TRUE;
+ }
+
+ for (i = 0; i < parameters->len; i++)
+ {
+ GParameter *param = &g_array_index (parameters, GParameter, i);
+ if (custom_set_property)
+ iface->set_property (buildable, builder, param->name, &param->value);
+ else
+ g_object_set_property (obj, param->name, &param->value);
+
+#if G_ENABLE_DEBUG
+ if (gtk_debug_flags & GTK_DEBUG_BUILDER)
+ {
+ gchar *str = g_strdup_value_contents ((const GValue*)&param->value);
+ g_print ("set %s: %s = %s\n", info->id, param->name, str);
+ g_free (str);
+ }
+#endif
+ g_value_unset (&param->value);
+ }
+ g_array_free (parameters, TRUE);
+
+ if (GTK_IS_BUILDABLE (obj))
+ gtk_buildable_set_name (buildable, info->id);
+ else
+ g_object_set_data_full (obj,
+ "gtk-builder-name",
+ g_strdup (info->id),
+ g_free);
+
+ if (!info->parent)
+ {
+ g_free (builder->priv->current_toplevel);
+ builder->priv->current_toplevel = g_strdup (info->id);
+ }
+ g_hash_table_insert (builder->priv->objects, g_strdup (info->id), obj);
+
+ builder->priv->signals = g_slist_concat (builder->priv->signals,
+ g_slist_copy (info->signals));
+ return obj;
+}
+
+
+void
+_gtk_builder_add (GtkBuilder *builder,
+ ChildInfo *child_info)
+{
+ GObject *object;
+ GObject *parent;
+
+ /* Internal children are already added
+ * Also prevent us from being called twice.
+ */
+ if (!child_info ||
+ child_info->internal_child ||
+ child_info->added)
+ return;
+
+ object = child_info->object;
+ if (!object)
+ return;
+
+ if (!child_info->parent)
+ {
+ g_warning ("%s: Not adding, No parent\n",
+ gtk_buildable_get_name (GTK_BUILDABLE (object)));
+ return;
+ }
+
+ g_assert (object != NULL);
+
+ parent = ((ObjectInfo*)child_info->parent)->object;
+ g_assert (GTK_IS_BUILDABLE (parent));
+
+ GTK_NOTE (BUILDER,
+ g_print ("adding %s to %s\n",
+ gtk_buildable_get_name (GTK_BUILDABLE (object)),
+ gtk_buildable_get_name (GTK_BUILDABLE (parent))));
+
+ gtk_buildable_add (GTK_BUILDABLE (parent), builder, object,
+ child_info->type);
+
+ child_info->added = TRUE;
+}
+
+static void
+apply_delayed_properties (const gchar *window_name,
+ GSList *props,
+ GtkBuilder *builder)
+{
+ GSList *l;
+ DelayedProperty *property;
+ GObject *object;
+ GType object_type;
+ GObjectClass *oclass;
+ GParamSpec *pspec;
+
+ g_assert (props != NULL);
+ props = g_slist_reverse (props);
+ for (l = props; l; l = l->next)
+ {
+ property = (DelayedProperty*)l->data;
+ object = g_hash_table_lookup (builder->priv->objects, property->object);
+ g_assert (object != NULL);
+
+ object_type = G_OBJECT_TYPE (object);
+ g_assert (object_type != G_TYPE_INVALID);
+
+ oclass = g_type_class_ref (object_type);
+ g_assert (oclass != NULL);
+
+ pspec = g_object_class_find_property (G_OBJECT_CLASS (oclass),
+ property->name);
+ if (!pspec)
+ g_warning ("Unknown property: %s.%s\n", g_type_name (object_type),
+ property->name);
+ else
+ {
+ GObject *obj;
+
+ obj = g_hash_table_lookup (builder->priv->objects, property->value);
+ if (!obj)
+ g_warning ("No object called: %s\n", property->object);
+ else
+ g_object_set (object, property->name, obj, NULL);
+ }
+ g_free (property->value);
+ g_free (property->object);
+ g_free (property->name);
+ g_slice_free (DelayedProperty, property);
+ g_type_class_unref (oclass);
+ }
+ g_slist_free (props);
+}
+
+void
+_gtk_builder_finish (GtkBuilder *builder)
+{
+ if (builder->priv->delayed_properties)
+ g_hash_table_foreach (builder->priv->delayed_properties,
+ (GHFunc)apply_delayed_properties, builder);
+}
+
+/**
+ * gtk_builder_new:
+ *
+ * Creates a new builder object.
+ *
+ * Return value: a new builder object.
+ *
+ * Since: 2.12
+ **/
+GtkBuilder *
+gtk_builder_new (void)
+{
+ return g_object_new (GTK_TYPE_BUILDER, NULL);
+}
+
+/**
+ * gtk_builder_add_from_file:
+ * @builder: a #GtkBuilder
+ * @filename: the name of the file to parse
+ * @error: return location for an error
+ *
+ * Parses a string containing a <link linkend="BUILDER-UI">GtkBuilder UI definition</link> and
+ * merges it with the current contents of @builder.
+ *
+ * Returns: A positive value on success, 0 if an error occurred
+ *
+ * Since: 2.12
+ **/
+guint
+gtk_builder_add_from_file (GtkBuilder *builder,
+ const gchar *filename,
+ GError **error)
+{
+ char *buffer;
+ unsigned length;
+ GError *tmp_error;
+
+ g_return_val_if_fail (GTK_IS_BUILDER (builder), 0);
+ g_return_val_if_fail (filename != NULL, 0);
+
+ tmp_error = NULL;
+
+ if (!g_file_get_contents (filename, &buffer, &length, &tmp_error))
+ {
+ g_propagate_error (error, tmp_error);
+ return 0;
+ }
+
+ _gtk_builder_parser_parse_buffer (builder, filename,
+ buffer, length,
+ &tmp_error);
+
+ if (tmp_error != NULL)
+ {
+ g_propagate_error (error, tmp_error);
+ return 0;
+ }
+
+ g_free (buffer);
+
+ return 1;
+}
+
+/**
+ * gtk_builder_add_from_string:
+ * @builder: a #GtkBuilder
+ * @buffer: the string to parse
+ * @length: the length of @buffer (may be -1 if @buffer is nul-terminated)
+ * @error: return location for an error
+ *
+ * Parses a file containing a <link linkend="BUILDER-UI">GtkBuilder UI definition</link> and
+ * merges it with the current contents of @builder.
+ *
+ * Returns: A positive value on success, 0 if an error occurred
+ *
+ * Since: 2.12
+ **/
+guint
+gtk_builder_add_from_string (GtkBuilder *builder,
+ const gchar *buffer,
+ gsize length,
+ GError **error)
+{
+ GError *tmp_error;
+
+ g_return_val_if_fail (GTK_IS_BUILDER (builder), 0);
+ g_return_val_if_fail (buffer != NULL, 0);
+
+ tmp_error = NULL;
+
+ _gtk_builder_parser_parse_buffer (builder, "<input>",
+ buffer, length,
+ &tmp_error);
+ if (tmp_error != NULL)
+ {
+ g_propagate_error (error, tmp_error);
+ return 0;
+ }
+
+ return 1;
+}
+
+/**
+ * gtk_builder_get_object:
+ * @builder: a #GtkBuilder
+ * @name: name of object to get
+ *
+ * Return value: GObject or %NULL if it could not be found in the object tree.
+ *
+ * Since: 2.12
+ **/
+GObject *
+gtk_builder_get_object (GtkBuilder *builder,
+ const gchar *name)
+{
+ g_return_val_if_fail (GTK_IS_BUILDER (builder), NULL);
+ g_return_val_if_fail (name != NULL, NULL);
+
+ return g_hash_table_lookup (builder->priv->objects, name);
+}
+
+static void
+object_add_to_list (gchar *object_id,
+ GObject *object,
+ GSList **list)
+{
+ *list = g_slist_prepend (*list, object);
+}
+
+/**
+ * gtk_builder_get_objects:
+ * @builder: a #GtkBuilder
+ *
+ * Return value: a newly-allocated #GSList containing all the objects
+ * constructed by GtkBuilder instance.
+ *
+ * Since: 2.12
+ **/
+GSList *
+gtk_builder_get_objects (GtkBuilder *builder)
+{
+ GSList *objects = NULL;
+
+ g_return_val_if_fail (GTK_IS_BUILDER (builder), NULL);
+
+ g_hash_table_foreach (builder->priv->objects, (GHFunc)object_add_to_list, &objects);
+
+ return g_slist_reverse (objects);
+}
+
+/**
+ * gtk_builder_set_translation_domain:
+ * @builder: a #GtkBuilder
+ * @domain: the translation domain or %NULL
+ *
+ * Sets the translation domain and uses dgettext() for translating the
+ * property values marked as translatable from an interface description.
+ * You can also pass in %NULL to this method to use gettext() instead of
+ * dgettext().
+ *
+ * Since: 2.12
+ **/
+void
+gtk_builder_set_translation_domain (GtkBuilder *builder,
+ const gchar *domain)
+{
+ gchar *new_domain;
+
+ g_return_if_fail (GTK_IS_BUILDER (builder));
+
+ new_domain = g_strdup (domain);
+ g_free (builder->priv->domain);
+ builder->priv->domain = new_domain;
+
+ g_object_notify (G_OBJECT (builder), "translation-domain");
+}
+
+/**
+ * gtk_builder_get_translation_domain:
+ * @builder: a #GtkBuilder
+ *
+ * Return value : the translation domain. This string is owned
+ * by the builder object and must not be modified or freed.
+ *
+ * Since: 2.12
+ **/
+const gchar *
+gtk_builder_get_translation_domain (GtkBuilder *builder)
+{
+ g_return_val_if_fail (GTK_IS_BUILDER (builder), NULL);
+
+ return builder->priv->domain;
+}
+
+typedef struct {
+ GModule *module;
+ gpointer data;
+} connect_args;
+
+static void
+gtk_builder_connect_signals_default (GtkBuilder *builder,
+ GObject *object,
+ const gchar *signal_name,
+ const gchar *handler_name,
+ GObject *connect_object,
+ GConnectFlags flags,
+ gpointer user_data)
+{
+ GCallback func;
+ connect_args *args = (connect_args*)user_data;
+
+ if (!g_module_symbol (args->module, handler_name, (gpointer)&func))
+ {
+ g_warning ("could not find signal handler '%s'", handler_name);
+ return;
+ }
+
+ if (connect_object)
+ g_signal_connect_object (object, signal_name, func, connect_object, flags);
+ else
+ g_signal_connect_data (object, signal_name, func, args->data, NULL, flags);
+}
+
+
+/**
+ * gtk_builder_connect_signals:
+ * @builder: a #GtkBuilder
+ * @user_data: a pointer to a structure sent in as user data to all signals
+ *
+ * This method is a simpler variation of gtk_builder_connect_signals_full().
+ * It uses #GModule's introspective features (by opening the module %NULL) to
+ * look at the application's symbol table. From here it tries to match
+ * the signal handler names given in the interface description with
+ * symbols in the application and connects the signals.
+ *
+ * Note that this function will not work correctly if #GModule is not
+ * supported on the platform.
+ *
+ * Since: 2.12
+ **/
+void
+gtk_builder_connect_signals (GtkBuilder *builder,
+ gpointer user_data)
+{
+ connect_args *args;
+
+ g_return_if_fail (GTK_IS_BUILDER (builder));
+
+ if (!g_module_supported ())
+ g_error ("gtk_builder_connect_signals requires working GModule");
+
+ args = g_slice_new0 (connect_args);
+ args->module = g_module_open (NULL, G_MODULE_BIND_LAZY);
+ args->data = user_data;
+
+ gtk_builder_connect_signals_full (builder,
+ gtk_builder_connect_signals_default,
+ args);
+ g_module_close (args->module);
+
+ g_slice_free (connect_args, args);
+}
+
+/**
+ * GtkBuilderConnectFunc:
+ * @builder: a #GtkBuilder
+ * @object: a GObject subclass to connect a signal to
+ * @signal_name: name of the signal
+ * @handler_name: name of the handler
+ * @connect_object: GObject, if non-%NULL, use g_signal_connect_object.
+ * @flags: #GConnectFlags to use
+ * @user_data: user data
+ *
+ * This is the signature of a function used to connect signals. It is used
+ * by the gtk_builder_connect_signals() and gtk_builder_connect_signals_full()
+ * methods. It is mainly intended for interpreted language bindings, but
+ * could be useful where the programmer wants more control over the signal
+ * connection process.
+ *
+ * Since: 2.12
+ */
+
+/**
+ * gtk_builder_connect_signals_full:
+ * @builder: a #GtkBuilder
+ * @func: the function used to connect the signals.
+ * @user_data: arbitrary data that will be passed to the connection function.
+ *
+ * This function can be thought of the interpreted language binding
+ * version of gtk_builder_signal_autoconnect(), except that it does not
+ * require gmodule to function correctly.
+ *
+ * Since: 2.12
+ */
+void
+gtk_builder_connect_signals_full (GtkBuilder *builder,
+ GtkBuilderConnectFunc func,
+ gpointer user_data)
+{
+ GSList *l;
+ GObject *object;
+ GObject *connect_object;
+
+ g_return_if_fail (GTK_IS_BUILDER (builder));
+ g_return_if_fail (func != NULL);
+
+ if (!builder->priv->signals)
+ return;
+
+ builder->priv->signals = g_slist_reverse (builder->priv->signals);
+ for (l = builder->priv->signals; l; l = l->next)
+ {
+ SignalInfo *signal = (SignalInfo*)l->data;
+
+ g_assert (signal != NULL);
+ g_assert (signal->name != NULL);
+
+ object = g_hash_table_lookup (builder->priv->objects,
+ signal->object_name);
+ g_assert (object != NULL);
+
+ connect_object = NULL;
+
+ if (signal->connect_object_name)
+ {
+ connect_object = g_hash_table_lookup (builder->priv->objects,
+ signal->connect_object_name);
+ if (!connect_object)
+ g_warning ("could not lookup object %s on signal %s of object %s",
+ signal->connect_object_name, signal->name,
+ signal->object_name);
+ }
+
+ func (builder, object, signal->name, signal->handler,
+ connect_object, signal->flags, user_data);
+ }
+
+ g_slist_foreach (builder->priv->signals, (GFunc)_free_signal_info, NULL);
+ g_slist_free (builder->priv->signals);
+ builder->priv->signals = NULL;
+}
+
+/**
+ * gtk_builder_value_from_string
+ * @pspec: the GParamSpec for the property
+ * @string: the string representation of the value.
+ * @value: the GValue to store the result in.
+ *
+ * This function demarshals a value from a string. This function
+ * calls g_value_init() on the @value argument, so it need not be
+ * initialised beforehand.
+ *
+ * This function can handle char, uchar, boolean, int, uint, long,
+ * ulong, enum, flags, float, double, string, GdkColor and
+ * GtkAdjustment type values. Support for GtkWidget type values is
+ * still to come.
+ *
+ * Returns: %TRUE on success.
+ *
+ * Since: 2.12
+ */
+gboolean
+gtk_builder_value_from_string (GParamSpec *pspec,
+ const gchar *string,
+ GValue *value)
+{
+ /*
+ * GParamSpecUnichar has the internal type G_TYPE_UINT,
+ * so we cannot handle this in the switch, do it separately
+ */
+ if (G_IS_PARAM_SPEC_UNICHAR (pspec))
+ {
+ gunichar c;
+ g_value_init (value, G_TYPE_UINT);
+ c = g_utf8_get_char_validated (string, strlen (string));
+ if (c > 0)
+ g_value_set_uint (value, c);
+ return TRUE;
+ }
+
+ return gtk_builder_value_from_string_type (G_PARAM_SPEC_VALUE_TYPE (pspec),
+ string, value);
+}
+
+/**
+ * gtk_builder_value_from_string_type
+ * @type: the GType of the value
+ * @string: the string representation of the value.
+ * @value: the GValue to store the result in.
+ *
+ * Like gtk_builder_value_from_string(), but takes a #GType instead of #GParamSpec.
+ *
+ * Returns: %TRUE on success.
+ *
+ * Since: 2.12
+ */
+gboolean
+gtk_builder_value_from_string_type (GType type,
+ const gchar *string,
+ GValue *value)
+{
+ gboolean ret = TRUE;
+
+ g_return_val_if_fail (type != G_TYPE_INVALID, FALSE);
+ g_return_val_if_fail (string != NULL, FALSE);
+
+ g_value_init (value, type);
+
+ switch (G_TYPE_FUNDAMENTAL (type))
+ {
+ case G_TYPE_CHAR:
+ g_value_set_char (value, string[0]);
+ break;
+ case G_TYPE_UCHAR:
+ g_value_set_uchar (value, (guchar)string[0]);
+ break;
+ case G_TYPE_BOOLEAN:
+ {
+ gboolean b;
+
+ if (g_ascii_tolower (string[0]) == 't')
+ b = TRUE;
+ else if (g_ascii_tolower (string[0]) == 'y')
+ b = FALSE;
+ else {
+ errno = 0;
+ b = strtol (string, NULL, 0);
+ if (errno) {
+ g_warning ("could not parse int `%s'", string);
+ break;
+ }
+ }
+ g_value_set_boolean (value, b);
+ break;
+ }
+ case G_TYPE_INT:
+ case G_TYPE_LONG:
+ {
+ long l;
+ errno = 0;
+ l = strtol (string, NULL, 0);
+ if (errno) {
+ g_warning ("could not parse long `%s'", string);
+ break;
+ }
+ if (G_VALUE_HOLDS_INT (value))
+ g_value_set_int (value, l);
+ else
+ g_value_set_long (value, l);
+ break;
+ }
+ case G_TYPE_UINT:
+ case G_TYPE_ULONG:
+ {
+ ulong ul;
+ errno = 0;
+ ul = strtoul (string, NULL, 0);
+ if (errno)
+ {
+ g_warning ("could not parse ulong `%s'", string);
+ break;
+ }
+ if (G_VALUE_HOLDS_UINT (value))
+ g_value_set_uint (value, strtoul (string, NULL, 0));
+ else
+ g_value_set_ulong (value, strtoul (string, NULL, 0));
+ break;
+ }
+ case G_TYPE_ENUM:
+ g_value_set_enum (value, _gtk_builder_enum_from_string (type, string));
+ break;
+ case G_TYPE_FLAGS:
+ g_value_set_flags (value, _gtk_builder_flags_from_string (type, string));
+ break;
+ case G_TYPE_FLOAT:
+ case G_TYPE_DOUBLE:
+ {
+ double d;
+ errno = 0;
+ d = g_ascii_strtod (string, NULL);
+ if (errno)
+ {
+ g_warning ("could not parse double `%s'", string);
+ break;
+ }
+ if (G_VALUE_HOLDS_FLOAT (value))
+ g_value_set_float (value, d);
+ else
+ g_value_set_double (value, d);
+ break;
+ }
+ case G_TYPE_STRING:
+ g_value_set_string (value, string);
+ break;
+ case G_TYPE_BOXED:
+ if (G_VALUE_HOLDS (value, GDK_TYPE_COLOR))
+ {
+ GdkColor colour = { 0, };
+
+ if (gdk_color_parse (string, &colour) &&
+ gdk_colormap_alloc_color (gtk_widget_get_default_colormap (),
+ &colour, FALSE, TRUE))
+ g_value_set_boxed (value, &colour);
+ else
+ {
+ g_warning ("could not parse colour name `%s'", string);
+ ret = FALSE;
+ }
+ }
+ else if (G_VALUE_HOLDS (value, G_TYPE_STRV))
+ {
+ char **vector = g_strsplit (string, "\n", 0);
+ g_value_take_boxed (value, vector);
+ }
+ else
+ ret = FALSE;
+ break;
+ case G_TYPE_OBJECT:
+#if 0
+ if (G_VALUE_HOLDS (value, GDK_TYPE_PIXBUF))
+ {
+ gchar *filename;
+ GError *error = NULL;
+ GdkPixbuf *pixbuf;
+
+ filename = gtk_xml_relative_file (xml, string);
+ pixbuf = gdk_pixbuf_new_from_file (filename, &error);
+ if (pixbuf)
+ {
+ g_value_set_object (value, pixbuf);
+ g_object_unref (G_OBJECT (pixbuf));
+ }
+ else
+ {
+ g_warning ("Error loading image: %s", error->message);
+ g_error_free (error);
+ ret = FALSE;
+ }
+ g_free (filename);
+ }
+ else
+#endif
+ ret = FALSE;
+ break;
+ default:
+ ret = FALSE;
+ break;
+ }
+
+ return ret;
+}
+
+static gint
+_gtk_builder_enum_from_string (GType type, const char *string)
+{
+ GEnumClass *eclass;
+ GEnumValue *ev;
+ gchar *endptr;
+ gint ret = 0;
+
+ g_return_val_if_fail (G_TYPE_IS_ENUM (type), 0);
+ g_return_val_if_fail (string != NULL, 0);
+
+ ret = strtoul (string, &endptr, 0);
+ if (endptr != string) /* parsed a number */
+ return ret;
+
+ eclass = g_type_class_ref (type);
+ ev = g_enum_get_value_by_name (eclass, string);
+ if (!ev)
+ ev = g_enum_get_value_by_nick (eclass, string);
+
+ if (ev)
+ ret = ev->value;
+
+ g_type_class_unref (eclass);
+
+ return ret;
+}
+
+guint
+_gtk_builder_flags_from_string (GType type, const char *string)
+{
+ GFlagsClass *fclass;
+ gchar *endptr, *prevptr;
+ guint i, j, ret;
+ char *flagstr;
+ GFlagsValue *fv;
+ const char *flag;
+ gunichar ch;
+ gboolean eos;
+
+ g_return_val_if_fail (G_TYPE_IS_FLAGS (type), 0);
+ g_return_val_if_fail (string != 0, 0);
+
+ ret = strtoul (string, &endptr, 0);
+ if (endptr != string) /* parsed a number */
+ return ret;
+
+ fclass = g_type_class_ref (type);
+
+ flagstr = g_strdup (string);
+ for (ret = i = j = 0; ; i++)
+ {
+
+ eos = flagstr[i] == '\0';
+
+ if (!eos && flagstr[i] != '|')
+ continue;
+
+ flag = &flagstr[j];
+ endptr = &flagstr[i];
+
+ if (!eos)
+ {
+ flagstr[i++] = '\0';
+ j = i;
+ }
+
+ /* trim spaces */
+ for (;;)
+ {
+ ch = g_utf8_get_char (flag);
+ if (!g_unichar_isspace (ch))
+ break;
+ flag = g_utf8_next_char (flag);
+ }
+
+ while (endptr > flag)
+ {
+ prevptr = g_utf8_prev_char (endptr);
+ ch = g_utf8_get_char (prevptr);
+ if (!g_unichar_isspace (ch))
+ break;
+ endptr = prevptr;
+ }
+
+ if (endptr > flag)
+ {
+ *endptr = '\0';
+ fv = g_flags_get_value_by_name (fclass, flag);
+
+ if (!fv)
+ fv = g_flags_get_value_by_nick (fclass, flag);
+
+ if (fv)
+ ret |= fv->value;
+ else
+ g_warning ("Unknown flag: '%s'", flag);
+ }
+
+ if (eos)
+ break;
+ }
+
+ g_free (flagstr);
+
+ g_type_class_unref (fclass);
+
+ return ret;
+}
+
+/**
+ * gtk_builder_get_type_from_name:
+ * @builder: a #GtkBuilder
+ * @typename: Type name to lookup.
+ *
+ * This method is used to lookup a type. It can be implemented in a subclass to
+ * override the #GType of an object created by the builder.
+ *
+ * Since 2.12
+ */
+GType
+gtk_builder_get_type_from_name (GtkBuilder *builder, const gchar *typename)
+{
+ g_return_val_if_fail (GTK_IS_BUILDER (builder), G_TYPE_INVALID);
+ g_return_val_if_fail (typename != NULL, G_TYPE_INVALID);
+
+ return GTK_BUILDER_GET_CLASS (builder)->get_type_from_name (builder, typename);
+}
+
+/**
+ * gtk_builder_error_quark:
+ *
+ * Registers an error quark for #GtkBuilder if necessary.
+ *
+ * Return value: The error quark used for #GtkBuilder errors.
+ *
+ * Since: 2.12
+ **/
+GQuark
+gtk_builder_error_quark (void)
+{
+ return g_quark_from_static_string ("gtk-builder-error-quark");
+}
+
+
+#define __GTK_BUILDER_C__
+#include "gtkaliasdef.c"
diff --git a/gtk/gtkbuilder.h b/gtk/gtkbuilder.h
new file mode 100644
index 0000000000..81ea9a7250
--- /dev/null
+++ b/gtk/gtkbuilder.h
@@ -0,0 +1,122 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 2006-2007 Async Open Source,
+ * Johan Dahlin <jdahlin@async.com.br>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#ifndef __GTK_BUILDER_H__
+#define __GTK_BUILDER_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_BUILDER (gtk_builder_get_type ())
+#define GTK_BUILDER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_BUILDER, GtkBuilder))
+#define GTK_BUILDER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_BUILDER, GtkBuilderClass))
+#define GTK_IS_BUILDER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_BUILDER))
+#define GTK_IS_BUILDER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_BUILDER))
+#define GTK_BUILDER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_BUILDER, GtkBuilderClass))
+
+#define GTK_BUILDER_ERROR (gtk_builder_error_quark ())
+
+typedef struct _GtkBuilder GtkBuilder;
+typedef struct _GtkBuilderClass GtkBuilderClass;
+typedef struct _GtkBuilderPrivate GtkBuilderPrivate;
+
+typedef enum
+{
+ GTK_BUILDER_ERROR_INVALID_TYPE_FUNCTION,
+ GTK_BUILDER_ERROR_UNHANDLED_TAG,
+ GTK_BUILDER_ERROR_MISSING_ATTRIBUTE,
+ GTK_BUILDER_ERROR_INVALID_ATTRIBUTE,
+ GTK_BUILDER_ERROR_INVALID_TAG
+} GtkBuilderError;
+
+GQuark gtk_builder_error_quark (void);
+
+struct _GtkBuilder
+{
+ GObject parent_instance;
+
+ GtkBuilderPrivate *priv;
+};
+
+struct _GtkBuilderClass
+{
+ GObjectClass parent_class;
+
+ GType (* get_type_from_name) (GtkBuilder *builder,
+ const char *typename);
+
+ /* Padding for future expansion */
+ void (*_gtk_reserved1) (void);
+ void (*_gtk_reserved2) (void);
+ void (*_gtk_reserved3) (void);
+ void (*_gtk_reserved4) (void);
+ void (*_gtk_reserved5) (void);
+ void (*_gtk_reserved6) (void);
+ void (*_gtk_reserved7) (void);
+ void (*_gtk_reserved8) (void);
+};
+
+typedef void (*GtkBuilderConnectFunc) (GtkBuilder *builder,
+ GObject *object,
+ const gchar *signal_name,
+ const gchar *handler_name,
+ GObject *connect_object,
+ GConnectFlags flags,
+ gpointer user_data);
+
+GType gtk_builder_get_type (void) G_GNUC_CONST;
+GtkBuilder* gtk_builder_new (void);
+
+guint gtk_builder_add_from_file (GtkBuilder *builder,
+ const gchar *filename,
+ GError **error);
+guint gtk_builder_add_from_string (GtkBuilder *builder,
+ const gchar *buffer,
+ gsize length,
+ GError **error);
+GObject* gtk_builder_get_object (GtkBuilder *builder,
+ const gchar *name);
+GSList* gtk_builder_get_objects (GtkBuilder *builder);
+void gtk_builder_connect_signals (GtkBuilder *builder,
+ gpointer user_data);
+void gtk_builder_connect_signals_full (GtkBuilder *builder,
+ GtkBuilderConnectFunc func,
+ gpointer user_data);
+void gtk_builder_set_translation_domain (GtkBuilder *builder,
+ const gchar *domain);
+const gchar* gtk_builder_get_translation_domain (GtkBuilder *builder);
+GType gtk_builder_get_type_from_name (GtkBuilder *builder,
+ const char *typename);
+
+gboolean gtk_builder_value_from_string (GParamSpec *pspec,
+ const gchar *string,
+ GValue *value);
+gboolean gtk_builder_value_from_string_type (GType type,
+ const gchar *string,
+ GValue *value);
+guint _gtk_builder_flags_from_string (GType type,
+ const char *string);
+
+#define GTK_BUILDER_WARN_INVALID_CHILD_TYPE(object, type) \
+ g_warning ("'%s' is not a valid child type of '%s'", type, g_type_name (G_OBJECT_TYPE (type)))
+
+G_END_DECLS
+
+#endif /* __GTK_BUILDER_H__ */
diff --git a/gtk/gtkbuilderparser.c b/gtk/gtkbuilderparser.c
new file mode 100644
index 0000000000..6d82b35126
--- /dev/null
+++ b/gtk/gtkbuilderparser.c
@@ -0,0 +1,851 @@
+/* gtkbuilderparser.c
+ * Copyright (C) 2006-2007 Async Open Source,
+ * Johan Dahlin <jdahlin@async.com.br>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <string.h>
+#include <glib/gfileutils.h>
+#include <glib/gi18n.h>
+#include <glib/gmacros.h>
+#include <glib/gmessages.h>
+#include <glib/gslist.h>
+#include <glib/gstrfuncs.h>
+#include <glib-object.h>
+#include <gmodule.h>
+
+#include <gdk/gdkenumtypes.h>
+#include <gdk/gdkkeys.h>
+#include <gtk/gtktypeutils.h>
+#include "gtkbuilderprivate.h"
+#include "gtkbuilder.h"
+#include "gtkbuildable.h"
+#include "gtkdebug.h"
+#include "gtktypeutils.h"
+#include "gtkalias.h"
+
+static void free_property_info (PropertyInfo *info,
+ gpointer user_data);
+
+static inline void
+state_push (ParserData *data, gpointer info)
+{
+ data->stack = g_slist_prepend (data->stack, info);
+}
+
+static inline gpointer
+state_peek (ParserData *data)
+{
+ if (!data->stack)
+ return NULL;
+
+ return data->stack->data;
+}
+
+static inline gpointer
+state_pop (ParserData *data)
+{
+ gpointer old = NULL;
+
+ if (!data->stack)
+ return NULL;
+
+ old = data->stack->data;
+ data->stack = g_slist_delete_link (data->stack, data->stack);
+ return old;
+}
+#define state_peek_info(data, st) ((st*)state_peek(data))
+#define state_pop_info(data, st) ((st*)state_pop(data))
+
+static void
+error_missing_attribute (ParserData *data,
+ const gchar *tag,
+ const gchar *attribute,
+ GError **error)
+{
+ gint line_number, char_number;
+
+ g_markup_parse_context_get_position (data->ctx,
+ &line_number,
+ &char_number);
+
+ g_set_error (error,
+ GTK_BUILDER_ERROR,
+ GTK_BUILDER_ERROR_MISSING_ATTRIBUTE,
+ "%s:%d:%d <%s> requires attribute \"%s\"",
+ data->filename,
+ line_number, char_number, tag, attribute);
+}
+
+static void
+error_invalid_attribute (ParserData *data,
+ const gchar *tag,
+ const gchar *attribute,
+ GError **error)
+{
+ gint line_number, char_number;
+
+ g_markup_parse_context_get_position (data->ctx,
+ &line_number,
+ &char_number);
+
+ g_set_error (error,
+ GTK_BUILDER_ERROR,
+ GTK_BUILDER_ERROR_INVALID_ATTRIBUTE,
+ "%s:%d:%d '%s' is not a valid attribute of <%s>",
+ data->filename,
+ line_number, char_number, attribute, tag);
+}
+
+static void
+error_invalid_tag (ParserData *data,
+ const gchar *tag,
+ const gchar *expected,
+ GError **error)
+{
+ gint line_number, char_number;
+
+ g_markup_parse_context_get_position (data->ctx,
+ &line_number,
+ &char_number);
+
+ if (expected)
+ g_set_error (error,
+ GTK_BUILDER_ERROR,
+ GTK_BUILDER_ERROR_INVALID_TAG,
+ "%s:%d:%d '%s' is not a valid tag here, expected a '%s' tag",
+ data->filename,
+ line_number, char_number, tag, expected);
+ else
+ g_set_error (error,
+ GTK_BUILDER_ERROR,
+ GTK_BUILDER_ERROR_INVALID_TAG,
+ "%s:%d:%d '%s' is not a valid tag here",
+ data->filename,
+ line_number, char_number, tag);
+}
+
+static GObject *
+builder_construct (ParserData *data,
+ ObjectInfo *object_info)
+{
+ GObject *object;
+
+ g_assert (object_info != NULL);
+
+ if (object_info->object)
+ return object_info->object;
+
+ object_info->properties = g_slist_reverse (object_info->properties);
+
+ object = _gtk_builder_construct (data->builder, object_info);
+ g_assert (G_IS_OBJECT (object));
+
+ object_info->object = object;
+
+ return object;
+}
+
+static void
+parse_object (ParserData *data,
+ const gchar *element_name,
+ const gchar **names,
+ const gchar **values,
+ GError **error)
+{
+ ObjectInfo *object_info;
+ ChildInfo* child_info;
+ int i;
+ gchar *object_class = NULL;
+ gchar *object_id = NULL;
+ gchar *constructor = NULL;
+
+ child_info = state_peek_info (data, ChildInfo);
+ if (child_info && strcmp (child_info->tag.name, "object") == 0)
+ {
+ error_invalid_tag (data, element_name, NULL, error);
+ return;
+ }
+
+ for (i = 0; names[i] != NULL; i++)
+ {
+ if (strcmp (names[i], "class") == 0)
+ object_class = g_strdup (values[i]);
+ else if (strcmp (names[i], "id") == 0)
+ object_id = g_strdup (values[i]);
+ else if (strcmp (names[i], "constructor") == 0)
+ constructor = g_strdup (values[i]);
+ else
+ {
+ error_invalid_attribute (data, element_name, values[i], error);
+ return;
+ }
+ }
+
+ if (!object_class)
+ {
+ error_missing_attribute (data, element_name, "class", error);
+ return;
+ }
+
+ if (!object_id)
+ {
+ error_missing_attribute (data, element_name, "id", error);
+ return;
+ }
+
+ object_info = g_slice_new0 (ObjectInfo);
+ object_info->class_name = object_class;
+ object_info->id = object_id;
+ object_info->constructor = constructor;
+ state_push (data, object_info);
+ g_assert (state_peek (data) != NULL);
+ object_info->tag.name = element_name;
+
+ if (child_info)
+ object_info->parent = (CommonInfo*)child_info;
+}
+
+static void
+free_object_info (ObjectInfo *info)
+{
+ /* Do not free the signal items, which GtkBuilder takes ownership of */
+ g_slist_free (info->signals);
+ g_slist_foreach (info->properties,
+ (GFunc)free_property_info, NULL);
+ g_slist_free (info->properties);
+ g_free (info->constructor);
+ g_free (info->class_name);
+ g_free (info->id);
+ g_slice_free (ObjectInfo, info);
+}
+
+static gchar *
+_get_type_by_symbol (const gchar* symbol)
+{
+ static GModule *module = NULL;
+ GTypeGetFunc func;
+ GType type;
+
+ if (!module)
+ module = g_module_open (NULL, 0);
+
+ if (!g_module_symbol (module, symbol, (gpointer)&func))
+ return NULL;
+
+ type = func ();
+ if (type == G_TYPE_INVALID)
+ return NULL;
+
+ return g_strdup (g_type_name (type));
+}
+
+static void
+parse_child (ParserData *data,
+ const gchar *element_name,
+ const gchar **names,
+ const gchar **values,
+ GError **error)
+
+{
+ ObjectInfo* object_info;
+ ChildInfo *child_info;
+ guint i;
+
+ object_info = state_peek_info (data, ObjectInfo);
+ if (!object_info || strcmp (object_info->tag.name, "object") != 0)
+ {
+ error_invalid_tag (data, element_name, "object", error);
+ return;
+ }
+
+ child_info = g_slice_new0 (ChildInfo);
+ state_push (data, child_info);
+ g_assert (state_peek (data) != NULL);
+ child_info->tag.name = element_name;
+ for (i = 0; names[i]; i++)
+ {
+ if (strcmp (names[i], "type") == 0)
+ child_info->type = g_strdup (values[i]);
+ else if (strcmp (names[i], "internal-child") == 0)
+ child_info->internal_child = g_strdup (values[i]);
+ else if (strcmp (names[i], "type-func") == 0)
+ {
+ child_info->type = _get_type_by_symbol (values[i]);
+ if (!child_info->type)
+ {
+ g_set_error (error, GTK_BUILDER_ERROR,
+ GTK_BUILDER_ERROR_INVALID_TYPE_FUNCTION,
+ _("Invalid type function: `%s'"),
+ values[i]);
+ return;
+ }
+ }
+ else
+ error_invalid_attribute (data, element_name, values[i], error);
+ }
+
+ child_info->parent = (CommonInfo*)object_info;
+
+ object_info->object = builder_construct (data, object_info);
+}
+
+static void
+free_child_info (ChildInfo *info)
+{
+ g_free (info->type);
+ g_free (info->internal_child);
+ g_slice_free (ChildInfo, info);
+}
+
+static void
+parse_property (ParserData *data,
+ const gchar *element_name,
+ const gchar **names,
+ const gchar **values,
+ GError **error)
+{
+ PropertyInfo *info;
+ gchar *name = NULL;
+ gboolean translatable = FALSE;
+ int i;
+
+ g_assert (data->stack != NULL);
+
+ for (i = 0; names[i] != NULL; i++)
+ {
+ if (strcmp (names[i], "name") == 0)
+ name = g_strdelimit (g_strdup (values[i]), "_", '-');
+ else if (strcmp (names[i], "translatable") == 0)
+ translatable = strcmp (values[i], "yes") == 0;
+ else
+ {
+ error_invalid_attribute (data, element_name, values[i], error);
+ return;
+ }
+ }
+
+ if (!name)
+ {
+ error_missing_attribute (data, element_name, "name", error);
+ return;
+ }
+
+ info = g_slice_new0 (PropertyInfo);
+ info->name = name;
+ info->translatable = translatable;
+ state_push (data, info);
+
+ info->tag.name = element_name;
+}
+
+static void
+free_property_info (PropertyInfo *info,
+ gpointer user_data)
+{
+ g_free (info->data);
+ g_free (info->name);
+ g_slice_free (PropertyInfo, info);
+}
+
+static void
+parse_signal (ParserData *data,
+ const gchar *element_name,
+ const gchar **names,
+ const gchar **values,
+ GError **error)
+{
+ SignalInfo *info;
+ gchar *name = NULL;
+ gchar *handler = NULL;
+ gchar *object = NULL;
+ gboolean after = FALSE;
+ gboolean swapped = FALSE;
+ gboolean swapped_set = FALSE;
+ int i;
+
+ g_assert (data->stack != NULL);
+
+ for (i = 0; names[i] != NULL; i++)
+ {
+ if (strcmp (names[i], "name") == 0)
+ name = g_strdup (values[i]);
+ else if (strcmp (names[i], "handler") == 0)
+ handler = g_strdup (values[i]);
+ else if (strcmp (names[i], "after") == 0)
+ after = strcmp (values[i], "yes") == 0;
+ else if (strcmp (names[i], "swapped") == 0)
+ {
+ swapped = strcmp (values[i], "yes") == 0;
+ swapped_set = TRUE;
+ }
+ else if (strcmp (names[i], "object") == 0)
+ object = g_strdup (values[i]);
+ else
+ {
+ error_invalid_attribute (data, element_name, values[i], error);
+ return;
+ }
+ }
+
+ if (!name)
+ {
+ error_missing_attribute (data, element_name, "name", error);
+ return;
+ }
+ else if (!handler)
+ {
+ error_missing_attribute (data, element_name, "handler", error);
+ return;
+ }
+
+ /* Swapped defaults to FALSE except when object is set */
+ if (object && !swapped_set)
+ swapped = TRUE;
+
+ info = g_slice_new0 (SignalInfo);
+ info->name = name;
+ info->handler = handler;
+ if (after)
+ info->flags |= G_CONNECT_AFTER;
+ if (swapped)
+ info->flags |= G_CONNECT_SWAPPED;
+ info->connect_object_name = object;
+ state_push (data, info);
+
+ info->tag.name = element_name;
+}
+
+/* Called by GtkBuilder */
+void
+_free_signal_info (SignalInfo *info,
+ gpointer user_data)
+{
+ g_free (info->name);
+ g_free (info->handler);
+ g_free (info->connect_object_name);
+ g_free (info->object_name);
+ g_slice_free (SignalInfo, info);
+}
+
+static void
+parse_interface (ParserData *data,
+ const gchar *element_name,
+ const gchar **names,
+ const gchar **values,
+ GError **error)
+{
+ int i;
+
+ for (i = 0; names[i] != NULL; i++)
+ {
+ if (strcmp (names[i], "domain") == 0 && !data->domain)
+ {
+ data->domain = g_strdup (values[i]);
+ break;
+ }
+ else
+ error_invalid_attribute (data, "interface", values[i], error);
+ }
+}
+
+static SubParser *
+create_subparser (GObject *object,
+ GObject *child,
+ const gchar *element_name,
+ GMarkupParser *parser,
+ gpointer user_data)
+{
+ SubParser *subparser;
+
+ subparser = g_slice_new0 (SubParser);
+ subparser->object = object;
+ subparser->child = child;
+ subparser->tagname = g_strdup (element_name);
+ subparser->start = element_name;
+ subparser->parser = g_memdup (parser, sizeof (GMarkupParser));
+ subparser->data = user_data;
+
+ return subparser;
+}
+
+static void
+free_subparser (SubParser *subparser)
+{
+ g_free (subparser->tagname);
+ g_slice_free (SubParser, subparser);
+}
+
+static gboolean
+subparser_start (GMarkupParseContext *context,
+ const gchar *element_name,
+ const gchar **names,
+ const gchar **values,
+ ParserData *data,
+ GError **error)
+{
+ SubParser *subparser = data->subparser;
+
+ if (!subparser->start &&
+ strcmp (element_name, subparser->tagname) == 0)
+ subparser->start = element_name;
+
+ if (subparser->start)
+ {
+ if (subparser->parser->start_element)
+ subparser->parser->start_element (context,
+ element_name, names, values,
+ subparser->data, error);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static void
+subparser_end (GMarkupParseContext *context,
+ const gchar *element_name,
+ ParserData *data,
+ GError **error)
+{
+ if (data->subparser->parser->end_element)
+ data->subparser->parser->end_element (context, element_name,
+ data->subparser->data, error);
+
+ if (!strcmp (data->subparser->start, element_name) == 0)
+ return;
+
+ gtk_buildable_custom_tag_end (GTK_BUILDABLE (data->subparser->object),
+ data->builder,
+ data->subparser->child,
+ element_name,
+ data->subparser->data);
+ g_free (data->subparser->parser);
+
+ if (GTK_BUILDABLE_GET_IFACE (data->subparser->object)->custom_finished)
+ data->custom_finalizers = g_slist_prepend (data->custom_finalizers,
+ data->subparser);
+ else
+ free_subparser (data->subparser);
+
+ data->subparser = NULL;
+}
+
+static gboolean
+parse_custom (GMarkupParseContext *context,
+ const gchar *element_name,
+ const gchar **names,
+ const gchar **values,
+ ParserData *data,
+ GError **error)
+{
+ CommonInfo* parent_info;
+ GMarkupParser parser;
+ gpointer *subparser_data;
+ GObject *object;
+ GObject *child;
+
+ parent_info = state_peek_info (data, CommonInfo);
+ if (!parent_info)
+ return FALSE;
+
+ if (strcmp (parent_info->tag.name, "object") == 0)
+ {
+ ObjectInfo* object_info = (ObjectInfo*)parent_info;
+ if (!object_info->object)
+ object_info->object = _gtk_builder_construct (data->builder,
+ object_info);
+ g_assert (object_info->object);
+ object = object_info->object;
+ child = NULL;
+ }
+ else if (strcmp (parent_info->tag.name, "child") == 0)
+ {
+ ChildInfo* child_info = (ChildInfo*)parent_info;
+
+ _gtk_builder_add (data->builder, child_info);
+
+ object = ((ObjectInfo*)child_info->parent)->object;
+ child = child_info->object;
+ }
+ else
+ return FALSE;
+
+ if (!gtk_buildable_custom_tag_start (GTK_BUILDABLE (object),
+ data->builder,
+ child,
+ element_name,
+ &parser,
+ (gpointer*)&subparser_data))
+ return FALSE;
+
+ data->subparser = create_subparser (object, child, element_name,
+ &parser, subparser_data);
+
+ if (parser.start_element)
+ parser.start_element (context,
+ element_name, names, values,
+ subparser_data, error);
+ return TRUE;
+}
+
+static void
+start_element (GMarkupParseContext *context,
+ const gchar *element_name,
+ const gchar **names,
+ const gchar **values,
+ gpointer user_data,
+ GError **error)
+{
+ ParserData *data = (ParserData*)user_data;
+
+#ifdef GTK_ENABLE_DEBUG
+ if (gtk_debug_flags & GTK_DEBUG_BUILDER)
+ {
+ GString *tags = g_string_new ("");
+ int i;
+ for (i = 0; names[i]; i++)
+ g_string_append_printf (tags, "%s=\"%s\" ", names[i], values[i]);
+
+ if (i)
+ {
+ g_string_insert_c (tags, 0, ' ');
+ g_string_truncate (tags, tags->len - 1);
+ }
+ g_print ("<%s%s>\n", element_name, tags->str);
+ g_string_free (tags, TRUE);
+ }
+#endif
+
+ if (!data->last_element && strcmp (element_name, "interface") != 0)
+ {
+ g_set_error (error, GTK_BUILDER_ERROR,
+ GTK_BUILDER_ERROR_UNHANDLED_TAG,
+ _("Invalid root element: '%s'"),
+ element_name);
+ return;
+ }
+ data->last_element = element_name;
+
+ if (data->subparser)
+ if (!subparser_start (context, element_name, names, values,
+ data, error))
+ return;
+
+ if (strcmp (element_name, "object") == 0)
+ parse_object (data, element_name, names, values, error);
+ else if (strcmp (element_name, "child") == 0)
+ parse_child (data, element_name, names, values, error);
+ else if (strcmp (element_name, "property") == 0)
+ parse_property (data, element_name, names, values, error);
+ else if (strcmp (element_name, "signal") == 0)
+ parse_signal (data, element_name, names, values, error);
+ else if (strcmp (element_name, "interface") == 0)
+ parse_interface (data, element_name, names, values, error);
+ else if (strcmp (element_name, "placeholder") == 0)
+ {
+ /* placeholder has no special treatmeant, but it needs an
+ * if clause to avoid an error below.
+ */
+ }
+ else
+ if (!parse_custom (context, element_name, names, values,
+ data, error))
+ g_set_error (error, GTK_BUILDER_ERROR,
+ GTK_BUILDER_ERROR_UNHANDLED_TAG,
+ _("Unhandled tag: '%s'"),
+ element_name);
+}
+
+/* Called for close tags </foo> */
+static void
+end_element (GMarkupParseContext *context,
+ const gchar *element_name,
+ gpointer user_data,
+ GError **error)
+{
+ ParserData *data = (ParserData*)user_data;
+
+ GTK_NOTE (BUILDER, g_print ("</%s>\n", element_name));
+
+ if (data->subparser && data->subparser->start)
+ {
+ subparser_end (context, element_name, data, error);
+ return;
+ }
+
+ if (strcmp (element_name, "object") == 0)
+ {
+ ObjectInfo *object_info = state_pop_info (data, ObjectInfo);
+ ChildInfo* child_info = state_peek_info (data, ChildInfo);
+
+ object_info->object = builder_construct (data, object_info);
+
+ if (child_info)
+ child_info->object = object_info->object;
+
+ if (GTK_IS_BUILDABLE (object_info->object) &&
+ GTK_BUILDABLE_GET_IFACE (object_info->object)->parser_finished)
+ data->finalizers = g_slist_prepend (data->finalizers, object_info->object);
+ free_object_info (object_info);
+ }
+ else if (strcmp (element_name, "property") == 0)
+ {
+ PropertyInfo *prop_info = state_pop_info (data, PropertyInfo);
+ CommonInfo *info = state_peek_info (data, CommonInfo);
+
+ /* Normal properties */
+ if (strcmp (info->tag.name, "object") == 0)
+ {
+ ObjectInfo *object_info = (ObjectInfo*)info;
+ object_info->properties =
+ g_slist_prepend (object_info->properties, prop_info);
+ }
+ else
+ g_assert_not_reached ();
+ }
+ else if (strcmp (element_name, "child") == 0)
+ {
+ ChildInfo *child_info = state_pop_info (data, ChildInfo);
+
+ _gtk_builder_add (data->builder, child_info);
+
+ free_child_info (child_info);
+ }
+ else if (strcmp (element_name, "signal") == 0)
+ {
+ SignalInfo *signal_info = state_pop_info (data, SignalInfo);
+ ObjectInfo *object_info = (ObjectInfo*)state_peek_info (data, CommonInfo);
+ signal_info->object_name = g_strdup (object_info->id);
+ object_info->signals =
+ g_slist_prepend (object_info->signals, signal_info);
+ }
+ else if (strcmp (element_name, "interface") == 0)
+ {
+ }
+ else if (strcmp (element_name, "placeholder") == 0)
+ {
+ }
+ else
+ {
+ g_assert_not_reached ();
+ }
+}
+
+/* Called for character data */
+/* text is not nul-terminated */
+static void
+text (GMarkupParseContext *context,
+ const gchar *text,
+ gsize text_len,
+ gpointer user_data,
+ GError **error)
+{
+ ParserData *data = (ParserData*)user_data;
+ CommonInfo *info;
+
+ if (data->subparser && data->subparser->start)
+ {
+ if (data->subparser->parser->text)
+ data->subparser->parser->text (context, text, text_len,
+ data->subparser->data, error);
+ return;
+ }
+
+ if (!data->stack)
+ return;
+
+ info = state_peek_info (data, CommonInfo);
+ g_assert (info != NULL);
+
+ if (strcmp (g_markup_parse_context_get_element (context), "property") == 0)
+ {
+ PropertyInfo *prop_info = (PropertyInfo*)info;
+
+ if (prop_info->translatable && text_len)
+ {
+ if (data->domain)
+ text = dgettext (text, data->domain);
+ else
+ text = gettext (text);
+ }
+ prop_info->data = g_strndup (text, text_len);
+ }
+}
+
+static const GMarkupParser parser = {
+ start_element,
+ end_element,
+ text,
+ NULL,
+ NULL
+};
+
+void
+_gtk_builder_parser_parse_buffer (GtkBuilder *builder,
+ const gchar *filename,
+ const gchar *buffer,
+ gsize length,
+ GError **error)
+{
+ ParserData *data;
+ GSList *l;
+
+ data = g_new0 (ParserData, 1);
+ data->builder = builder;
+ data->filename = filename;
+ data->domain = g_strdup (gtk_builder_get_translation_domain (builder));
+
+ data->ctx = g_markup_parse_context_new (
+ &parser, G_MARKUP_TREAT_CDATA_AS_TEXT, data, NULL);
+
+ if (!g_markup_parse_context_parse (data->ctx, buffer, length, error))
+ goto out;
+
+ gtk_builder_set_translation_domain (data->builder, data->domain);
+ _gtk_builder_finish (builder);
+
+ /* Custom parser_finished */
+ data->custom_finalizers = g_slist_reverse (data->custom_finalizers);
+ for (l = data->custom_finalizers; l; l = l->next)
+ {
+ SubParser *sub = (SubParser*)l->data;
+
+ gtk_buildable_custom_finished (GTK_BUILDABLE (sub->object),
+ builder,
+ sub->child,
+ sub->tagname,
+ sub->data);
+ free_subparser (sub);
+ }
+
+ /* Common parser_finished, for all created objects */
+ data->finalizers = g_slist_reverse (data->finalizers);
+ for (l = data->finalizers; l; l = l->next)
+ {
+ GtkBuildable *buildable = (GtkBuildable*)l->data;
+ gtk_buildable_parser_finished (GTK_BUILDABLE (buildable), builder);
+ }
+
+ out:
+ g_markup_parse_context_free (data->ctx);
+
+ g_slist_free (data->stack);
+ g_slist_free (data->custom_finalizers);
+ g_slist_free (data->finalizers);
+ g_free (data->domain);
+ g_free (data);
+}
diff --git a/gtk/gtkbuilderprivate.h b/gtk/gtkbuilderprivate.h
new file mode 100644
index 0000000000..1a65d48cc4
--- /dev/null
+++ b/gtk/gtkbuilderprivate.h
@@ -0,0 +1,111 @@
+/* gtkbuilderprivate.h
+ * Copyright (C) 2006-2007 Async Open Source,
+ * Johan Dahlin <jdahlin@async.com.br>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GTK_BUILDER_PRIVATE_H__
+#define __GTK_BUILDER_PRIVATE_H__
+
+#include <glib/gmarkup.h>
+#include <glib/gslist.h>
+
+#include <glib-object.h>
+#include "gtkbuilder.h"
+
+typedef struct {
+ const gchar *name;
+} TagInfo;
+
+typedef struct {
+ TagInfo tag;
+} CommonInfo;
+
+typedef struct {
+ TagInfo tag;
+ gchar *class_name;
+ gchar *id;
+ gchar *constructor;
+ GSList *properties;
+ GSList *signals;
+ GObject *object;
+ CommonInfo *parent;
+} ObjectInfo;
+
+typedef struct {
+ TagInfo tag;
+ GSList *packing_properties;
+ GObject *object;
+ CommonInfo *parent;
+ gchar *type;
+ gchar *internal_child;
+ gboolean added;
+} ChildInfo;
+
+typedef struct {
+ TagInfo tag;
+ gchar *name;
+ gchar *data;
+ gboolean translatable;
+} PropertyInfo;
+
+typedef struct {
+ TagInfo tag;
+ gchar *object_name;
+ gchar *name;
+ gchar *handler;
+ GConnectFlags flags;
+ gchar *connect_object_name;
+} SignalInfo;
+
+typedef struct {
+ GMarkupParser *parser;
+ gchar *tagname;
+ const gchar *start;
+ gpointer data;
+ GObject *object;
+ GObject *child;
+} SubParser;
+
+typedef struct {
+ const gchar *last_element;
+ GtkBuilder *builder;
+ gchar *domain;
+ GSList *stack;
+ SubParser *subparser;
+ GMarkupParseContext *ctx;
+ const gchar *filename;
+ GSList *finalizers;
+ GSList *custom_finalizers;
+} ParserData;
+
+typedef GType (*GTypeGetFunc) (void);
+
+void _gtk_builder_parser_parse_buffer (GtkBuilder *builder,
+ const gchar *filename,
+ const gchar *buffer,
+ gsize length,
+ GError **error);
+GObject * _gtk_builder_construct (GtkBuilder *builder,
+ ObjectInfo *info);
+void _gtk_builder_add (GtkBuilder *builder,
+ ChildInfo *child_info);
+void _gtk_builder_finish (GtkBuilder *builder);
+void _free_signal_info (SignalInfo *info,
+ gpointer user_data);
+
+#endif /* __GTK_BUILDER_PRIVATE_H__ */
diff --git a/gtk/gtkcelllayout.c b/gtk/gtkcelllayout.c
index 10cf3c4267..89f0a1ab03 100644
--- a/gtk/gtkcelllayout.c
+++ b/gtk/gtkcelllayout.c
@@ -17,6 +17,8 @@
* Boston, MA 02111-1307, USA.
*/
+#include <string.h>
+#include <stdlib.h>
#include <config.h>
#include "gtkcelllayout.h"
#include "gtkintl.h"
@@ -309,5 +311,115 @@ gtk_cell_layout_get_cells (GtkCellLayout *cell_layout)
return NULL;
}
+typedef struct {
+ GtkCellLayout *cell_layout;
+ GtkCellRenderer *renderer;
+ gchar *attr_name;
+} AttributesSubParserData;
+
+static void
+attributes_start_element (GMarkupParseContext *context,
+ const gchar *element_name,
+ const gchar **names,
+ const gchar **values,
+ gpointer user_data,
+ GError **error)
+{
+ AttributesSubParserData *parser_data = (AttributesSubParserData*)user_data;
+ guint i;
+
+ if (strcmp (element_name, "attribute") == 0)
+ for (i = 0; names[i]; i++)
+ if (strcmp (names[i], "name") == 0)
+ parser_data->attr_name = g_strdup (values[i]);
+ else if (strcmp (element_name, "attributes") == 0)
+ return;
+ else
+ g_warning ("Unsupported tag for GtkCellLayout: %s\n", element_name);
+}
+
+static void
+attributes_text_element (GMarkupParseContext *context,
+ const gchar *text,
+ gsize text_len,
+ gpointer user_data,
+ GError **error)
+{
+ AttributesSubParserData *parser_data = (AttributesSubParserData*)user_data;
+
+ if (!parser_data->attr_name)
+ return;
+ gtk_cell_layout_add_attribute (parser_data->cell_layout,
+ parser_data->renderer,
+ parser_data->attr_name, atoi (text));
+ g_free (parser_data->attr_name);
+ parser_data->attr_name = NULL;
+}
+
+static const GMarkupParser attributes_parser =
+ {
+ attributes_start_element,
+ NULL,
+ attributes_text_element,
+ };
+
+gboolean
+_gtk_cell_layout_buildable_custom_tag_start (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *tagname,
+ GMarkupParser *parser,
+ gpointer *data)
+{
+ AttributesSubParserData *parser_data;
+
+ if (!child)
+ return FALSE;
+
+ if (strcmp (tagname, "attributes") == 0)
+ {
+ parser_data = g_slice_new0 (AttributesSubParserData);
+ parser_data->cell_layout = GTK_CELL_LAYOUT (buildable);
+ parser_data->renderer = GTK_CELL_RENDERER (child);
+ parser_data->attr_name = NULL;
+
+ *parser = attributes_parser;
+ *data = parser_data;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+void
+_gtk_cell_layout_buildable_custom_tag_end (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *tagname,
+ gpointer *data)
+{
+ AttributesSubParserData *parser_data;
+
+ parser_data = (AttributesSubParserData*)data;
+ g_assert (!parser_data->attr_name);
+ g_slice_free (AttributesSubParserData, parser_data);
+}
+
+void
+_gtk_cell_layout_buildable_add (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *type)
+{
+ GtkCellLayoutIface *iface;
+
+ g_return_if_fail (GTK_IS_CELL_LAYOUT (buildable));
+ g_return_if_fail (GTK_IS_CELL_RENDERER (child));
+
+ iface = GTK_CELL_LAYOUT_GET_IFACE (buildable);
+ g_return_if_fail (iface->pack_end != NULL);
+ iface->pack_end (GTK_CELL_LAYOUT (buildable), GTK_CELL_RENDERER (child), FALSE);
+}
+
#define __GTK_CELL_LAYOUT_C__
#include "gtkaliasdef.c"
diff --git a/gtk/gtkcelllayout.h b/gtk/gtkcelllayout.h
index 520f35dbc1..8e2e272cb2 100644
--- a/gtk/gtkcelllayout.h
+++ b/gtk/gtkcelllayout.h
@@ -24,6 +24,8 @@
#include <gtk/gtkcellrenderer.h>
#include <gtk/gtktreeviewcolumn.h>
+#include <gtk/gtkbuildable.h>
+#include <gtk/gtkbuilder.h>
G_BEGIN_DECLS
@@ -97,7 +99,21 @@ void gtk_cell_layout_clear_attributes (GtkCellLayout *cell_layout,
void gtk_cell_layout_reorder (GtkCellLayout *cell_layout,
GtkCellRenderer *cell,
gint position);
-
+gboolean _gtk_cell_layout_buildable_custom_tag_start (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *tagname,
+ GMarkupParser *parser,
+ gpointer *data);
+void _gtk_cell_layout_buildable_custom_tag_end (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *tagname,
+ gpointer *data);
+void _gtk_cell_layout_buildable_add (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *type);
G_END_DECLS
diff --git a/gtk/gtkcellview.c b/gtk/gtkcellview.c
index 1cd3fc7065..f9d49896ad 100644
--- a/gtk/gtkcellview.c
+++ b/gtk/gtkcellview.c
@@ -18,6 +18,7 @@
*/
#include <config.h>
+#include <string.h>
#include "gtkcellview.h"
#include "gtkcelllayout.h"
#include "gtkintl.h"
@@ -26,6 +27,7 @@
#include "gtkcellrendererpixbuf.h"
#include "gtkprivate.h"
#include <gobject/gmarshal.h>
+#include "gtkbuildable.h"
#include "gtkalias.h"
typedef struct _GtkCellViewCellInfo GtkCellViewCellInfo;
@@ -105,6 +107,22 @@ static void gtk_cell_view_cell_layout_reorder (GtkCellLayout
gint position);
static GList * gtk_cell_view_cell_layout_get_cells (GtkCellLayout *layout);
+/* buildable */
+static void gtk_cell_view_buildable_init (GtkBuildableIface *iface);
+static gboolean gtk_cell_view_buildable_custom_tag_start (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *tagname,
+ GMarkupParser *parser,
+ gpointer *data);
+static void gtk_cell_view_buildable_custom_tag_end (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *tagname,
+ gpointer *data);
+
+static GtkBuildableIface *parent_buildable_iface;
+
#define GTK_CELL_VIEW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_CELL_VIEW, GtkCellViewPrivate))
enum
@@ -118,7 +136,9 @@ enum
G_DEFINE_TYPE_WITH_CODE (GtkCellView, gtk_cell_view, GTK_TYPE_WIDGET,
G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_LAYOUT,
- gtk_cell_view_cell_layout_init))
+ gtk_cell_view_cell_layout_init)
+ G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
+ gtk_cell_view_buildable_init))
static void
gtk_cell_view_class_init (GtkCellViewClass *klass)
@@ -175,6 +195,15 @@ gtk_cell_view_class_init (GtkCellViewClass *klass)
}
static void
+gtk_cell_view_buildable_init (GtkBuildableIface *iface)
+{
+ parent_buildable_iface = g_type_interface_peek_parent (iface);
+ iface->add = _gtk_cell_layout_buildable_add;
+ iface->custom_tag_start = gtk_cell_view_buildable_custom_tag_start;
+ iface->custom_tag_end = gtk_cell_view_buildable_custom_tag_end;
+}
+
+static void
gtk_cell_view_cell_layout_init (GtkCellLayoutIface *iface)
{
iface->pack_start = gtk_cell_view_cell_layout_pack_start;
@@ -1068,5 +1097,37 @@ gtk_cell_view_cell_layout_get_cells (GtkCellLayout *layout)
}
+static gboolean
+gtk_cell_view_buildable_custom_tag_start (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *tagname,
+ GMarkupParser *parser,
+ gpointer *data)
+{
+ if (parent_buildable_iface->custom_tag_start (buildable, builder, child,
+ tagname, parser, data))
+ return TRUE;
+
+ return _gtk_cell_layout_buildable_custom_tag_start (buildable, builder, child,
+ tagname, parser, data);
+}
+
+static void
+gtk_cell_view_buildable_custom_tag_end (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *tagname,
+ gpointer *data)
+{
+ if (strcmp (tagname, "attributes") == 0)
+ _gtk_cell_layout_buildable_custom_tag_end (buildable, builder, child, tagname,
+ data);
+ else
+ parent_buildable_iface->custom_tag_end (buildable, builder, child, tagname,
+ data);
+}
+
+
#define __GTK_CELL_VIEW_C__
#include "gtkaliasdef.c"
diff --git a/gtk/gtkcolorseldialog.c b/gtk/gtkcolorseldialog.c
index 1f427ca43e..d1b7c00603 100644
--- a/gtk/gtkcolorseldialog.c
+++ b/gtk/gtkcolorseldialog.c
@@ -24,6 +24,7 @@
* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
*/
#include <config.h>
+#include <string.h>
#include <glib.h>
#include "gtkcolorseldialog.h"
#include "gtkframe.h"
@@ -31,6 +32,7 @@
#include "gtkbutton.h"
#include "gtkstock.h"
#include "gtkintl.h"
+#include "gtkbuildable.h"
#include "gtkalias.h"
@@ -38,7 +40,17 @@
/* GtkColorSelectionDialog */
/***************************/
-G_DEFINE_TYPE (GtkColorSelectionDialog, gtk_color_selection_dialog, GTK_TYPE_DIALOG)
+static void gtk_color_selection_dialog_buildable_interface_init (GtkBuildableIface *iface);
+static GObject * gtk_color_selection_dialog_buildable_get_internal_child (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ const gchar *childname);
+
+G_DEFINE_TYPE_WITH_CODE (GtkColorSelectionDialog, gtk_color_selection_dialog,
+ GTK_TYPE_DIALOG,
+ G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
+ gtk_color_selection_dialog_buildable_interface_init))
+
+static GtkBuildableIface *parent_buildable_iface;
static void
gtk_color_selection_dialog_class_init (GtkColorSelectionDialogClass *klass)
@@ -106,5 +118,30 @@ gtk_color_selection_dialog_new (const gchar *title)
return GTK_WIDGET (colorseldiag);
}
+static void
+gtk_color_selection_dialog_buildable_interface_init (GtkBuildableIface *iface)
+{
+ parent_buildable_iface = g_type_interface_peek_parent (iface);
+ iface->get_internal_child = gtk_color_selection_dialog_buildable_get_internal_child;
+}
+
+static GObject *
+gtk_color_selection_dialog_buildable_get_internal_child (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ const gchar *childname)
+{
+ if (strcmp(childname, "ok_button") == 0)
+ return G_OBJECT (GTK_COLOR_SELECTION_DIALOG (buildable)->ok_button);
+ else if (strcmp(childname, "cancel_button") == 0)
+ return G_OBJECT (GTK_COLOR_SELECTION_DIALOG (buildable)->cancel_button);
+ else if (strcmp(childname, "help_button") == 0)
+ return G_OBJECT (GTK_COLOR_SELECTION_DIALOG(buildable)->help_button);
+ else if (strcmp(childname, "color_selection") == 0)
+ return G_OBJECT (GTK_COLOR_SELECTION_DIALOG(buildable)->colorsel);
+
+ return parent_buildable_iface->get_internal_child (buildable, builder, childname);
+}
+
+
#define __GTK_COLOR_SELECTION_DIALOG_C__
#include "gtkaliasdef.c"
diff --git a/gtk/gtkcombobox.c b/gtk/gtkcombobox.c
index 14dfbe34da..742de106e5 100644
--- a/gtk/gtkcombobox.c
+++ b/gtk/gtkcombobox.c
@@ -438,6 +438,21 @@ static void gtk_combo_box_child_show (GtkWidget *w
static void gtk_combo_box_child_hide (GtkWidget *widget,
GtkComboBox *combo_box);
+/* GtkBuildable method implementation */
+static GtkBuildableIface *parent_buildable_iface;
+
+static void gtk_combo_box_buildable_init (GtkBuildableIface *iface);
+static gboolean gtk_combo_box_buildable_custom_tag_start (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *tagname,
+ GMarkupParser *parser,
+ gpointer *data);
+static void gtk_combo_box_buildable_custom_tag_end (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *tagname,
+ gpointer *data);
/* GtkCellEditable method implementations */
static void gtk_combo_box_start_editing (GtkCellEditable *cell_editable,
@@ -448,7 +463,10 @@ G_DEFINE_TYPE_WITH_CODE (GtkComboBox, gtk_combo_box, GTK_TYPE_BIN,
G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_LAYOUT,
gtk_combo_box_cell_layout_init)
G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_EDITABLE,
- gtk_combo_box_cell_editable_init))
+ gtk_combo_box_cell_editable_init)
+ G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
+ gtk_combo_box_buildable_init))
+
/* common */
static void
@@ -814,6 +832,15 @@ gtk_combo_box_class_init (GtkComboBoxClass *klass)
}
static void
+gtk_combo_box_buildable_init (GtkBuildableIface *iface)
+{
+ parent_buildable_iface = g_type_interface_peek_parent (iface);
+ iface->add = _gtk_cell_layout_buildable_add;
+ iface->custom_tag_start = gtk_combo_box_buildable_custom_tag_start;
+ iface->custom_tag_end = gtk_combo_box_buildable_custom_tag_end;
+}
+
+static void
gtk_combo_box_cell_layout_init (GtkCellLayoutIface *iface)
{
iface->pack_start = gtk_combo_box_cell_layout_pack_start;
@@ -5583,5 +5610,36 @@ gtk_combo_box_get_focus_on_click (GtkComboBox *combo_box)
}
+static gboolean
+gtk_combo_box_buildable_custom_tag_start (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *tagname,
+ GMarkupParser *parser,
+ gpointer *data)
+{
+ if (parent_buildable_iface->custom_tag_start (buildable, builder, child,
+ tagname, parser, data))
+ return TRUE;
+
+ return _gtk_cell_layout_buildable_custom_tag_start (buildable, builder, child,
+ tagname, parser, data);
+}
+
+static void
+gtk_combo_box_buildable_custom_tag_end (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *tagname,
+ gpointer *data)
+{
+ if (strcmp (tagname, "attributes") == 0)
+ _gtk_cell_layout_buildable_custom_tag_end (buildable, builder, child, tagname,
+ data);
+ else
+ parent_buildable_iface->custom_tag_end (buildable, builder, child, tagname,
+ data);
+}
+
#define __GTK_COMBO_BOX_C__
#include "gtkaliasdef.c"
diff --git a/gtk/gtkcomboboxentry.c b/gtk/gtkcomboboxentry.c
index f8b698a849..eff22d5c44 100644
--- a/gtk/gtkcomboboxentry.c
+++ b/gtk/gtkcomboboxentry.c
@@ -18,6 +18,7 @@
*/
#include <config.h>
+#include <string.h>
#include "gtkcomboboxentry.h"
#include "gtkcelllayout.h"
@@ -26,6 +27,7 @@
#include "gtkprivate.h"
#include "gtkintl.h"
+#include "gtkbuildable.h"
#include "gtkalias.h"
#define GTK_COMBO_BOX_ENTRY_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_COMBO_BOX_ENTRY, GtkComboBoxEntryPrivate))
@@ -60,6 +62,10 @@ static void gtk_combo_box_entry_grab_focus (GtkWidget *widget);
static void has_frame_changed (GtkComboBoxEntry *entry_box,
GParamSpec *pspec,
gpointer data);
+static void gtk_combo_box_entry_buildable_interface_init (GtkBuildableIface *iface);
+static GObject * gtk_combo_box_entry_buildable_get_internal_child (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ const gchar *childname);
enum
{
@@ -67,7 +73,9 @@ enum
PROP_TEXT_COLUMN
};
-G_DEFINE_TYPE (GtkComboBoxEntry, gtk_combo_box_entry, GTK_TYPE_COMBO_BOX)
+G_DEFINE_TYPE_WITH_CODE (GtkComboBoxEntry, gtk_combo_box_entry, GTK_TYPE_COMBO_BOX,
+ G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
+ gtk_combo_box_entry_buildable_interface_init))
static void
gtk_combo_box_entry_class_init (GtkComboBoxEntryClass *klass)
@@ -130,6 +138,23 @@ gtk_combo_box_entry_init (GtkComboBoxEntry *entry_box)
}
static void
+gtk_combo_box_entry_buildable_interface_init (GtkBuildableIface *iface)
+{
+ iface->get_internal_child = gtk_combo_box_entry_buildable_get_internal_child;
+}
+
+static GObject *
+gtk_combo_box_entry_buildable_get_internal_child (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ const gchar *childname)
+{
+ if (strcmp (childname, "entry") == 0)
+ return G_OBJECT (gtk_bin_get_child (GTK_BIN (buildable)));
+
+ return NULL;
+}
+
+static void
gtk_combo_box_entry_set_property (GObject *object,
guint prop_id,
const GValue *value,
diff --git a/gtk/gtkcontainer.c b/gtk/gtkcontainer.c
index 2040503d95..9305db57d8 100644
--- a/gtk/gtkcontainer.c
+++ b/gtk/gtkcontainer.c
@@ -30,6 +30,7 @@
#include <stdlib.h>
#include "gtkcontainer.h"
+#include "gtkbuildable.h"
#include "gtkprivate.h"
#include "gtkmain.h"
#include "gtkmarshalers.h"
@@ -99,6 +100,24 @@ static void gtk_container_unmap (GtkWidget *widget);
static gchar* gtk_container_child_default_composite_name (GtkContainer *container,
GtkWidget *child);
+/* GtkBuildable */
+static void gtk_container_buildable_init (GtkBuildableIface *iface);
+static void gtk_container_buildable_add (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *type);
+static gboolean gtk_container_buildable_custom_tag_start (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *tagname,
+ GMarkupParser *parser,
+ gpointer *data);
+static void gtk_container_buildable_custom_tag_end (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *tagname,
+ gpointer *data);
+
/* --- variables --- */
static const gchar vadjustment_key[] = "gtk-vadjustment";
@@ -110,6 +129,7 @@ static guint container_signals[LAST_SIGNAL] = { 0 };
static GtkWidgetClass *parent_class = NULL;
extern GParamSpecPool *_gtk_widget_child_property_pool;
extern GObjectNotifyContext *_gtk_widget_child_property_notify_context;
+static GtkBuildableIface *parent_buildable_iface;
/* --- functions --- */
@@ -134,9 +154,21 @@ gtk_container_get_type (void)
NULL, /* value_table */
};
+ static const GInterfaceInfo buildable_info =
+ {
+ (GInterfaceInitFunc) gtk_container_buildable_init,
+ NULL,
+ NULL
+ };
+
container_type =
g_type_register_static (GTK_TYPE_WIDGET, I_("GtkContainer"),
&container_info, G_TYPE_FLAG_ABSTRACT);
+
+ g_type_add_interface_static (container_type,
+ GTK_TYPE_BUILDABLE,
+ &buildable_info);
+
}
return container_type;
@@ -260,6 +292,164 @@ gtk_container_class_init (GtkContainerClass *class)
GTK_TYPE_WIDGET);
}
+static void
+gtk_container_buildable_init (GtkBuildableIface *iface)
+{
+ parent_buildable_iface = g_type_interface_peek_parent (iface);
+ iface->add = gtk_container_buildable_add;
+ iface->custom_tag_start = gtk_container_buildable_custom_tag_start;
+ iface->custom_tag_end = gtk_container_buildable_custom_tag_end;
+}
+
+static void
+gtk_container_buildable_add (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *type)
+{
+ g_return_if_fail (GTK_IS_WIDGET (child));
+
+ gtk_container_add (GTK_CONTAINER (buildable), GTK_WIDGET (child));
+}
+
+static void
+gtk_container_buildable_set_child_property (GtkContainer *container,
+ GtkWidget *child,
+ gchar *name,
+ const gchar *value)
+{
+ GParamSpec *pspec;
+ GValue gvalue = { 0, };
+
+ pspec = gtk_container_class_find_child_property
+ (G_OBJECT_GET_CLASS (container), name);
+ if (!pspec)
+ {
+ g_warning ("%s does not have a property called %s",
+ g_type_name (G_OBJECT_TYPE (container)), name);
+ return;
+ }
+
+ if (!gtk_builder_value_from_string (pspec, value, &gvalue))
+ {
+ g_warning ("Could not read property %s:%s with value %s of type %s",
+ g_type_name (G_OBJECT_TYPE (container)),
+ name,
+ value,
+ g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)));
+ return;
+ }
+
+ gtk_container_child_set_property (container, child, name, &gvalue);
+ g_value_unset (&gvalue);
+}
+
+typedef struct {
+ GtkBuilder *builder;
+ GtkContainer *container;
+ GtkWidget *child;
+ gchar *child_prop_name;
+} PackingPropertiesData;
+
+static void
+attributes_start_element (GMarkupParseContext *context,
+ const gchar *element_name,
+ const gchar **names,
+ const gchar **values,
+ gpointer user_data,
+ GError **error)
+{
+ PackingPropertiesData *parser_data = (PackingPropertiesData*)user_data;
+ guint i;
+
+ if (strcmp (element_name, "property") == 0)
+ for (i = 0; names[i]; i++)
+ if (strcmp (names[i], "name") == 0)
+ parser_data->child_prop_name = g_strdup (values[i]);
+ else if (strcmp (element_name, "packing") == 0)
+ return;
+ else
+ g_warning ("Unsupported tag for GtkContainer: %s\n", element_name);
+}
+
+static void
+attributes_text_element (GMarkupParseContext *context,
+ const gchar *text,
+ gsize text_len,
+ gpointer user_data,
+ GError **error)
+{
+ PackingPropertiesData *parser_data = (PackingPropertiesData*)user_data;
+
+ if (!parser_data->child_prop_name)
+ return;
+
+ gtk_container_buildable_set_child_property (parser_data->container,
+ parser_data->child,
+ parser_data->child_prop_name,
+ text);
+
+ g_free (parser_data->child_prop_name);
+ parser_data->child_prop_name = NULL;
+}
+
+static const GMarkupParser attributes_parser =
+ {
+ attributes_start_element,
+ NULL,
+ attributes_text_element,
+ };
+
+static gboolean
+gtk_container_buildable_custom_tag_start (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *tagname,
+ GMarkupParser *parser,
+ gpointer *data)
+{
+ PackingPropertiesData *parser_data;
+
+ if (parent_buildable_iface->custom_tag_start (buildable, builder, child,
+ tagname, parser, data))
+ return TRUE;
+
+ if (child && strcmp (tagname, "packing") == 0)
+ {
+ parser_data = g_slice_new0 (PackingPropertiesData);
+ parser_data->builder = builder;
+ parser_data->container = GTK_CONTAINER (buildable);
+ parser_data->child = GTK_WIDGET (child);
+ parser_data->child_prop_name = NULL;
+
+ *parser = attributes_parser;
+ *data = parser_data;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void
+gtk_container_buildable_custom_tag_end (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *tagname,
+ gpointer *data)
+{
+ if (strcmp (tagname, "packing") == 0)
+ {
+ g_slice_free (PackingPropertiesData, (gpointer)data);
+ return;
+
+ }
+
+ if (parent_buildable_iface->custom_tag_end)
+ parent_buildable_iface->custom_tag_end (buildable, builder,
+ child, tagname, data);
+
+}
+
/**
* gtk_container_child_type:
* @container: a #GtkContainer
diff --git a/gtk/gtkdebug.h b/gtk/gtkdebug.h
index c70c61768a..5b148c8862 100644
--- a/gtk/gtkdebug.h
+++ b/gtk/gtkdebug.h
@@ -42,7 +42,8 @@ typedef enum {
GTK_DEBUG_MODULES = 1 << 7,
GTK_DEBUG_GEOMETRY = 1 << 8,
GTK_DEBUG_ICONTHEME = 1 << 9,
- GTK_DEBUG_PRINTING = 1 << 10
+ GTK_DEBUG_PRINTING = 1 << 10,
+ GTK_DEBUG_BUILDER = 1 << 11
} GtkDebugFlag;
#ifdef G_ENABLE_DEBUG
diff --git a/gtk/gtkdialog.c b/gtk/gtkdialog.c
index 93c6ce70f9..2419689487 100644
--- a/gtk/gtkdialog.c
+++ b/gtk/gtkdialog.c
@@ -24,6 +24,8 @@
* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
*/
+#include <stdlib.h>
+#include <string.h>
#include <config.h>
#include "gtkbutton.h"
#include "gtkdialog.h"
@@ -37,6 +39,7 @@
#include "gtkintl.h"
#include "gtkbindings.h"
#include "gtkprivate.h"
+#include "gtkbuildable.h"
#include "gtkalias.h"
#define GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_DIALOG, GtkDialogPrivate))
@@ -76,6 +79,22 @@ static void gtk_dialog_close (GtkDialog *dialog);
static ResponseData* get_response_data (GtkWidget *widget,
gboolean create);
+static void gtk_dialog_buildable_interface_init (GtkBuildableIface *iface);
+static GObject * gtk_dialog_buildable_get_internal_child (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ const gchar *childname);
+static gboolean gtk_dialog_buildable_custom_tag_start (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *tagname,
+ GMarkupParser *parser,
+ gpointer *data);
+static void gtk_dialog_buildable_custom_finished (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *tagname,
+ gpointer user_data);
+
enum {
PROP_0,
@@ -90,7 +109,9 @@ enum {
static guint dialog_signals[LAST_SIGNAL];
-G_DEFINE_TYPE (GtkDialog, gtk_dialog, GTK_TYPE_WINDOW)
+G_DEFINE_TYPE_WITH_CODE (GtkDialog, gtk_dialog, GTK_TYPE_WINDOW,
+ G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
+ gtk_dialog_buildable_interface_init))
static void
gtk_dialog_class_init (GtkDialogClass *class)
@@ -235,6 +256,26 @@ gtk_dialog_init (GtkDialog *dialog)
gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER_ON_PARENT);
}
+static void
+gtk_dialog_buildable_interface_init (GtkBuildableIface *iface)
+{
+ iface->get_internal_child = gtk_dialog_buildable_get_internal_child;
+ iface->custom_tag_start = gtk_dialog_buildable_custom_tag_start;
+ iface->custom_finished = gtk_dialog_buildable_custom_finished;
+}
+
+static GObject *
+gtk_dialog_buildable_get_internal_child (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ const gchar *childname)
+{
+ if (strcmp (childname, "vbox") == 0)
+ return G_OBJECT (GTK_DIALOG (buildable)->vbox);
+ else if (strcmp (childname, "action_area") == 0)
+ return G_OBJECT (GTK_DIALOG (buildable)->action_area);
+
+ return NULL;
+}
static void
gtk_dialog_set_property (GObject *object,
@@ -1216,5 +1257,134 @@ gtk_dialog_set_alternative_button_order_from_array (GtkDialog *dialog,
}
}
+typedef struct {
+ gchar *widget_name;
+ gchar *response_id;
+} ActionWidgetInfo;
+
+typedef struct {
+ GtkDialog *dialog;
+ GtkBuilder *builder;
+ GSList *items;
+ gchar *response;
+} ActionWidgetsSubParserData;
+
+static void
+attributes_start_element (GMarkupParseContext *context,
+ const gchar *element_name,
+ const gchar **names,
+ const gchar **values,
+ gpointer user_data,
+ GError **error)
+{
+ ActionWidgetsSubParserData *parser_data = (ActionWidgetsSubParserData*)user_data;
+ guint i;
+
+ if (strcmp (element_name, "action-widget") == 0)
+ for (i = 0; names[i]; i++)
+ if (strcmp (names[i], "response") == 0)
+ parser_data->response = g_strdup (values[i]);
+ else if (strcmp (element_name, "action-widgets") == 0)
+ return;
+ else
+ g_warning ("Unsupported tag for GtkDialog: %s\n", element_name);
+}
+
+static void
+attributes_text_element (GMarkupParseContext *context,
+ const gchar *text,
+ gsize text_len,
+ gpointer user_data,
+ GError **error)
+{
+ ActionWidgetsSubParserData *parser_data = (ActionWidgetsSubParserData*)user_data;
+ ActionWidgetInfo *item;
+
+ if (!parser_data->response)
+ return;
+
+ item = g_new (ActionWidgetInfo, 1);
+ item->widget_name = g_strndup (text, text_len);
+ item->response_id = parser_data->response;
+ parser_data->items = g_slist_prepend (parser_data->items, item);
+ parser_data->response = NULL;
+}
+
+static const GMarkupParser attributes_parser =
+ {
+ attributes_start_element,
+ NULL,
+ attributes_text_element,
+ };
+
+gboolean
+gtk_dialog_buildable_custom_tag_start (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *tagname,
+ GMarkupParser *parser,
+ gpointer *data)
+{
+ ActionWidgetsSubParserData *parser_data;
+
+ if (child)
+ return FALSE;
+
+ if (strcmp (tagname, "action-widgets") == 0)
+ {
+ parser_data = g_slice_new0 (ActionWidgetsSubParserData);
+ parser_data->dialog = GTK_DIALOG (buildable);
+ parser_data->items = NULL;
+
+ *parser = attributes_parser;
+ *data = parser_data;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void
+gtk_dialog_buildable_custom_finished (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *tagname,
+ gpointer user_data)
+{
+ GSList *l;
+ ActionWidgetsSubParserData *parser_data;
+ GObject *object;
+ ResponseData* data;
+
+ if (strcmp (tagname, "action-widgets"))
+ return;
+
+ parser_data = (ActionWidgetsSubParserData*)user_data;
+ parser_data->items = g_slist_reverse (parser_data->items);
+
+ for (l = parser_data->items; l; l = l->next)
+ {
+ ActionWidgetInfo *item = l->data;
+
+ object = gtk_builder_get_object (builder, item->widget_name);
+ if (!object)
+ {
+ g_warning ("Unknown object %s specified in action-widgets %s",
+ item->widget_name,
+ gtk_buildable_get_name (GTK_BUILDABLE (object)));
+ continue;
+ }
+
+ data = get_response_data (GTK_WIDGET (object), TRUE);
+ data->response_id = atoi (item->response_id);
+
+ g_free (item->widget_name);
+ g_free (item->response_id);
+ g_free (item);
+ }
+ g_slist_free (parser_data->items);
+ g_slice_free (ActionWidgetsSubParserData, parser_data);
+}
+
#define __GTK_DIALOG_C__
#include "gtkaliasdef.c"
diff --git a/gtk/gtkentrycompletion.c b/gtk/gtkentrycompletion.c
index 8df785c158..53b87748b9 100644
--- a/gtk/gtkentrycompletion.c
+++ b/gtk/gtkentrycompletion.c
@@ -149,9 +149,15 @@ static void gtk_entry_completion_insert_completion_text (GtkEntryCompletion
static guint entry_completion_signals[LAST_SIGNAL] = { 0 };
+/* GtkBuildable */
+static void gtk_entry_completion_buildable_init (GtkBuildableIface *iface);
+
G_DEFINE_TYPE_WITH_CODE (GtkEntryCompletion, gtk_entry_completion, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_LAYOUT,
- gtk_entry_completion_cell_layout_init))
+ gtk_entry_completion_cell_layout_init)
+ G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
+ gtk_entry_completion_buildable_init))
+
static void
gtk_entry_completion_class_init (GtkEntryCompletionClass *klass)
@@ -387,6 +393,14 @@ gtk_entry_completion_class_init (GtkEntryCompletionClass *klass)
}
static void
+gtk_entry_completion_buildable_init (GtkBuildableIface *iface)
+{
+ iface->add = _gtk_cell_layout_buildable_add;
+ iface->custom_tag_start = _gtk_cell_layout_buildable_custom_tag_start;
+ iface->custom_tag_end = _gtk_cell_layout_buildable_custom_tag_end;
+}
+
+static void
gtk_entry_completion_cell_layout_init (GtkCellLayoutIface *iface)
{
iface->pack_start = gtk_entry_completion_pack_start;
diff --git a/gtk/gtkexpander.c b/gtk/gtkexpander.c
index 7d99da960e..62c08cd356 100644
--- a/gtk/gtkexpander.c
+++ b/gtk/gtkexpander.c
@@ -22,10 +22,11 @@
*/
#include <config.h>
-
+#include <string.h>
#include "gtkexpander.h"
#include "gtklabel.h"
+#include "gtkbuildable.h"
#include "gtkcontainer.h"
#include "gtkmarshalers.h"
#include "gtkmain.h"
@@ -126,7 +127,16 @@ static void gtk_expander_activate (GtkExpander *expander);
static void get_expander_bounds (GtkExpander *expander,
GdkRectangle *rect);
-G_DEFINE_TYPE (GtkExpander, gtk_expander, GTK_TYPE_BIN)
+/* GtkBuildable */
+static void gtk_expander_buildable_init (GtkBuildableIface *iface);
+static void gtk_expander_buildable_add (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *type);
+
+G_DEFINE_TYPE_WITH_CODE (GtkExpander, gtk_expander, GTK_TYPE_BIN,
+ G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
+ gtk_expander_buildable_init))
static void
gtk_expander_class_init (GtkExpanderClass *klass)
@@ -278,6 +288,26 @@ gtk_expander_init (GtkExpander *expander)
}
static void
+gtk_expander_buildable_add (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *type)
+{
+ if (!type)
+ gtk_container_add (GTK_CONTAINER (buildable), GTK_WIDGET (child));
+ else if (strcmp (type, "label") == 0)
+ gtk_expander_set_label_widget (GTK_EXPANDER (buildable), GTK_WIDGET (child));
+ else
+ GTK_BUILDER_WARN_INVALID_CHILD_TYPE (GTK_EXPANDER (buildable), type);
+}
+
+static void
+gtk_expander_buildable_init (GtkBuildableIface *iface)
+{
+ iface->add = gtk_expander_buildable_add;
+}
+
+static void
gtk_expander_set_property (GObject *object,
guint prop_id,
const GValue *value,
diff --git a/gtk/gtkfontsel.c b/gtk/gtkfontsel.c
index 095f216ab6..5be9b7cf0b 100644
--- a/gtk/gtkfontsel.c
+++ b/gtk/gtkfontsel.c
@@ -59,6 +59,7 @@
#include "gtkintl.h"
#include "gtkaccessible.h"
#include "gtkprivate.h"
+#include "gtkbuildable.h"
#include "gtkalias.h"
/* We don't enable the font and style entries because they don't add
@@ -1291,7 +1292,17 @@ gtk_font_selection_set_preview_text (GtkFontSelection *fontsel,
* GtkFontSelectionDialog
*****************************************************************************/
-G_DEFINE_TYPE (GtkFontSelectionDialog, gtk_font_selection_dialog, GTK_TYPE_DIALOG);
+static void gtk_font_selection_dialog_buildable_interface_init (GtkBuildableIface *iface);
+static GObject * gtk_font_selection_dialog_buildable_get_internal_child (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ const gchar *childname);
+
+G_DEFINE_TYPE_WITH_CODE (GtkFontSelectionDialog, gtk_font_selection_dialog,
+ GTK_TYPE_DIALOG,
+ G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
+ gtk_font_selection_dialog_buildable_interface_init))
+
+static GtkBuildableIface *parent_buildable_iface;
static void
gtk_font_selection_dialog_class_init (GtkFontSelectionDialogClass *klass)
@@ -1365,6 +1376,30 @@ gtk_font_selection_dialog_new (const gchar *title)
return GTK_WIDGET (fontseldiag);
}
+static void
+gtk_font_selection_dialog_buildable_interface_init (GtkBuildableIface *iface)
+{
+ parent_buildable_iface = g_type_interface_peek_parent (iface);
+ iface->get_internal_child = gtk_font_selection_dialog_buildable_get_internal_child;
+}
+
+static GObject *
+gtk_font_selection_dialog_buildable_get_internal_child (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ const gchar *childname)
+{
+ if (strcmp(childname, "ok_button") == 0)
+ return G_OBJECT (GTK_FONT_SELECTION_DIALOG(buildable)->ok_button);
+ else if (strcmp(childname, "cancel_button") == 0)
+ return G_OBJECT (GTK_FONT_SELECTION_DIALOG (buildable)->cancel_button);
+ else if (strcmp(childname, "apply_button") == 0)
+ return G_OBJECT (GTK_FONT_SELECTION_DIALOG(buildable)->apply_button);
+ else if (strcmp(childname, "font_selection") == 0)
+ return G_OBJECT (GTK_FONT_SELECTION_DIALOG(buildable)->fontsel);
+
+ return parent_buildable_iface->get_internal_child (buildable, builder, childname);
+}
+
/**
* gtk_font_selection_dialog_get_font_name:
* @fsd: a #GtkFontSelectionDialog
diff --git a/gtk/gtkframe.c b/gtk/gtkframe.c
index f5974022fc..fba55df934 100644
--- a/gtk/gtkframe.c
+++ b/gtk/gtkframe.c
@@ -30,6 +30,7 @@
#include "gtklabel.h"
#include "gtkprivate.h"
#include "gtkintl.h"
+#include "gtkbuildable.h"
#include "gtkalias.h"
#define LABEL_PAD 1
@@ -73,7 +74,16 @@ static void gtk_frame_compute_child_allocation (GtkFrame *frame,
static void gtk_frame_real_compute_child_allocation (GtkFrame *frame,
GtkAllocation *child_allocation);
-G_DEFINE_TYPE (GtkFrame, gtk_frame, GTK_TYPE_BIN)
+/* GtkBuildable */
+static void gtk_frame_buildable_init (GtkBuildableIface *iface);
+static void gtk_frame_buildable_add (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *type);
+
+G_DEFINE_TYPE_WITH_CODE (GtkFrame, gtk_frame, GTK_TYPE_BIN,
+ G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
+ gtk_frame_buildable_init))
static void
gtk_frame_class_init (GtkFrameClass *class)
@@ -150,6 +160,26 @@ gtk_frame_class_init (GtkFrameClass *class)
}
static void
+gtk_frame_buildable_init (GtkBuildableIface *iface)
+{
+ iface->add = gtk_frame_buildable_add;
+}
+
+static void
+gtk_frame_buildable_add (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *type)
+{
+ if (type && strcmp (type, "label") == 0)
+ gtk_frame_set_label_widget (GTK_FRAME (buildable), GTK_WIDGET (child));
+ else if (!type)
+ gtk_container_add (GTK_CONTAINER (buildable), GTK_WIDGET (child));
+ else
+ GTK_BUILDER_WARN_INVALID_CHILD_TYPE (GTK_FRAME (buildable), type);
+}
+
+static void
gtk_frame_init (GtkFrame *frame)
{
frame->label_widget = NULL;
diff --git a/gtk/gtkiconview.c b/gtk/gtkiconview.c
index 46db615363..ea7a1933b0 100644
--- a/gtk/gtkiconview.c
+++ b/gtk/gtkiconview.c
@@ -450,11 +450,28 @@ static void clear_source_info (GtkIconView *icon_view);
static void adjust_wrap_width (GtkIconView *icon_view,
GtkIconViewItem *item);
+/* GtkBuildable */
+static GtkBuildableIface *parent_buildable_iface;
+static void gtk_icon_view_buildable_init (GtkBuildableIface *iface);
+static gboolean gtk_icon_view_buildable_custom_tag_start (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *tagname,
+ GMarkupParser *parser,
+ gpointer *data);
+static void gtk_icon_view_buildable_custom_tag_end (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *tagname,
+ gpointer *data);
+
static guint icon_view_signals[LAST_SIGNAL] = { 0 };
G_DEFINE_TYPE_WITH_CODE (GtkIconView, gtk_icon_view, GTK_TYPE_CONTAINER,
G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_LAYOUT,
- gtk_icon_view_cell_layout_init))
+ gtk_icon_view_cell_layout_init)
+ G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
+ gtk_icon_view_buildable_init))
static void
gtk_icon_view_class_init (GtkIconViewClass *klass)
@@ -896,6 +913,15 @@ gtk_icon_view_class_init (GtkIconViewClass *klass)
}
static void
+gtk_icon_view_buildable_init (GtkBuildableIface *iface)
+{
+ parent_buildable_iface = g_type_interface_peek_parent (iface);
+ iface->add = _gtk_cell_layout_buildable_add;
+ iface->custom_tag_start = gtk_icon_view_buildable_custom_tag_start;
+ iface->custom_tag_end = gtk_icon_view_buildable_custom_tag_end;
+}
+
+static void
gtk_icon_view_cell_layout_init (GtkCellLayoutIface *iface)
{
iface->pack_start = gtk_icon_view_cell_layout_pack_start;
@@ -9236,5 +9262,38 @@ gtk_icon_view_get_accessible (GtkWidget *widget)
return (* GTK_WIDGET_CLASS (gtk_icon_view_parent_class)->get_accessible) (widget);
}
+static gboolean
+gtk_icon_view_buildable_custom_tag_start (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *tagname,
+ GMarkupParser *parser,
+ gpointer *data)
+{
+ if (parent_buildable_iface->custom_tag_start (buildable, builder, child,
+ tagname, parser, data))
+ return TRUE;
+
+ return _gtk_cell_layout_buildable_custom_tag_start (buildable, builder, child,
+ tagname, parser, data);
+}
+
+static void
+gtk_icon_view_buildable_custom_tag_end (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *tagname,
+ gpointer *data)
+{
+ if (strcmp (tagname, "attributes") == 0)
+ _gtk_cell_layout_buildable_custom_tag_end (buildable, builder, child, tagname,
+ data);
+ else
+ parent_buildable_iface->custom_tag_end (buildable, builder, child, tagname,
+ data);
+}
+
+
+
#define __GTK_ICON_VIEW_C__
#include "gtkaliasdef.c"
diff --git a/gtk/gtkliststore.c b/gtk/gtkliststore.c
index dc5ebbfa9a..c012afbda3 100644
--- a/gtk/gtkliststore.c
+++ b/gtk/gtkliststore.c
@@ -18,6 +18,8 @@
*/
#include <config.h>
+#include <errno.h>
+#include <stdlib.h>
#include <string.h>
#include <gobject/gvaluecollector.h>
#include "gtktreemodel.h"
@@ -25,6 +27,7 @@
#include "gtktreedatalist.h"
#include "gtktreednd.h"
#include "gtkintl.h"
+#include "gtkbuildable.h"
#include "gtkalias.h"
#define GTK_LIST_STORE_IS_SORTED(list) (((GtkListStore*)(list))->sort_column_id != GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID)
@@ -34,6 +37,7 @@ static void gtk_list_store_tree_model_init (GtkTreeModelIface *iface);
static void gtk_list_store_drag_source_init(GtkTreeDragSourceIface *iface);
static void gtk_list_store_drag_dest_init (GtkTreeDragDestIface *iface);
static void gtk_list_store_sortable_init (GtkTreeSortableIface *iface);
+static void gtk_list_store_buildable_init (GtkBuildableIface *iface);
static void gtk_list_store_finalize (GObject *object);
static GtkTreeModelFlags gtk_list_store_get_flags (GtkTreeModel *tree_model);
static gint gtk_list_store_get_n_columns (GtkTreeModel *tree_model);
@@ -114,6 +118,19 @@ static void gtk_list_store_set_default_sort_func (GtkTreeSortable *so
static gboolean gtk_list_store_has_default_sort_func (GtkTreeSortable *sortable);
+/* buildable */
+static gboolean gtk_list_store_buildable_custom_tag_start (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *tagname,
+ GMarkupParser *parser,
+ gpointer *data);
+static void gtk_list_store_buildable_custom_tag_end (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *tagname,
+ gpointer *data);
+
G_DEFINE_TYPE_WITH_CODE (GtkListStore, gtk_list_store, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL,
gtk_list_store_tree_model_init)
@@ -122,7 +139,10 @@ G_DEFINE_TYPE_WITH_CODE (GtkListStore, gtk_list_store, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_DRAG_DEST,
gtk_list_store_drag_dest_init)
G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_SORTABLE,
- gtk_list_store_sortable_init))
+ gtk_list_store_sortable_init)
+ G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
+ gtk_list_store_buildable_init))
+
static void
gtk_list_store_class_init (GtkListStoreClass *class)
@@ -176,6 +196,13 @@ gtk_list_store_sortable_init (GtkTreeSortableIface *iface)
iface->has_default_sort_func = gtk_list_store_has_default_sort_func;
}
+void
+gtk_list_store_buildable_init (GtkBuildableIface *iface)
+{
+ iface->custom_tag_start = gtk_list_store_buildable_custom_tag_start;
+ iface->custom_tag_end = gtk_list_store_buildable_custom_tag_end;
+}
+
static void
gtk_list_store_init (GtkListStore *list_store)
{
@@ -2008,5 +2035,252 @@ gtk_list_store_insert_with_valuesv (GtkListStore *list_store,
gtk_tree_path_free (path);
}
+/* GtkBuildable custom tag implementation
+ *
+ * <columns>
+ * <column type="..."/>
+ * <column type="..."/>
+ * </columns>
+ */
+typedef struct {
+ GtkBuilder *builder;
+ GObject *object;
+ GSList *column_type_names;
+ GType *column_types;
+ GValue *values;
+ gint *columns;
+ gint last_row;
+ gint n_columns;
+ gint row_column;
+ GQuark error_quark;
+ gboolean is_data;
+} SubParserData;
+
+static void
+list_store_start_element (GMarkupParseContext *context,
+ const gchar *element_name,
+ const gchar **names,
+ const gchar **values,
+ gpointer user_data,
+ GError **error)
+{
+ guint i;
+ SubParserData *data = (SubParserData*)user_data;
+
+ if (strcmp (element_name, "col") == 0)
+ {
+ int i, id = -1;
+
+ if (data->row_column >= data->n_columns)
+ g_set_error (error, data->error_quark, 0,
+ "Too many columns, maximum is %d\n", data->n_columns - 1);
+
+ for (i = 0; names[i]; i++)
+ if (strcmp (names[i], "id") == 0)
+ {
+ errno = 0;
+ id = atoi (values[i]);
+ if (errno)
+ g_set_error (error, data->error_quark, 0,
+ "the id tag %s could not be converted to an integer", values[i]);
+ }
+
+ if (id == -1)
+ g_set_error (error, data->error_quark, 0,
+ "<col> needs an id attribute");
+
+ data->columns[data->row_column] = id;
+ data->row_column++;
+ data->is_data = TRUE;
+ }
+ else if (strcmp (element_name, "row") == 0)
+ ;
+ else if (strcmp (element_name, "column") == 0)
+ for (i = 0; names[i]; i++)
+ if (strcmp (names[i], "type") == 0)
+ data->column_type_names = g_slist_prepend (data->column_type_names,
+ g_strdup (values[i]));
+ else if (strcmp (element_name, "columns") == 0)
+ ;
+ else if (strcmp (element_name, "data") == 0)
+ ;
+ else
+ g_set_error (error, data->error_quark, 0,
+ "Unknown start tag: %s", element_name);
+}
+
+static void
+list_store_end_element (GMarkupParseContext *context,
+ const gchar *element_name,
+ gpointer user_data,
+ GError **error)
+{
+ SubParserData *data = (SubParserData*)user_data;
+
+ g_assert (data->builder);
+
+ if (strcmp (element_name, "row") == 0)
+ {
+ GtkTreeIter iter;
+ int i;
+
+ gtk_list_store_insert_with_valuesv (GTK_LIST_STORE (data->object),
+ &iter,
+ data->last_row,
+ data->columns,
+ data->values,
+ data->row_column);
+ for (i = 0; i < data->row_column; i++)
+ g_value_unset (&data->values[i]);
+ g_free (data->values);
+ data->values = g_new0 (GValue, data->n_columns);
+ data->last_row++;
+ data->row_column = 0;
+ }
+ else if (strcmp (element_name, "columns") == 0)
+ {
+ GType *column_types;
+ GSList *l;
+ int i;
+ GType type;
+
+ data->column_type_names = g_slist_reverse (data->column_type_names);
+ column_types = g_new0 (GType, g_slist_length (data->column_type_names));
+
+ for (l = data->column_type_names, i = 0; l; l = l->next, i++)
+ {
+ type = gtk_builder_get_type_from_name (data->builder, l->data);
+ if (type == G_TYPE_INVALID)
+ {
+ g_warning ("Unknown type %s specified in treemodel %s",
+ (const gchar*)l->data,
+ gtk_buildable_get_name (GTK_BUILDABLE (data->object)));
+ continue;
+ }
+ column_types[i] = type;
+
+ g_free (l->data);
+ }
+
+ gtk_list_store_set_column_types (GTK_LIST_STORE (data->object), i,
+ column_types);
+
+ g_free (column_types);
+ }
+ else if (strcmp (element_name, "col") == 0)
+ data->is_data = FALSE;
+ else if (strcmp (element_name, "data") == 0)
+ ;
+ else if (strcmp (element_name, "column") == 0)
+ ;
+ else
+ g_set_error (error, data->error_quark, 0,
+ "Unknown end tag: %s", element_name);
+}
+
+static void
+list_store_text (GMarkupParseContext *context,
+ const gchar *text,
+ gsize text_len,
+ gpointer user_data,
+ GError **error)
+{
+ SubParserData *data = (SubParserData*)user_data;
+ gint i;
+
+ if (!data->is_data)
+ return;
+
+ i = data->row_column - 1;
+
+ if (!gtk_builder_value_from_string_type (data->column_types[i],
+ text,
+ &data->values[i]))
+ g_error ("Could not convert '%s' to type %s\n",
+ text, g_type_name (data->column_types[i]));
+}
+
+static const GMarkupParser list_store_parser =
+ {
+ list_store_start_element,
+ list_store_end_element,
+ list_store_text
+ };
+
+static gboolean
+gtk_list_store_buildable_custom_tag_start (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *tagname,
+ GMarkupParser *parser,
+ gpointer *data)
+{
+ SubParserData *parser_data;
+
+ if (child)
+ return FALSE;
+
+ if (strcmp (tagname, "columns") == 0)
+ {
+
+ parser_data = g_slice_new0 (SubParserData);
+ parser_data->builder = builder;
+ parser_data->object = G_OBJECT (buildable);
+ parser_data->column_type_names = NULL;
+
+ *parser = list_store_parser;
+ *data = parser_data;
+ return TRUE;
+ }
+ else if (strcmp (tagname, "data") == 0)
+ {
+ gint n_columns = gtk_list_store_get_n_columns (GTK_TREE_MODEL (buildable));
+ if (n_columns == 0)
+ g_error ("Cannot append data to an empty model");
+
+ parser_data = g_slice_new0 (SubParserData);
+ parser_data->builder = builder;
+ parser_data->object = G_OBJECT (buildable);
+ parser_data->values = g_new0 (GValue, n_columns);
+ parser_data->columns = g_new0 (gint, n_columns);
+ parser_data->column_types = GTK_LIST_STORE (buildable)->column_headers;
+ parser_data->n_columns = n_columns;
+ parser_data->last_row = 0;
+ parser_data->error_quark = g_quark_from_static_string ("GtkListStore");
+
+ *parser = list_store_parser;
+ *data = parser_data;
+ return TRUE;
+ }
+ else
+ g_warning ("Unknown custom list store tag: %s", tagname);
+
+ return FALSE;
+}
+
+static void
+gtk_list_store_buildable_custom_tag_end (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *tagname,
+ gpointer *data)
+{
+ SubParserData *sub = (SubParserData*)data;
+
+ if (strcmp (tagname, "columns") == 0)
+ {
+ g_slist_free (sub->column_type_names);
+ g_slice_free (SubParserData, sub);
+ }
+ else if (strcmp (tagname, "data") == 0)
+ {
+ g_free (sub->columns);
+ g_free (sub->values);
+ g_slice_free (SubParserData, sub);
+ }
+ else
+ g_warning ("Unknown custom list store tag: %s", tagname);
+}
+
#define __GTK_LIST_STORE_C__
#include "gtkaliasdef.c"
diff --git a/gtk/gtkmain.c b/gtk/gtkmain.c
index d5e9fc20b9..ca9e874bc2 100644
--- a/gtk/gtkmain.c
+++ b/gtk/gtkmain.c
@@ -162,7 +162,8 @@ static const GDebugKey gtk_debug_keys[] = {
{"modules", GTK_DEBUG_MODULES},
{"geometry", GTK_DEBUG_GEOMETRY},
{"icontheme", GTK_DEBUG_ICONTHEME},
- {"printing", GTK_DEBUG_PRINTING}
+ {"printing", GTK_DEBUG_PRINTING},
+ {"builder", GTK_DEBUG_BUILDER}
};
#endif /* G_ENABLE_DEBUG */
@@ -658,7 +659,7 @@ do_post_parse_initialization (int *argc,
}
gtk_type_init (0);
- _gtk_accel_map_init ();
+ _gtk_accel_map_init ();
_gtk_rc_init ();
/* Set the 'initialized' flag.
diff --git a/gtk/gtknotebook.c b/gtk/gtknotebook.c
index 227a4972e7..4297456f1f 100644
--- a/gtk/gtknotebook.c
+++ b/gtk/gtknotebook.c
@@ -26,6 +26,7 @@
*/
#include <config.h>
+#include <string.h>
#include "gtknotebook.h"
#include "gtkmain.h"
#include "gtkmenu.h"
@@ -38,6 +39,7 @@
#include "gtkbindings.h"
#include "gtkprivate.h"
#include "gtkdnd.h"
+#include "gtkbuildable.h"
#include "gtkalias.h"
#define SCROLL_DELAY_FACTOR 5
@@ -421,6 +423,12 @@ static void do_detach_tab (GtkNotebook *from,
gint x,
gint y);
+/* GtkBuildable */
+static void gtk_notebook_buildable_init (GtkBuildableIface *iface);
+static void gtk_notebook_buildable_add (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *type);
static GtkNotebookWindowCreationFunc window_creation_hook = NULL;
static gpointer window_creation_hook_data;
@@ -428,7 +436,9 @@ static GDestroyNotify window_creation_hook_destroy = NULL;
static guint notebook_signals[LAST_SIGNAL] = { 0 };
-G_DEFINE_TYPE (GtkNotebook, gtk_notebook, GTK_TYPE_CONTAINER)
+G_DEFINE_TYPE_WITH_CODE (GtkNotebook, gtk_notebook, GTK_TYPE_CONTAINER,
+ G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
+ gtk_notebook_buildable_init))
static void
add_tab_bindings (GtkBindingSet *binding_set,
@@ -1095,6 +1105,36 @@ gtk_notebook_init (GtkNotebook *notebook)
gtk_drag_dest_set_track_motion (GTK_WIDGET (notebook), TRUE);
}
+static void
+gtk_notebook_buildable_init (GtkBuildableIface *iface)
+{
+ iface->add = gtk_notebook_buildable_add;
+}
+
+static void
+gtk_notebook_buildable_add (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *type)
+{
+ GtkNotebook *notebook = GTK_NOTEBOOK (buildable);
+
+ if (type && strcmp (type, "tab") == 0)
+ {
+ GtkWidget * page;
+
+ page = gtk_notebook_get_nth_page (notebook, -1);
+ /* To set the tab label widget, we must have already a child
+ * inside the tab container. */
+ g_assert (page != NULL);
+ gtk_notebook_set_tab_label (notebook, page, GTK_WIDGET (child));
+ }
+ else if (!type)
+ gtk_notebook_append_page (notebook, GTK_WIDGET (child), NULL);
+ else
+ GTK_BUILDER_WARN_INVALID_CHILD_TYPE (notebook, type);
+}
+
static gboolean
gtk_notebook_select_page (GtkNotebook *notebook,
gboolean move_focus)
diff --git a/gtk/gtksizegroup.c b/gtk/gtksizegroup.c
index af404f0a7c..477c45f5f1 100644
--- a/gtk/gtksizegroup.c
+++ b/gtk/gtksizegroup.c
@@ -19,10 +19,12 @@
*/
#include <config.h>
+#include <string.h>
#include "gtkcontainer.h"
#include "gtkintl.h"
#include "gtkprivate.h"
#include "gtksizegroup.h"
+#include "gtkbuildable.h"
#include "gtkalias.h"
enum {
@@ -49,6 +51,20 @@ static void add_widget_to_closure (GtkWidget *widget,
GSList **groups,
GSList **widgets);
+/* GtkBuildable */
+static void gtk_size_group_buildable_init (GtkBuildableIface *iface);
+static gboolean gtk_size_group_buildable_custom_tag_start (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *tagname,
+ GMarkupParser *parser,
+ gpointer *data);
+static void gtk_size_group_buildable_custom_finished (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *tagname,
+ gpointer user_data);
+
static GQuark size_groups_quark;
static const gchar size_groups_tag[] = "gtk-size-groups";
@@ -310,7 +326,16 @@ gtk_size_group_init (GtkSizeGroup *size_group)
size_group->ignore_hidden = 0;
}
-G_DEFINE_TYPE (GtkSizeGroup, gtk_size_group, G_TYPE_OBJECT)
+static void
+gtk_size_group_buildable_init (GtkBuildableIface *iface)
+{
+ iface->custom_tag_start = gtk_size_group_buildable_custom_tag_start;
+ iface->custom_finished = gtk_size_group_buildable_custom_finished;
+}
+
+G_DEFINE_TYPE_WITH_CODE (GtkSizeGroup, gtk_size_group, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
+ gtk_size_group_buildable_init))
static void
gtk_size_group_set_property (GObject *object,
@@ -813,5 +838,101 @@ _gtk_size_group_queue_resize (GtkWidget *widget)
queue_resize_on_widget (widget, TRUE);
}
+typedef struct {
+ GObject *object;
+ GSList *items;
+} GSListSubParserData;
+
+static void
+size_group_start_element (GMarkupParseContext *context,
+ const gchar *element_name,
+ const gchar **names,
+ const gchar **values,
+ gpointer user_data,
+ GError **error)
+{
+ guint i;
+ GSListSubParserData *data = (GSListSubParserData*)user_data;
+
+ if (strcmp (element_name, "widget") == 0)
+ for (i = 0; names[i]; i++)
+ if (strcmp (names[i], "name") == 0)
+ data->items = g_slist_prepend (data->items, g_strdup (values[i]));
+ else if (strcmp (element_name, "widgets") == 0)
+ return;
+ else
+ g_warning ("Unsupported type tag for GtkSizeGroup: %s\n",
+ element_name);
+
+}
+
+static const GMarkupParser size_group_parser =
+ {
+ size_group_start_element
+ };
+
+static gboolean
+gtk_size_group_buildable_custom_tag_start (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *tagname,
+ GMarkupParser *parser,
+ gpointer *data)
+{
+ GSListSubParserData *parser_data;
+
+ if (child)
+ return FALSE;
+
+ if (strcmp (tagname, "widgets") == 0)
+ {
+ parser_data = g_slice_new0 (GSListSubParserData);
+ parser_data->items = NULL;
+ parser_data->object = G_OBJECT (buildable);
+
+ *parser = size_group_parser;
+ *data = parser_data;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void
+gtk_size_group_buildable_custom_finished (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *tagname,
+ gpointer user_data)
+{
+ GSList *l;
+ GSListSubParserData *data;
+ GObject *object;
+
+ if (strcmp (tagname, "widgets"))
+ return;
+
+ data = (GSListSubParserData*)user_data;
+ data->items = g_slist_reverse (data->items);
+
+ for (l = data->items; l; l = l->next)
+ {
+ object = gtk_builder_get_object (builder, l->data);
+ if (!object)
+ {
+ g_warning ("Unknown object %s specified in sizegroup %s",
+ (const gchar*)l->data,
+ gtk_buildable_get_name (GTK_BUILDABLE (data->object)));
+ continue;
+ }
+ gtk_size_group_add_widget (GTK_SIZE_GROUP (data->object),
+ GTK_WIDGET (object));
+ g_free (l->data);
+ }
+ g_slist_free (data->items);
+ g_slice_free (GSListSubParserData, data);
+}
+
+
#define __GTK_SIZE_GROUP_C__
#include "gtkaliasdef.c"
diff --git a/gtk/gtktreestore.c b/gtk/gtktreestore.c
index 4379af70bb..730c942f5b 100644
--- a/gtk/gtktreestore.c
+++ b/gtk/gtktreestore.c
@@ -24,6 +24,7 @@
#include "gtktreestore.h"
#include "gtktreedatalist.h"
#include "gtktreednd.h"
+#include "gtkbuildable.h"
#include "gtkintl.h"
#include "gtkalias.h"
@@ -35,6 +36,7 @@ static void gtk_tree_store_tree_model_init (GtkTreeModelIface *iface);
static void gtk_tree_store_drag_source_init(GtkTreeDragSourceIface *iface);
static void gtk_tree_store_drag_dest_init (GtkTreeDragDestIface *iface);
static void gtk_tree_store_sortable_init (GtkTreeSortableIface *iface);
+static void gtk_tree_store_buildable_init (GtkBuildableIface *iface);
static void gtk_tree_store_finalize (GObject *object);
static GtkTreeModelFlags gtk_tree_store_get_flags (GtkTreeModel *tree_model);
static gint gtk_tree_store_get_n_columns (GtkTreeModel *tree_model);
@@ -115,6 +117,21 @@ static void gtk_tree_store_set_default_sort_func (GtkTreeSortable *
GtkDestroyNotify destroy);
static gboolean gtk_tree_store_has_default_sort_func (GtkTreeSortable *sortable);
+
+/* buildable */
+
+static gboolean gtk_tree_store_buildable_custom_tag_start (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *tagname,
+ GMarkupParser *parser,
+ gpointer *data);
+static void gtk_tree_store_buildable_custom_finished (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *tagname,
+ gpointer user_data);
+
static void validate_gnode (GNode *node);
static void gtk_tree_store_move (GtkTreeStore *tree_store,
@@ -142,7 +159,9 @@ G_DEFINE_TYPE_WITH_CODE (GtkTreeStore, gtk_tree_store, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_DRAG_DEST,
gtk_tree_store_drag_dest_init)
G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_SORTABLE,
- gtk_tree_store_sortable_init))
+ gtk_tree_store_sortable_init)
+ G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
+ gtk_tree_store_buildable_init))
static void
gtk_tree_store_class_init (GtkTreeStoreClass *class)
@@ -196,6 +215,13 @@ gtk_tree_store_sortable_init (GtkTreeSortableIface *iface)
iface->has_default_sort_func = gtk_tree_store_has_default_sort_func;
}
+void
+gtk_tree_store_buildable_init (GtkBuildableIface *iface)
+{
+ iface->custom_tag_start = gtk_tree_store_buildable_custom_tag_start;
+ iface->custom_finished = gtk_tree_store_buildable_custom_finished;
+}
+
static void
gtk_tree_store_init (GtkTreeStore *tree_store)
{
@@ -3173,5 +3199,110 @@ validate_gnode (GNode* node)
}
}
+/* GtkBuildable custom tag implementation
+ *
+ * <columns>
+ * <column type="..."/>
+ * <column type="..."/>
+ * </columns>
+ */
+typedef struct {
+ GObject *object;
+ GSList *items;
+} GSListSubParserData;
+
+static void
+tree_model_start_element (GMarkupParseContext *context,
+ const gchar *element_name,
+ const gchar **names,
+ const gchar **values,
+ gpointer user_data,
+ GError **error)
+{
+ guint i;
+ GSListSubParserData *data = (GSListSubParserData*)user_data;
+
+ for (i = 0; names[i]; i++)
+ {
+ if (strcmp (names[i], "type") == 0)
+ data->items = g_slist_prepend (data->items, g_strdup (values[i]));
+ }
+}
+
+static const GMarkupParser tree_model_parser =
+ {
+ tree_model_start_element
+ };
+
+
+static gboolean
+gtk_tree_store_buildable_custom_tag_start (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *tagname,
+ GMarkupParser *parser,
+ gpointer *data)
+{
+ GSListSubParserData *parser_data;
+
+ if (child)
+ return FALSE;
+
+ if (strcmp (tagname, "columns") == 0)
+ {
+ parser_data = g_slice_new0 (GSListSubParserData);
+ parser_data->items = NULL;
+ parser_data->object = G_OBJECT (buildable);
+
+ *parser = tree_model_parser;
+ *data = parser_data;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void
+gtk_tree_store_buildable_custom_finished (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *tagname,
+ gpointer user_data)
+{
+ GSList *l;
+ GSListSubParserData *data;
+ GType *types;
+ int i;
+ GType type;
+
+ if (strcmp (tagname, "columns"))
+ return;
+
+ data = (GSListSubParserData*)user_data;
+ data->items = g_slist_reverse (data->items);
+ types = g_new0 (GType, g_slist_length (data->items));
+
+ for (l = data->items, i = 0; l; l = l->next, i++)
+ {
+ type = gtk_builder_get_type_from_name (builder, l->data);
+ if (type == G_TYPE_INVALID)
+ {
+ g_warning ("Unknown type %s specified in treemodel %s",
+ (const gchar*)l->data,
+ gtk_buildable_get_name (GTK_BUILDABLE (data->object)));
+ continue;
+ }
+ types[i] = type;
+
+ g_free (l->data);
+ }
+
+ gtk_tree_store_set_column_types (GTK_TREE_STORE (data->object), i, types);
+
+ g_free (types);
+ g_slist_free (data->items);
+ g_slice_free (GSListSubParserData, data);
+}
+
#define __GTK_TREE_STORE_C__
#include "gtkaliasdef.c"
diff --git a/gtk/gtktreeview.c b/gtk/gtktreeview.c
index 268389808f..474c2f0387 100644
--- a/gtk/gtktreeview.c
+++ b/gtk/gtktreeview.c
@@ -29,6 +29,7 @@
#include "gtkcellrenderer.h"
#include "gtkmain.h"
#include "gtkmarshalers.h"
+#include "gtkbuildable.h"
#include "gtkbutton.h"
#include "gtkalignment.h"
#include "gtklabel.h"
@@ -460,6 +461,14 @@ static GtkTreeViewColumn *gtk_tree_view_get_drop_column (GtkTreeView *tree
GtkTreeViewColumn *column,
gint drop_position);
+/* GtkBuildable */
+static void gtk_tree_view_buildable_add (GtkBuildable *tree_view,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *type);
+static void gtk_tree_view_buildable_init (GtkBuildableIface *iface);
+
+
static gboolean scroll_row_timeout (gpointer data);
static void add_scroll_timeout (GtkTreeView *tree_view);
static void remove_scroll_timeout (GtkTreeView *tree_view);
@@ -471,7 +480,9 @@ static guint tree_view_signals [LAST_SIGNAL] = { 0 };
/* GType Methods
*/
-G_DEFINE_TYPE (GtkTreeView, gtk_tree_view, GTK_TYPE_CONTAINER)
+G_DEFINE_TYPE_WITH_CODE (GtkTreeView, gtk_tree_view, GTK_TYPE_CONTAINER,
+ G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
+ gtk_tree_view_buildable_init))
static void
gtk_tree_view_class_init (GtkTreeViewClass *class)
@@ -1282,6 +1293,12 @@ gtk_tree_view_class_init (GtkTreeViewClass *class)
}
static void
+gtk_tree_view_buildable_init (GtkBuildableIface *iface)
+{
+ iface->add = gtk_tree_view_buildable_add;
+}
+
+static void
gtk_tree_view_init (GtkTreeView *tree_view)
{
tree_view->priv = G_TYPE_INSTANCE_GET_PRIVATE (tree_view, GTK_TYPE_TREE_VIEW, GtkTreeViewPrivate);
@@ -1489,6 +1506,15 @@ gtk_tree_view_finalize (GObject *object)
+static void
+gtk_tree_view_buildable_add (GtkBuildable *tree_view,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *type)
+{
+ gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), GTK_TREE_VIEW_COLUMN (child));
+}
+
/* GtkObject Methods
*/
diff --git a/gtk/gtktreeviewcolumn.c b/gtk/gtktreeviewcolumn.c
index f2d2b9a421..86be0371b7 100644
--- a/gtk/gtktreeviewcolumn.c
+++ b/gtk/gtktreeviewcolumn.c
@@ -151,12 +151,17 @@ static GList *gtk_tree_view_column_cell_prev (GtkTreeViewColum
GList *current);
static void gtk_tree_view_column_clear_attributes_by_info (GtkTreeViewColumn *tree_column,
GtkTreeViewColumnCellInfo *info);
+/* GtkBuildable implementation */
+static void gtk_tree_view_column_buildable_init (GtkBuildableIface *iface);
static guint tree_column_signals[LAST_SIGNAL] = { 0 };
G_DEFINE_TYPE_WITH_CODE (GtkTreeViewColumn, gtk_tree_view_column, GTK_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_LAYOUT,
- gtk_tree_view_column_cell_layout_init))
+ gtk_tree_view_column_cell_layout_init)
+ G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
+ gtk_tree_view_column_buildable_init))
+
static void
gtk_tree_view_column_class_init (GtkTreeViewColumnClass *class)
@@ -324,6 +329,14 @@ gtk_tree_view_column_class_init (GtkTreeViewColumnClass *class)
}
static void
+gtk_tree_view_column_buildable_init (GtkBuildableIface *iface)
+{
+ iface->add = _gtk_cell_layout_buildable_add;
+ iface->custom_tag_start = _gtk_cell_layout_buildable_custom_tag_start;
+ iface->custom_tag_end = _gtk_cell_layout_buildable_custom_tag_end;
+}
+
+static void
gtk_tree_view_column_cell_layout_init (GtkCellLayoutIface *iface)
{
iface->pack_start = gtk_tree_view_column_cell_layout_pack_start;
diff --git a/gtk/gtkuimanager.c b/gtk/gtkuimanager.c
index 529c296035..d1a5ce4906 100644
--- a/gtk/gtkuimanager.c
+++ b/gtk/gtkuimanager.c
@@ -31,6 +31,7 @@
#include <config.h>
#include <string.h>
+#include "gtkbuildable.h"
#include "gtkintl.h"
#include "gtkmarshalers.h"
#include "gtkmenu.h"
@@ -142,6 +143,28 @@ static void node_prepend_ui_reference (GNode *node,
static void node_remove_ui_reference (GNode *node,
guint merge_id);
+/* GtkBuildable */
+static void gtk_ui_manager_buildable_init (GtkBuildableIface *iface);
+static void gtk_ui_manager_buildable_add (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *type);
+static GObject* gtk_ui_manager_buildable_construct_child (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ const gchar *name);
+static gboolean gtk_ui_manager_buildable_custom_tag_start (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *tagname,
+ GMarkupParser *parser,
+ gpointer *data);
+static void gtk_ui_manager_buildable_custom_tag_end (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *tagname,
+ gpointer *data);
+
+
enum
{
@@ -163,7 +186,9 @@ enum
static guint ui_manager_signals[LAST_SIGNAL] = { 0 };
-G_DEFINE_TYPE (GtkUIManager, gtk_ui_manager, G_TYPE_OBJECT)
+G_DEFINE_TYPE_WITH_CODE (GtkUIManager, gtk_ui_manager, GTK_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
+ gtk_ui_manager_buildable_init))
static void
gtk_ui_manager_class_init (GtkUIManagerClass *klass)
@@ -401,6 +426,52 @@ gtk_ui_manager_finalize (GObject *object)
}
static void
+gtk_ui_manager_buildable_init (GtkBuildableIface *iface)
+{
+ iface->add = gtk_ui_manager_buildable_add;
+ iface->construct_child = gtk_ui_manager_buildable_construct_child;
+ iface->custom_tag_start = gtk_ui_manager_buildable_custom_tag_start;
+ iface->custom_tag_end = gtk_ui_manager_buildable_custom_tag_end;
+}
+
+static void
+gtk_ui_manager_buildable_add (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *type)
+{
+ GtkUIManager *self = GTK_UI_MANAGER (buildable);
+ guint pos;
+
+ g_return_if_fail (GTK_IS_ACTION_GROUP (child));
+
+ pos = g_list_length (self->private_data->action_groups);
+
+ g_object_ref (child);
+ gtk_ui_manager_insert_action_group (self,
+ GTK_ACTION_GROUP (child),
+ pos);
+}
+
+static GObject *
+gtk_ui_manager_buildable_construct_child (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ const gchar *id)
+{
+ GtkWidget *widget;
+ char *name;
+
+ name = g_strdup_printf ("ui/%s", id);
+ widget = gtk_ui_manager_get_widget (GTK_UI_MANAGER (buildable), name);
+ if (!widget)
+ g_error ("Unknown ui manager child: %s\n", name);
+
+ g_free (name);
+
+ return G_OBJECT (widget);
+}
+
+static void
gtk_ui_manager_set_property (GObject *object,
guint prop_id,
const GValue *value,
@@ -1479,7 +1550,7 @@ add_ui_from_string (GtkUIManager *self,
queue_update (self);
- g_object_notify (G_OBJECT (self), "ui");
+ g_object_notify (G_OBJECT (self), "ui");
return ctx.merge_id;
@@ -2818,6 +2889,49 @@ print_node (GtkUIManager *self,
g_string_append_printf (buffer, close_fmt, indent_level, "");
}
+static gboolean
+gtk_ui_manager_buildable_custom_tag_start (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *tagname,
+ GMarkupParser *parser,
+ gpointer *data)
+{
+ if (child)
+ return FALSE;
+
+ if (strcmp (tagname, "ui") == 0)
+ {
+ ParseContext *ctx;
+
+ ctx = g_new0 (ParseContext, 1);
+ ctx->state = STATE_START;
+ ctx->self = GTK_UI_MANAGER (buildable);
+ ctx->current = NULL;
+ ctx->merge_id = gtk_ui_manager_new_merge_id (GTK_UI_MANAGER (buildable));
+
+ *data = ctx;
+ *parser = ui_parser;
+
+ return TRUE;
+ }
+
+ return FALSE;
+
+}
+
+static void
+gtk_ui_manager_buildable_custom_tag_end (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *tagname,
+ gpointer *data)
+{
+ queue_update (GTK_UI_MANAGER (buildable));
+ g_object_notify (G_OBJECT (buildable), "ui");
+ g_free (data);
+}
+
/**
* gtk_ui_manager_get_ui:
* @self: a #GtkUIManager
diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c
index 40917ed5f8..1d47c8c315 100644
--- a/gtk/gtkwidget.c
+++ b/gtk/gtkwidget.c
@@ -52,6 +52,7 @@
#include "gtktooltips.h"
#include "gtktooltip.h"
#include "gtkinvisible.h"
+#include "gtkbuildable.h"
#include "gtkalias.h"
#define WIDGET_CLASS(w) GTK_WIDGET_GET_CLASS (w)
@@ -245,6 +246,28 @@ static gboolean gtk_widget_real_can_activate_accel (GtkWidget *widg
static void gtk_widget_set_has_tooltip (GtkWidget *widget,
gboolean has_tooltip,
gboolean force);
+static void gtk_widget_buildable_interface_init (GtkBuildableIface *iface);
+static void gtk_widget_buildable_set_name (GtkBuildable *buildable,
+ const gchar *name);
+static const gchar * gtk_widget_buildable_get_name (GtkBuildable *buildable);
+static void gtk_widget_buildable_set_property (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ const gchar *name,
+ const GValue *value);
+static gboolean gtk_widget_buildable_custom_tag_start (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *tagname,
+ GMarkupParser *parser,
+ gpointer *data);
+static void gtk_widget_buildable_custom_finshed (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *tagname,
+ gpointer data);
+static void gtk_widget_buildable_parser_finshed (GtkBuildable *buildable,
+ GtkBuilder *builder);
+
static void gtk_widget_set_usize_internal (GtkWidget *widget,
gint width,
@@ -311,11 +334,20 @@ gtk_widget_get_type (void)
NULL /* interface data */
};
+ const GInterfaceInfo buildable_info =
+ {
+ (GInterfaceInitFunc) gtk_widget_buildable_interface_init,
+ (GInterfaceFinalizeFunc) NULL,
+ NULL /* interface data */
+ };
+
widget_type = g_type_register_static (GTK_TYPE_OBJECT, "GtkWidget",
&widget_info, G_TYPE_FLAG_ABSTRACT);
g_type_add_interface_static (widget_type, ATK_TYPE_IMPLEMENTOR,
&accessibility_info) ;
+ g_type_add_interface_static (widget_type, GTK_TYPE_BUILDABLE,
+ &buildable_info) ;
}
@@ -8360,6 +8392,176 @@ gtk_widget_ref_accessible (AtkImplementor *implementor)
return accessible;
}
+/*
+ * GtkBuildable implementation
+ */
+static GQuark quark_builder_has_default = 0;
+static GQuark quark_builder_has_focus = 0;
+
+static void
+gtk_widget_buildable_interface_init (GtkBuildableIface *iface)
+{
+ quark_builder_has_default = g_quark_from_static_string ("gtk-builder-has-default");
+ quark_builder_has_focus = g_quark_from_static_string ("gtk-builder-has-focus");
+
+ iface->set_name = gtk_widget_buildable_set_name;
+ iface->get_name = gtk_widget_buildable_get_name;
+ iface->set_property = gtk_widget_buildable_set_property;
+ iface->parser_finished = gtk_widget_buildable_parser_finshed;
+ iface->custom_tag_start = gtk_widget_buildable_custom_tag_start;
+ iface->custom_finished = gtk_widget_buildable_custom_finshed;
+}
+
+static void
+gtk_widget_buildable_set_name (GtkBuildable *buildable,
+ const gchar *name)
+{
+ gtk_widget_set_name (GTK_WIDGET (buildable), name);
+}
+
+static const gchar *
+gtk_widget_buildable_get_name (GtkBuildable *buildable)
+{
+ return gtk_widget_get_name (GTK_WIDGET (buildable));
+}
+
+static void
+gtk_widget_buildable_set_property (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ const gchar *name,
+ const GValue *value)
+{
+ if (strcmp (name, "has-default") == 0 && g_value_get_boolean (value))
+ g_object_set_qdata (G_OBJECT (buildable), quark_builder_has_default,
+ GINT_TO_POINTER (TRUE));
+ else if (strcmp (name, "has-focus") == 0 && g_value_get_boolean (value))
+ g_object_set_qdata (G_OBJECT (buildable), quark_builder_has_focus,
+ GINT_TO_POINTER (TRUE));
+ else
+ g_object_set_property (G_OBJECT (buildable), name, value);
+}
+
+static void
+gtk_widget_buildable_parser_finshed (GtkBuildable *buildable,
+ GtkBuilder *builder)
+{
+ if (g_object_get_qdata (G_OBJECT (buildable), quark_builder_has_default))
+ gtk_widget_grab_default (GTK_WIDGET (buildable));
+ if (g_object_get_qdata (G_OBJECT (buildable), quark_builder_has_focus))
+ gtk_widget_grab_focus (GTK_WIDGET (buildable));
+}
+
+typedef struct {
+ GObject *object;
+ guint key;
+ guint modifiers;
+ gchar *signal;
+} AccelGroupParserData;
+
+static void
+accel_group_start_element (GMarkupParseContext *context,
+ const gchar *element_name,
+ const gchar **names,
+ const gchar **values,
+ gpointer user_data,
+ GError **error)
+{
+ gint i;
+ guint key = 0;
+ guint modifiers = 0;
+ gchar *signal = NULL;
+ AccelGroupParserData *parser_data = (AccelGroupParserData*)user_data;
+
+ for (i = 0; names[i]; i++)
+ {
+ if (strcmp (names[i], "key") == 0)
+ key = gdk_keyval_from_name (values[i]);
+ else if (strcmp (names[i], "modifiers") == 0)
+ modifiers = _gtk_builder_flags_from_string (GDK_TYPE_MODIFIER_TYPE, values[i]);
+ else if (strcmp (names[i], "signal") == 0)
+ signal = g_strdup (values[i]);
+ }
+
+ if (key == 0 || signal == NULL)
+ {
+ g_warning ("<accelerator> requires a key or signal attribute");
+ return;
+ }
+ parser_data->key = key;
+ parser_data->modifiers = modifiers;
+ parser_data->signal = signal;
+}
+
+static const GMarkupParser accel_group_parser =
+ {
+ accel_group_start_element,
+ };
+
+static gboolean
+gtk_widget_buildable_custom_tag_start (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *tagname,
+ GMarkupParser *parser,
+ gpointer *data)
+{
+ AccelGroupParserData *parser_data;
+
+ g_assert (buildable);
+
+ if (strcmp (tagname, "accelerator") == 0)
+ {
+ parser_data = g_new0 (AccelGroupParserData, 1);
+ parser_data->object = g_object_ref (buildable);
+ *parser = accel_group_parser;
+ *data = parser_data;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static void
+gtk_widget_buildable_custom_finshed (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *tagname,
+ gpointer user_data)
+{
+ AccelGroupParserData *data;
+ GtkWidget *toplevel;
+ GSList *accel_groups;
+ GtkAccelGroup *accel_group;
+
+ if (strcmp (tagname, "accelerator") == 0)
+ {
+ data = (AccelGroupParserData*)user_data;
+ g_assert (data->object);
+
+ toplevel = gtk_widget_get_toplevel (GTK_WIDGET (data->object));
+ accel_groups = gtk_accel_groups_from_object (G_OBJECT (toplevel));
+ if (g_slist_length (accel_groups) == 0)
+ {
+ accel_group = gtk_accel_group_new ();
+ gtk_window_add_accel_group (GTK_WINDOW (toplevel), accel_group);
+ }
+ else
+ {
+ g_assert (g_slist_length (accel_groups) == 1);
+ accel_group = g_slist_nth_data (accel_groups, 0);
+ }
+ gtk_widget_add_accelerator (GTK_WIDGET(data->object),
+ data->signal,
+ accel_group,
+ data->key,
+ data->modifiers,
+ GTK_ACCEL_VISIBLE);
+ g_object_unref (data->object);
+ g_free (data->signal);
+ g_slice_free (AccelGroupParserData, data);
+ }
+}
+
+
/**
* gtk_widget_get_clipboard:
* @widget: a #GtkWidget
@@ -8652,5 +8854,6 @@ gtk_widget_trigger_tooltip_query (GtkWidget *widget)
gtk_tooltip_trigger_tooltip_query (gtk_widget_get_display (widget));
}
+
#define __GTK_WIDGET_C__
#include "gtkaliasdef.c"
diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c
index a51c00a7cc..654ed152cb 100644
--- a/gtk/gtkwindow.c
+++ b/gtk/gtkwindow.c
@@ -46,6 +46,7 @@
#include "gtkicontheme.h"
#include "gtkmarshalers.h"
#include "gtkplug.h"
+#include "gtkbuildable.h"
#include "gtkalias.h"
#ifdef GDK_WINDOWING_X11
@@ -182,6 +183,7 @@ struct _GtkWindowPrivate
guint reset_type_hint : 1;
guint opacity_set : 1;
+ guint builder_visible : 1;
GdkWindowTypeHint type_hint;
@@ -309,6 +311,8 @@ static GQuark quark_gtk_window_key_hash = 0;
static GQuark quark_gtk_window_default_icon_pixmap = 0;
static GQuark quark_gtk_window_icon_info = 0;
+static GtkBuildableIface *parent_buildable_iface;
+
static void gtk_window_set_property (GObject *object,
guint prop_id,
const GValue *value,
@@ -318,8 +322,19 @@ static void gtk_window_get_property (GObject *object,
GValue *value,
GParamSpec *pspec);
+/* GtkBuildable */
+static void gtk_window_buildable_interface_init (GtkBuildableIface *iface);
+static void gtk_window_buildable_set_property (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ const gchar *name,
+ const GValue *value);
+static void gtk_window_buildable_parser_finished (GtkBuildable *buildable,
+ GtkBuilder *builder);
+
-G_DEFINE_TYPE (GtkWindow, gtk_window, GTK_TYPE_BIN)
+G_DEFINE_TYPE_WITH_CODE (GtkWindow, gtk_window, GTK_TYPE_BIN,
+ G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
+ gtk_window_buildable_interface_init))
static void
add_tab_bindings (GtkBindingSet *binding_set,
@@ -1114,6 +1129,39 @@ gtk_window_get_property (GObject *object,
}
}
+static void
+gtk_window_buildable_interface_init (GtkBuildableIface *iface)
+{
+ parent_buildable_iface = g_type_interface_peek_parent (iface);
+ iface->set_property = gtk_window_buildable_set_property;
+ iface->parser_finished = gtk_window_buildable_parser_finished;
+
+}
+
+static void
+gtk_window_buildable_set_property (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ const gchar *name,
+ const GValue *value)
+{
+ GtkWindowPrivate *priv = GTK_WINDOW_GET_PRIVATE (buildable);
+
+ if (strcmp (name, "visible") == 0 && g_value_get_boolean (value))
+ priv->builder_visible = TRUE;
+ else
+ parent_buildable_iface->set_property (buildable, builder, name, value);
+}
+
+static void
+gtk_window_buildable_parser_finished (GtkBuildable *buildable,
+ GtkBuilder *builder)
+{
+ GtkWindowPrivate *priv = GTK_WINDOW_GET_PRIVATE (buildable);
+
+ if (priv->builder_visible)
+ gtk_widget_show (GTK_WIDGET (buildable));
+}
+
/**
* gtk_window_new:
* @type: type of window
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 0f2a739eba..eed40262d8 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -24,11 +24,12 @@ if USE_X11
testsocket_programs = testsocket testsocket_child
endif
-TESTS = floatingtest
+TESTS = floatingtest buildertest
noinst_PROGRAMS = \
autotestfilechooser \
floatingtest \
+ buildertest \
simple \
print-editor \
testaccel \
@@ -91,6 +92,7 @@ noinst_PROGRAMS = \
autotestfilechooser_DEPENDENCIES = $(TEST_DEPS)
simple_DEPENDENCIES = $(TEST_DEPS)
floatingtest_DEPENDENCIES = $(TEST_DEPS)
+buildertest_DEPENDENCIES = $(TEST_DEPS)
print_editor_DEPENDENCIES = $(TEST_DEPS)
testicontheme_DEPENDENCIES = $(TEST_DEPS)
testiconview_DEPENDENCIES = $(TEST_DEPS)
@@ -146,6 +148,7 @@ testvolumebutton_DEPENDENCIES = $(TEST_DEPS)
autotestfilechooser_LDADD = $(LDADDS)
simple_LDADD = $(LDADDS)
floatingtest_LDADD = $(LDADDS)
+buildertest_LDADD = $(LDADDS)
print_editor_LDADD = $(LDADDS)
testaccel_LDADD = $(LDADDS)
testassistant_LDADD = $(LDADDS)
@@ -205,6 +208,8 @@ testgrouping_LDADD = $(LDADDS)
testtooltips_LDADD = $(LDADDS)
testvolumebutton_LDADD = $(LDADDS)
+buildertest_LDFLAGS = -export-dynamic
+
autotestfilechooser_SOURCES = \
autotestfilechooser.c
diff --git a/tests/buildertest.c b/tests/buildertest.c
new file mode 100644
index 0000000000..b5fbc6bf5b
--- /dev/null
+++ b/tests/buildertest.c
@@ -0,0 +1,1462 @@
+/* buildertest.c
+ * Copyright (C) 2006-2007 Async Open Source
+ * Authors: Johan Dahlin
+ * Henrique Romano
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <string.h>
+#include <libintl.h>
+#include <locale.h>
+
+#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
+#include <gtk/gtkprintjob.h>
+
+static GtkBuilder *
+builder_new_from_string (const gchar *buffer,
+ gsize length,
+ gchar *domain)
+{
+ GtkBuilder *builder;
+ builder = gtk_builder_new ();
+ if (domain)
+ gtk_builder_set_translation_domain (builder, domain);
+ gtk_builder_add_from_string (builder, buffer, length, NULL);
+ return builder;
+}
+
+gboolean test_parser (void)
+{
+ GtkBuilder *builder;
+ GError *error;
+
+ builder = gtk_builder_new ();
+
+ error = NULL;
+ gtk_builder_add_from_string (builder, "<xxx/>", -1, &error);
+ g_assert (error != NULL);
+ g_return_val_if_fail (strcmp (error->message, "Invalid root element: 'xxx'") == 0, FALSE);
+ g_error_free (error);
+
+ error = NULL;
+ gtk_builder_add_from_string (builder, "<interface invalid=\"X\"/>", -1, &error);
+ g_assert (error != NULL);
+ g_return_val_if_fail (strcmp (error->message, "<input>:1:24 'X' is not a valid attribute of <interface>") == 0, FALSE);
+ g_error_free (error);
+
+ error = NULL;
+ gtk_builder_add_from_string (builder, "<interface><child/></interface>", -1, &error);
+ g_assert (error != NULL);
+ g_return_val_if_fail (strcmp (error->message, "<input>:1:19 'child' is not a valid tag here, expected a 'object' tag") == 0, FALSE);
+ g_error_free (error);
+
+ error = NULL;
+ gtk_builder_add_from_string (builder, "<interface><object class=\"GtkVBox\" id=\"a\"><object class=\"GtkHBox\" id=\"b\"/></object></interface>", -1, &error);
+ g_assert (error != NULL);
+ g_return_val_if_fail (strcmp (error->message, "<input>:1:74 'object' is not a valid tag here") == 0, FALSE);
+ g_error_free (error);
+
+ return TRUE;
+}
+
+ int normal;
+int after;
+int object;
+int object_after;
+
+void
+signal_normal (GtkWindow *window, GParamSpec spec)
+{
+ g_assert (GTK_IS_WINDOW (window));
+ g_assert (normal == 0);
+ g_assert (after == 0);
+
+ normal++;
+}
+
+void
+signal_after (GtkWindow *window, GParamSpec spec)
+{
+ g_assert (GTK_IS_WINDOW (window));
+ g_assert (normal == 1);
+ g_assert (after == 0);
+
+ after++;
+}
+
+void
+signal_object (GtkButton *button, GParamSpec spec)
+{
+ g_assert (GTK_IS_BUTTON (button));
+ g_assert (object == 0);
+ g_assert (object_after == 0);
+
+ object++;
+}
+
+void
+signal_object_after (GtkButton *button, GParamSpec spec)
+{
+ g_assert (GTK_IS_BUTTON (button));
+ g_assert (object == 1);
+ g_assert (object_after == 0);
+
+ object_after++;
+}
+
+void
+signal_first (GtkButton *button, GParamSpec spec)
+{
+ g_assert (normal == 0);
+ normal = 10;
+}
+
+void
+signal_second (GtkButton *button, GParamSpec spec)
+{
+ g_assert (normal == 10);
+ normal = 20;
+}
+
+void
+signal_extra (GtkButton *button, GParamSpec spec)
+{
+ g_assert (normal == 20);
+ normal = 30;
+}
+
+void
+signal_extra2 (GtkButton *button, GParamSpec spec)
+{
+ g_assert (normal == 30);
+ normal = 40;
+}
+
+gboolean test_connect_signals (void)
+{
+ GtkBuilder *builder;
+ GObject *window;
+ const gchar buffer[] =
+ "<interface>"
+ " <object class=\"GtkButton\" id=\"button\"/>"
+ " <object class=\"GtkWindow\" id=\"window1\">"
+ " <signal name=\"notify::title\" handler=\"signal_normal\"/>"
+ " <signal name=\"notify::title\" handler=\"signal_after\" after=\"yes\"/>"
+ " <signal name=\"notify::title\" handler=\"signal_object\""
+ " object=\"button\"/>"
+ " <signal name=\"notify::title\" handler=\"signal_object_after\""
+ " object=\"button\" after=\"yes\"/>"
+ " </object>"
+ "</interface>";
+ const gchar buffer_order[] =
+ "<interface>"
+ " <object class=\"GtkWindow\" id=\"window1\">"
+ " <signal name=\"notify::title\" handler=\"signal_first\"/>"
+ " <signal name=\"notify::title\" handler=\"signal_second\"/>"
+ " </object>"
+ "</interface>";
+ const gchar buffer_extra[] =
+ "<interface>"
+ " <object class=\"GtkWindow\" id=\"window2\">"
+ " <signal name=\"notify::title\" handler=\"signal_extra\"/>"
+ " </object>"
+ "</interface>";
+ const gchar buffer_extra2[] =
+ "<interface>"
+ " <object class=\"GtkWindow\" id=\"window3\">"
+ " <signal name=\"notify::title\" handler=\"signal_extra2\"/>"
+ " </object>"
+ "</interface>";
+
+ builder = builder_new_from_string (buffer, -1, NULL);
+ gtk_builder_connect_signals (builder, NULL);
+
+ window = gtk_builder_get_object (builder, "window1");
+ gtk_window_set_title (GTK_WINDOW (window), "test");
+
+ g_return_val_if_fail (normal == 1, FALSE);
+ g_return_val_if_fail (after == 1, FALSE);
+ g_return_val_if_fail (object == 1, FALSE);
+ g_return_val_if_fail (object_after == 1, FALSE);
+
+ g_object_unref (builder);
+
+ builder = builder_new_from_string (buffer_order, -1, NULL);
+ gtk_builder_connect_signals (builder, NULL);
+ window = gtk_builder_get_object (builder, "window1");
+ normal = 0;
+ gtk_window_set_title (GTK_WINDOW (window), "test");
+ g_assert (normal == 20);
+
+ gtk_builder_add_from_string (builder, buffer_extra,
+ strlen (buffer_extra), NULL);
+ gtk_builder_add_from_string (builder, buffer_extra2,
+ strlen (buffer_extra2), NULL);
+ gtk_builder_connect_signals (builder, NULL);
+ window = gtk_builder_get_object (builder, "window2");
+ gtk_window_set_title (GTK_WINDOW (window), "test");
+ g_assert (normal == 30);
+ window = gtk_builder_get_object (builder, "window3");
+ gtk_window_set_title (GTK_WINDOW (window), "test");
+ g_assert (normal == 40);
+
+ g_object_unref (builder);
+
+ return TRUE;
+}
+
+gboolean test_uimanager_simple (void)
+{
+ GtkBuilder *builder;
+ GObject *uimgr, *menubar;
+ GObject *menu, *label;
+ GList *children;
+ const gchar buffer[] =
+ "<interface>"
+ " <object class=\"GtkUIManager\" id=\"uimgr1\"/>"
+ "</interface>";
+
+ const gchar buffer2[] =
+ "<interface>"
+ " <object class=\"GtkUIManager\" id=\"uimgr1\">"
+ " <child>"
+ " <object class=\"GtkActionGroup\" id=\"ag1\">"
+ " <child>"
+ " <object class=\"GtkAction\" id=\"file\">"
+ " <property name=\"label\">_File</property>"
+ " </object>"
+ " </child>"
+ " </object>"
+ " </child>"
+ " <ui>"
+ " <menubar name=\"menubar1\">"
+ " <menu action=\"file\">"
+ " </menu>"
+ " </menubar>"
+ " </ui>"
+ " </object>"
+ " <object class=\"GtkWindow\" id=\"window1\">"
+ " <child>"
+ " <object class=\"GtkMenuBar\" id=\"menubar1\" constructor=\"uimgr1\"/>"
+ " </child>"
+ " </object>"
+ "</interface>";
+
+ builder = builder_new_from_string (buffer, -1, NULL);
+
+ uimgr = gtk_builder_get_object (builder, "uimgr1");
+ g_return_val_if_fail (uimgr != NULL, FALSE);
+ g_return_val_if_fail (GTK_IS_UI_MANAGER (uimgr), FALSE);
+
+ g_object_unref (builder);
+
+ builder = builder_new_from_string (buffer2, -1, NULL);
+
+ menubar = gtk_builder_get_object (builder, "menubar1");
+ g_return_val_if_fail (menubar != NULL, FALSE);
+ g_return_val_if_fail (GTK_IS_MENU_BAR (menubar), FALSE);
+
+ children = gtk_container_get_children (GTK_CONTAINER (menubar));
+ menu = children->data;
+ g_return_val_if_fail (menu != NULL, FALSE);
+ g_return_val_if_fail (GTK_IS_MENU_ITEM (menu), FALSE);
+ g_return_val_if_fail (strcmp (GTK_WIDGET (menu)->name, "file") == 0, FALSE);
+ g_list_free (children);
+
+ label = G_OBJECT (GTK_BIN (menu)->child);
+ g_return_val_if_fail (label != NULL, FALSE);
+ g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
+ g_return_val_if_fail
+ (strcmp (gtk_label_get_text (GTK_LABEL (label)), "File") == 0, FALSE);
+
+ g_object_unref (builder);
+
+ return TRUE;
+}
+
+gboolean test_domain (void)
+{
+ GtkBuilder *builder;
+ const gchar buffer1[] = "<interface/>";
+ const gchar buffer2[] = "<interface domain=\"domain\"/>";
+ const gchar *domain;
+
+ builder = builder_new_from_string (buffer1, -1, NULL);
+ domain = gtk_builder_get_translation_domain (builder);
+ g_assert (domain == NULL);
+ g_object_unref (builder);
+
+ builder = builder_new_from_string (buffer1, -1, "domain-1");
+ domain = gtk_builder_get_translation_domain (builder);
+ g_assert (domain);
+ g_assert (strcmp (domain, "domain-1") == 0);
+ g_object_unref (builder);
+
+ builder = builder_new_from_string (buffer2, -1, NULL);
+ domain = gtk_builder_get_translation_domain (builder);
+ g_assert (domain);
+ g_assert (strcmp (domain, "domain") == 0);
+ g_object_unref (builder);
+
+ builder = builder_new_from_string (buffer2, -1, "domain-1");
+ domain = gtk_builder_get_translation_domain (builder);
+ g_assert (domain);
+ g_assert (strcmp (domain, "domain-1") == 0);
+ g_object_unref (builder);
+
+ return TRUE;
+}
+
+#if 0
+gboolean test_translation (void)
+{
+ GtkBuilder *builder;
+ const gchar buffer[] =
+ "<interface>"
+ " <object class=\"GtkWindow\" id=\"window1\">"
+ " <child>"
+ " <object class=\"GtkLabel\" id=\"label\">"
+ " <property name=\"label\" translatable=\"yes\">File</property>"
+ " </object>"
+ " </child>"
+ " </object>"
+ "</interface>";
+ GtkLabel *label;
+
+ setlocale (LC_ALL, "sv_SE");
+ textdomain ("builder");
+ bindtextdomain ("builder", "tests");
+
+ builder = builder_new_from_string (buffer, -1, NULL);
+ label = GTK_LABEL (gtk_builder_get_object (builder, "label"));
+ g_assert (strcmp (gtk_label_get_text (label), "Arkiv") == 0);
+ g_object_unref (builder);
+
+ return TRUE;
+}
+#endif
+
+gboolean test_sizegroup (void)
+{
+ GtkBuilder * builder;
+ const gchar buffer1[] =
+ "<interface domain=\"test\">"
+ " <object class=\"GtkSizeGroup\" id=\"sizegroup1\">"
+ " <property name=\"mode\">GTK_SIZE_GROUP_HORIZONTAL</property>"
+ " <widgets>"
+ " <widget name=\"radio1\"/>"
+ " <widget name=\"radio2\"/>"
+ " </widgets>"
+ " </object>"
+ " <object class=\"GtkWindow\" id=\"window1\">"
+ " <child>"
+ " <object class=\"GtkVBox\" id=\"vbox1\">"
+ " <child>"
+ " <object class=\"GtkRadioButton\" id=\"radio1\"/>"
+ " </child>"
+ " <child>"
+ " <object class=\"GtkRadioButton\" id=\"radio2\"/>"
+ " </child>"
+ " </object>"
+ " </child>"
+ " </object>"
+ "</interface>";
+ const gchar buffer2[] =
+ "<interface domain=\"test\">"
+ " <object class=\"GtkSizeGroup\" id=\"sizegroup1\">"
+ " <property name=\"mode\">GTK_SIZE_GROUP_HORIZONTAL</property>"
+ " <widgets>"
+ " </widgets>"
+ " </object>"
+ "</interface>";
+ const gchar buffer3[] =
+ "<interface domain=\"test\">"
+ " <object class=\"GtkSizeGroup\" id=\"sizegroup1\">"
+ " <property name=\"mode\">GTK_SIZE_GROUP_HORIZONTAL</property>"
+ " <widgets>"
+ " <widget name=\"radio1\"/>"
+ " <widget name=\"radio2\"/>"
+ " </widgets>"
+ " </object>"
+ " <object class=\"GtkSizeGroup\" id=\"sizegroup2\">"
+ " <property name=\"mode\">GTK_SIZE_GROUP_HORIZONTAL</property>"
+ " <widgets>"
+ " <widget name=\"radio1\"/>"
+ " <widget name=\"radio2\"/>"
+ " </widgets>"
+ " </object>"
+ " <object class=\"GtkWindow\" id=\"window1\">"
+ " <child>"
+ " <object class=\"GtkVBox\" id=\"vbox1\">"
+ " <child>"
+ " <object class=\"GtkRadioButton\" id=\"radio1\"/>"
+ " </child>"
+ " <child>"
+ " <object class=\"GtkRadioButton\" id=\"radio2\"/>"
+ " </child>"
+ " </object>"
+ " </child>"
+ " </object>"
+ "</interface>";
+ GObject *sizegroup;
+ GSList *widgets;
+
+ builder = builder_new_from_string (buffer1, -1, NULL);
+ sizegroup = gtk_builder_get_object (builder, "sizegroup1");
+ widgets = gtk_size_group_get_widgets (GTK_SIZE_GROUP (sizegroup));
+ g_return_val_if_fail (g_slist_length (widgets) == 2, FALSE);
+ g_slist_free (widgets);
+ g_object_unref (builder);
+
+ builder = builder_new_from_string (buffer2, -1, NULL);
+ sizegroup = gtk_builder_get_object (builder, "sizegroup1");
+ widgets = gtk_size_group_get_widgets (GTK_SIZE_GROUP (sizegroup));
+ g_return_val_if_fail (g_slist_length (widgets) == 0, FALSE);
+ g_slist_free (widgets);
+ g_object_unref (builder);
+
+ builder = builder_new_from_string (buffer3, -1, NULL);
+ sizegroup = gtk_builder_get_object (builder, "sizegroup1");
+ widgets = gtk_size_group_get_widgets (GTK_SIZE_GROUP (sizegroup));
+ g_return_val_if_fail (g_slist_length (widgets) == 2, FALSE);
+ g_slist_free (widgets);
+ sizegroup = gtk_builder_get_object (builder, "sizegroup2");
+ widgets = gtk_size_group_get_widgets (GTK_SIZE_GROUP (sizegroup));
+ g_return_val_if_fail (g_slist_length (widgets) == 2, FALSE);
+ g_slist_free (widgets);
+ g_object_unref (builder);
+
+ return TRUE;
+}
+
+gboolean test_list_store (void)
+{
+ const gchar buffer1[] =
+ "<interface>"
+ " <object class=\"GtkListStore\" id=\"liststore1\">"
+ " <columns>"
+ " <column type=\"gchararray\"/>"
+ " <column type=\"guint\"/>"
+ " </columns>"
+ " </object>"
+ "</interface>";
+ const char buffer2[] =
+ "<interface>"
+ " <object class=\"GtkListStore\" id=\"liststore1\">"
+ " <columns>"
+ " <column type=\"gchararray\"/>"
+ " <column type=\"gchararray\"/>"
+ " <column type=\"gint\"/>"
+ " </columns>"
+ " <data>"
+ " <row>"
+ " <col id=\"0\">John</col>"
+ " <col id=\"1\">Doe</col>"
+ " <col id=\"2\">25</col>"
+ " </row>"
+ " <row>"
+ " <col id=\"0\">Johan</col>"
+ " <col id=\"1\">Dole</col>"
+ " <col id=\"2\">50</col>"
+ " </row>"
+ " </data>"
+ " </object>"
+ "</interface>";
+ GtkBuilder *builder;
+ GObject *store;
+ GtkTreeIter iter;
+ gchar *surname, *lastname;
+ int age;
+
+ builder = builder_new_from_string (buffer1, -1, NULL);
+ store = gtk_builder_get_object (builder, "liststore1");
+ g_return_val_if_fail (gtk_tree_model_get_n_columns (GTK_TREE_MODEL (store)) == 2, FALSE);
+ g_return_val_if_fail (gtk_tree_model_get_column_type (GTK_TREE_MODEL (store), 0) == G_TYPE_STRING, FALSE);
+ g_return_val_if_fail (gtk_tree_model_get_column_type (GTK_TREE_MODEL (store), 1) == G_TYPE_UINT, FALSE);
+ g_object_unref (builder);
+
+ builder = builder_new_from_string (buffer2, -1, NULL);
+ store = gtk_builder_get_object (builder, "liststore1");
+ g_return_val_if_fail (gtk_tree_model_get_n_columns (GTK_TREE_MODEL (store)) == 3, FALSE);
+ g_return_val_if_fail (gtk_tree_model_get_column_type (GTK_TREE_MODEL (store), 0) == G_TYPE_STRING, FALSE);
+ g_return_val_if_fail (gtk_tree_model_get_column_type (GTK_TREE_MODEL (store), 1) == G_TYPE_STRING, FALSE);
+ g_return_val_if_fail (gtk_tree_model_get_column_type (GTK_TREE_MODEL (store), 2) == G_TYPE_INT, FALSE);
+
+ g_return_val_if_fail (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter) == TRUE, FALSE);
+ gtk_tree_model_get (GTK_TREE_MODEL (store), &iter,
+ 0, &surname,
+ 1, &lastname,
+ 2, &age,
+ -1);
+ g_assert (surname != NULL);
+ g_return_val_if_fail (strcmp (surname, "John") == 0, FALSE);
+ g_free (surname);
+ g_assert (lastname != NULL);
+ g_return_val_if_fail (strcmp (lastname, "Doe") == 0, FALSE);
+ g_free (lastname);
+ g_return_val_if_fail (age == 25, FALSE);
+ g_return_val_if_fail (gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter) == TRUE, FALSE);
+
+ gtk_tree_model_get (GTK_TREE_MODEL (store), &iter,
+ 0, &surname,
+ 1, &lastname,
+ 2, &age,
+ -1);
+ g_assert (surname != NULL);
+ g_return_val_if_fail (strcmp (surname, "Johan") == 0, FALSE);
+ g_free (surname);
+ g_assert (lastname != NULL);
+ g_return_val_if_fail (strcmp (lastname, "Dole") == 0, FALSE);
+ g_free (lastname);
+ g_return_val_if_fail (age == 50, FALSE);
+ g_return_val_if_fail (gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter) == FALSE, FALSE);
+
+ g_object_unref (builder);
+
+ return TRUE;
+}
+
+gboolean test_tree_store (void)
+{
+ const gchar buffer[] =
+ "<interface domain=\"test\">"
+ " <object class=\"GtkTreeStore\" id=\"treestore1\">"
+ " <columns>"
+ " <column type=\"gchararray\"/>"
+ " <column type=\"guint\"/>"
+ " </columns>"
+ " </object>"
+ "</interface>";
+ GtkBuilder *builder;
+ GObject *store;
+
+ builder = builder_new_from_string (buffer, -1, NULL);
+ store = gtk_builder_get_object (builder, "treestore1");
+ g_return_val_if_fail (gtk_tree_model_get_n_columns (GTK_TREE_MODEL (store)) == 2, FALSE);
+ g_return_val_if_fail (gtk_tree_model_get_column_type (GTK_TREE_MODEL (store), 0) == G_TYPE_STRING, FALSE);
+ g_return_val_if_fail (gtk_tree_model_get_column_type (GTK_TREE_MODEL (store), 1) == G_TYPE_UINT, FALSE);
+
+ g_object_unref (builder);
+
+ return TRUE;
+}
+
+gboolean test_types (void)
+{
+ const gchar buffer[] =
+ "<interface>"
+ " <object class=\"GtkAction\" id=\"action\"/>"
+ " <object class=\"GtkActionGroup\" id=\"actiongroup\"/>"
+ " <object class=\"GtkAlignment\" id=\"alignment\"/>"
+ " <object class=\"GtkArrow\" id=\"arrow\"/>"
+ " <object class=\"GtkButton\" id=\"button\"/>"
+ " <object class=\"GtkCheckButton\" id=\"checkbutton\"/>"
+ " <object class=\"GtkDialog\" id=\"dialog\"/>"
+ " <object class=\"GtkDrawingArea\" id=\"drawingarea\"/>"
+ " <object class=\"GtkEventBox\" id=\"eventbox\"/>"
+ " <object class=\"GtkEntry\" id=\"entry\"/>"
+ " <object class=\"GtkFontButton\" id=\"fontbutton\"/>"
+ " <object class=\"GtkHButtonBox\" id=\"hbuttonbox\"/>"
+ " <object class=\"GtkHBox\" id=\"hbox\"/>"
+ " <object class=\"GtkHPaned\" id=\"hpaned\"/>"
+ " <object class=\"GtkHRuler\" id=\"hruler\"/>"
+ " <object class=\"GtkHScale\" id=\"hscale\"/>"
+ " <object class=\"GtkHScrollbar\" id=\"hscrollbar\"/>"
+ " <object class=\"GtkHSeparator\" id=\"hseparator\"/>"
+ " <object class=\"GtkImage\" id=\"image\"/>"
+ " <object class=\"GtkLabel\" id=\"label\"/>"
+ " <object class=\"GtkListStore\" id=\"liststore\"/>"
+ " <object class=\"GtkMenuBar\" id=\"menubar\"/>"
+ " <object class=\"GtkNotebook\" id=\"notebook\"/>"
+ " <object class=\"GtkProgressBar\" id=\"progressbar\"/>"
+ " <object class=\"GtkRadioButton\" id=\"radiobutton\"/>"
+ " <object class=\"GtkSizeGroup\" id=\"sizegroup\"/>"
+ " <object class=\"GtkScrolledWindow\" id=\"scrolledwindow\"/>"
+ " <object class=\"GtkSpinButton\" id=\"spinbutton\"/>"
+ " <object class=\"GtkStatusbar\" id=\"statusbar\"/>"
+ " <object class=\"GtkTextView\" id=\"textview\"/>"
+ " <object class=\"GtkToggleAction\" id=\"toggleaction\"/>"
+ " <object class=\"GtkToggleButton\" id=\"togglebutton\"/>"
+ " <object class=\"GtkToolbar\" id=\"toolbar\"/>"
+ " <object class=\"GtkTreeStore\" id=\"treestore\"/>"
+ " <object class=\"GtkTreeView\" id=\"treeview\"/>"
+ " <object class=\"GtkTable\" id=\"table\"/>"
+ " <object class=\"GtkVBox\" id=\"vbox\"/>"
+ " <object class=\"GtkVButtonBox\" id=\"vbuttonbox\"/>"
+ " <object class=\"GtkVScrollbar\" id=\"vscrollbar\"/>"
+ " <object class=\"GtkVSeparator\" id=\"vseparator\"/>"
+ " <object class=\"GtkViewport\" id=\"viewport\"/>"
+ " <object class=\"GtkVRuler\" id=\"vruler\"/>"
+ " <object class=\"GtkVPaned\" id=\"vpaned\"/>"
+ " <object class=\"GtkVScale\" id=\"vscale\"/>"
+ " <object class=\"GtkWindow\" id=\"window\"/>"
+ " <object class=\"GtkUIManager\" id=\"uimanager\"/>"
+ "</interface>";
+ GtkBuilder *builder;
+
+ builder = builder_new_from_string (buffer, -1, NULL);
+ g_object_unref (builder);
+
+ return TRUE;
+}
+
+gboolean test_spin_button (void)
+{
+ GtkBuilder *builder;
+ const gchar buffer[] =
+ "<interface>"
+ "<object class=\"GtkAdjustment\" id=\"adjustment1\">"
+ "<property name=\"lower\">0</property>"
+ "<property name=\"upper\">10</property>"
+ "<property name=\"step-increment\">2</property>"
+ "<property name=\"page-increment\">3</property>"
+ "<property name=\"page-size\">5</property>"
+ "<property name=\"value\">1</property>"
+ "</object>"
+ "<object class=\"GtkSpinButton\" id=\"spinbutton1\">"
+ "<property name=\"visible\">True</property>"
+ "<property name=\"adjustment\">adjustment1</property>"
+ "</object>"
+ "</interface>";
+ GObject *object;
+ GtkAdjustment *adjustment;
+ gdouble value;
+
+ builder = builder_new_from_string (buffer, -1, NULL);
+ object = gtk_builder_get_object (builder, "spinbutton1");
+ g_assert (GTK_IS_SPIN_BUTTON (object));
+ adjustment = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (object));
+ g_assert (GTK_IS_ADJUSTMENT (adjustment));
+ g_object_get (adjustment, "value", &value, NULL);
+ g_return_val_if_fail (value == 1, FALSE);
+ g_object_get (adjustment, "lower", &value, NULL);
+ g_return_val_if_fail (value == 0, FALSE);
+ g_object_get (adjustment, "upper", &value, NULL);
+ g_return_val_if_fail (value == 10, FALSE);
+ g_object_get (adjustment, "step-increment", &value, NULL);
+ g_return_val_if_fail (value == 2, FALSE);
+ g_object_get (adjustment, "page-increment", &value, NULL);
+ g_return_val_if_fail (value == 3, FALSE);
+ g_object_get (adjustment, "page-size", &value, NULL);
+ g_return_val_if_fail (value == 5, FALSE);
+
+ g_object_unref (builder);
+ return TRUE;
+}
+
+gboolean test_notebook (void)
+{
+ GtkBuilder *builder;
+ const gchar buffer[] =
+ "<interface>"
+ " <object class=\"GtkNotebook\" id=\"notebook1\">"
+ " <child>"
+ " <object class=\"GtkLabel\" id=\"label1\">"
+ " <property name=\"label\">label1</property>"
+ " </object>"
+ " </child>"
+ " <child type=\"tab\">"
+ " <object class=\"GtkLabel\" id=\"tablabel1\">"
+ " <property name=\"label\">tab_label1</property>"
+ " </object>"
+ " </child>"
+ " <child>"
+ " <object class=\"GtkLabel\" id=\"label2\">"
+ " <property name=\"label\">label2</property>"
+ " </object>"
+ " </child>"
+ " <child type=\"tab\">"
+ " <object class=\"GtkLabel\" id=\"tablabel2\">"
+ " <property name=\"label\">tab_label2</property>"
+ " </object>"
+ " </child>"
+ " </object>"
+ "</interface>";
+ GObject *notebook;
+ GtkWidget *label;
+
+ builder = builder_new_from_string (buffer, -1, NULL);
+ notebook = gtk_builder_get_object (builder, "notebook1");
+ g_assert (notebook != NULL);
+ g_return_val_if_fail (gtk_notebook_get_n_pages (GTK_NOTEBOOK (notebook)) == 2,
+ FALSE);
+
+ label = gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), 0);
+ g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
+ g_return_val_if_fail (strcmp (gtk_label_get_label (GTK_LABEL (label)),
+ "label1") == 0, FALSE);
+ label = gtk_notebook_get_tab_label (GTK_NOTEBOOK (notebook), label);
+ g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
+ g_return_val_if_fail (strcmp (gtk_label_get_label (GTK_LABEL (label)),
+ "tab_label1") == 0, FALSE);
+
+ label = gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), 1);
+ g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
+ g_return_val_if_fail (strcmp (gtk_label_get_label (GTK_LABEL (label)),
+ "label2") == 0, FALSE);
+ label = gtk_notebook_get_tab_label (GTK_NOTEBOOK (notebook), label);
+ g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
+ g_return_val_if_fail (strcmp (gtk_label_get_label (GTK_LABEL (label)),
+ "tab_label2") == 0, FALSE);
+
+ g_object_unref (builder);
+ return TRUE;
+}
+
+gboolean test_construct_only_property (void)
+{
+ GtkBuilder *builder;
+ const gchar buffer[] =
+ "<interface>"
+ " <object class=\"GtkWindow\" id=\"window1\">"
+ " <property name=\"type\">GTK_WINDOW_POPUP</property>"
+ " </object>"
+ "</interface>";
+ const gchar buffer2[] =
+ "<interface>"
+ " <object class=\"GtkTextTagTable\" id=\"tagtable1\"/>"
+ " <object class=\"GtkTextBuffer\" id=\"textbuffer1\">"
+ " <property name=\"tag-table\">tagtable1</property>"
+ " </object>"
+ "</interface>";
+ GObject *widget, *tagtable, *textbuffer;
+ GtkWindowType type;
+
+ builder = builder_new_from_string (buffer, -1, NULL);
+ widget = gtk_builder_get_object (builder, "window1");
+ g_object_get (widget, "type", &type, NULL);
+ g_return_val_if_fail (type == GTK_WINDOW_POPUP, FALSE);
+ g_object_unref (builder);
+
+ builder = builder_new_from_string (buffer2, -1, NULL);
+ textbuffer = gtk_builder_get_object (builder, "textbuffer1");
+ g_return_val_if_fail (textbuffer != NULL, FALSE);
+ g_object_get (textbuffer, "tag-table", &tagtable, NULL);
+ g_return_val_if_fail (tagtable == gtk_builder_get_object (builder, "tagtable1"), FALSE);
+ g_object_unref (builder);
+
+ return TRUE;
+}
+
+gboolean test_children (void)
+{
+ GtkBuilder * builder;
+ GList *children;
+ const gchar buffer1[] =
+ "<interface>"
+ " <object class=\"GtkWindow\" id=\"window1\">"
+ " <child>"
+ " <object class=\"GtkButton\" id=\"button1\">"
+ " <property name=\"label\">Hello</property>"
+ " </object>"
+ " </child>"
+ " </object>"
+ "</interface>";
+ const gchar buffer2[] =
+ "<interface>"
+ " <object class=\"GtkDialog\" id=\"dialog1\">"
+ " <child internal-child=\"vbox\">"
+ " <object class=\"GtkVBox\" id=\"dialog1-vbox\">"
+ " <property name=\"border-width\">10</property>"
+ " <child internal-child=\"action_area\">"
+ " <object class=\"GtkHButtonBox\" id=\"dialog1-action_area\">"
+ " <property name=\"border-width\">20</property>"
+ " </object>"
+ " </child>"
+ " </object>"
+ " </child>"
+ " </object>"
+ "</interface>";
+
+ GObject *window, *button;
+ GObject *dialog, *vbox, *action_area;
+
+ builder = builder_new_from_string (buffer1, -1, NULL);
+ window = gtk_builder_get_object (builder, "window1");
+ g_return_val_if_fail (window != NULL, FALSE);
+ g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
+
+ button = gtk_builder_get_object (builder, "button1");
+ g_return_val_if_fail (button != NULL, FALSE);
+ g_return_val_if_fail (GTK_IS_BUTTON (button), FALSE);
+ g_return_val_if_fail (strcmp (GTK_WIDGET (GTK_WIDGET (button)->parent)->name, "window1") == 0, FALSE);
+ g_object_unref (builder);
+
+ builder = builder_new_from_string (buffer2, -1, NULL);
+ dialog = gtk_builder_get_object (builder, "dialog1");
+ g_return_val_if_fail (dialog != NULL, FALSE);
+ g_return_val_if_fail (GTK_IS_DIALOG (dialog), FALSE);
+ children = gtk_container_get_children (GTK_CONTAINER (dialog));
+ g_return_val_if_fail (g_list_length (children) == 1, FALSE);
+ g_list_free (children);
+
+ vbox = gtk_builder_get_object (builder, "dialog1-vbox");
+ g_return_val_if_fail (vbox != NULL, FALSE);
+ g_return_val_if_fail (GTK_IS_VBOX (vbox), FALSE);
+ g_return_val_if_fail (GTK_WIDGET (vbox)->parent != NULL, FALSE);
+ g_return_val_if_fail (strcmp (GTK_WIDGET (GTK_WIDGET (vbox)->parent)->name, "dialog1") == 0, FALSE);
+ g_return_val_if_fail (GTK_CONTAINER (vbox)->border_width == 10, FALSE);
+ g_return_val_if_fail (strcmp (GTK_WIDGET (GTK_DIALOG (dialog)->vbox)->name,
+ "dialog1-vbox") == 0, FALSE);
+
+ action_area = gtk_builder_get_object (builder, "dialog1-action_area");
+ g_return_val_if_fail (action_area != NULL, FALSE);
+ g_return_val_if_fail (GTK_IS_HBUTTON_BOX (action_area), FALSE);
+ g_return_val_if_fail (GTK_WIDGET (action_area)->parent != NULL, FALSE);
+ g_return_val_if_fail (GTK_CONTAINER (action_area)->border_width == 20, FALSE);
+ g_return_val_if_fail (GTK_DIALOG (dialog)->action_area != NULL, FALSE);
+ g_return_val_if_fail (GTK_WIDGET (GTK_DIALOG (dialog)->action_area)->name != NULL, FALSE);
+ g_return_val_if_fail (strcmp (GTK_WIDGET (GTK_DIALOG (dialog)->action_area)->name,
+ "dialog1-action_area") == 0, FALSE);
+ g_object_unref (builder);
+
+ return TRUE;
+}
+
+gboolean test_child_properties (void)
+{
+ GtkBuilder * builder;
+ const gchar buffer1[] =
+ "<interface>"
+ " <object class=\"GtkVBox\" id=\"vbox1\">"
+ " <child>"
+ " <object class=\"GtkLabel\" id=\"label1\"/>"
+ " <packing>"
+ " <property name=\"pack-type\">start</property>"
+ " </packing>"
+ " </child>"
+ " <child>"
+ " <object class=\"GtkLabel\" id=\"label2\"/>"
+ " <packing>"
+ " <property name=\"pack-type\">end</property>"
+ " </packing>"
+ " </child>"
+ " </object>"
+ "</interface>";
+
+ GObject *label, *vbox;
+ GtkPackType pack_type;
+
+ builder = builder_new_from_string (buffer1, -1, NULL);
+ vbox = gtk_builder_get_object (builder, "vbox1");
+ g_return_val_if_fail (GTK_IS_VBOX (vbox), FALSE);
+
+ label = gtk_builder_get_object (builder, "label1");
+ g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
+ gtk_container_child_get (GTK_CONTAINER (vbox),
+ GTK_WIDGET (label),
+ "pack-type",
+ &pack_type,
+ NULL);
+ g_return_val_if_fail (pack_type == GTK_PACK_START, FALSE);
+
+ label = gtk_builder_get_object (builder, "label2");
+ g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
+ gtk_container_child_get (GTK_CONTAINER (vbox),
+ GTK_WIDGET (label),
+ "pack-type",
+ &pack_type,
+ NULL);
+ g_return_val_if_fail (pack_type == GTK_PACK_END, FALSE);
+
+ g_object_unref (builder);
+
+ return TRUE;
+}
+
+gboolean test_treeview_column (void)
+{
+ GtkBuilder *builder;
+ const gchar buffer[] =
+ "<interface>"
+ "<object class=\"GtkListStore\" id=\"liststore1\">"
+ " <columns>"
+ " <column type=\"gchararray\"/>"
+ " <column type=\"guint\"/>"
+ " </columns>"
+ " <data>"
+ " <row>"
+ " <col id=\"0\">John</col>"
+ " <col id=\"1\">25</col>"
+ " </row>"
+ " </data>"
+ "</object>"
+ "<object class=\"GtkWindow\" id=\"window1\">"
+ " <child>"
+ " <object class=\"GtkTreeView\" id=\"treeview1\">"
+ " <property name=\"visible\">True</property>"
+ " <property name=\"model\">liststore1</property>"
+ " <child>"
+ " <object class=\"GtkTreeViewColumn\" id=\"column1\">"
+ " <property name=\"title\">Test</property>"
+ " <child>"
+ " <object class=\"GtkCellRendererText\" id=\"renderer1\"/>"
+ " <attributes>"
+ " <attribute name=\"text\">1</attribute>"
+ " </attributes>"
+ " </child>"
+ " </object>"
+ " </child>"
+ " <child>"
+ " <object class=\"GtkTreeViewColumn\" id=\"column2\">"
+ " <property name=\"title\">Number</property>"
+ " <child>"
+ " <object class=\"GtkCellRendererText\" id=\"renderer2\"/>"
+ " <attributes>"
+ " <attribute name=\"text\">0</attribute>"
+ " </attributes>"
+ " </child>"
+ " </object>"
+ " </child>"
+ " </object>"
+ " </child>"
+ "</object>"
+ "</interface>";
+ GObject *treeview;
+ GtkTreeViewColumn *column;
+ GList *renderers;
+ GObject *renderer;
+ gchar *text;
+
+ builder = builder_new_from_string (buffer, -1, NULL);
+ treeview = gtk_builder_get_object (builder, "treeview1");
+ g_return_val_if_fail (treeview, FALSE);
+ g_return_val_if_fail (GTK_IS_TREE_VIEW (treeview), FALSE);
+ column = gtk_tree_view_get_column (GTK_TREE_VIEW (treeview), 0);
+ g_return_val_if_fail (strcmp (gtk_tree_view_column_get_title (column),
+ "Test") == 0, FALSE);
+
+ renderers = gtk_tree_view_column_get_cell_renderers (column);
+ g_return_val_if_fail (g_list_length (renderers) == 1, FALSE);
+ renderer = g_list_nth_data (renderers, 0);
+ g_return_val_if_fail (renderer, FALSE);
+ g_return_val_if_fail (GTK_IS_CELL_RENDERER_TEXT (renderer), FALSE);
+ g_list_free (renderers);
+
+ gtk_widget_realize (GTK_WIDGET (treeview));
+
+ renderer = gtk_builder_get_object (builder, "renderer1");
+ g_object_get (renderer, "text", &text, NULL);
+ g_assert (text);
+ g_return_val_if_fail (strcmp (text, "25") == 0, FALSE);
+ g_free (text);
+
+ renderer = gtk_builder_get_object (builder, "renderer2");
+ g_object_get (renderer, "text", &text, NULL);
+ g_assert (text);
+ g_return_val_if_fail (strcmp (text, "John") == 0, FALSE);
+ g_free (text);
+
+ gtk_widget_unrealize (GTK_WIDGET (treeview));
+
+ g_object_unref (builder);
+ return TRUE;
+}
+
+gboolean test_icon_view (void)
+{
+ GtkBuilder *builder;
+ const gchar buffer[] =
+ "<interface>"
+ " <object class=\"GtkListStore\" id=\"liststore1\">"
+ " <columns>"
+ " <column type=\"gchararray\"/>"
+ " <column type=\"GdkPixbuf\"/>"
+ " </columns>"
+ " <data>"
+ " <row>"
+ " <col id=\"0\">test</col>"
+ " </row>"
+ " </data>"
+ " </object>"
+ " <object class=\"GtkWindow\" id=\"window1\">"
+ " <child>"
+ " <object class=\"GtkIconView\" id=\"iconview1\">"
+ " <property name=\"model\">liststore1</property>"
+ " <property name=\"text-column\">0</property>"
+ " <property name=\"pixbuf-column\">1</property>"
+ " <property name=\"visible\">True</property>"
+ " <child>"
+ " <object class=\"GtkCellRendererText\" id=\"renderer1\"/>"
+ " <attributes>"
+ " <attribute name=\"text\">0</attribute>"
+ " </attributes>"
+ " </child>"
+ " </object>"
+ " </child>"
+ " </object>"
+ "</interface>";
+ GObject *iconview;
+ GObject *renderer;
+ gchar *text;
+
+ builder = builder_new_from_string (buffer, -1, NULL);
+ iconview = gtk_builder_get_object (builder, "iconview1");
+ g_return_val_if_fail (iconview, FALSE);
+ g_return_val_if_fail (GTK_IS_ICON_VIEW (iconview), FALSE);
+
+ gtk_widget_realize (GTK_WIDGET (iconview));
+
+ renderer = gtk_builder_get_object (builder, "renderer1");
+ g_object_get (renderer, "text", &text, NULL);
+ g_assert (text);
+ g_return_val_if_fail (strcmp (text, "test") == 0, FALSE);
+ g_free (text);
+
+ g_object_unref (builder);
+ return TRUE;
+}
+
+gboolean test_combo_box (void)
+{
+ GtkBuilder *builder;
+ const gchar buffer[] =
+ "<interface>"
+ " <object class=\"GtkListStore\" id=\"liststore1\">"
+ " <columns>"
+ " <column type=\"guint\"/>"
+ " <column type=\"gchararray\"/>"
+ " </columns>"
+ " <data>"
+ " <row>"
+ " <col id=\"0\">1</col>"
+ " <col id=\"1\">Foo</col>"
+ " </row>"
+ " <row>"
+ " <col id=\"0\">2</col>"
+ " <col id=\"1\">Bar</col>"
+ " </row>"
+ " </data>"
+ " </object>"
+ " <object class=\"GtkWindow\" id=\"window1\">"
+ " <child>"
+ " <object class=\"GtkComboBox\" id=\"combobox1\">"
+ " <property name=\"model\">liststore1</property>"
+ " <property name=\"visible\">True</property>"
+ " <child>"
+ " <object class=\"GtkCellRendererText\" id=\"renderer1\"/>"
+ " <attributes>"
+ " <attribute name=\"text\">0</attribute>"
+ " </attributes>"
+ " </child>"
+ " <child>"
+ " <object class=\"GtkCellRendererText\" id=\"renderer2\"/>"
+ " <attributes>"
+ " <attribute name=\"text\">1</attribute>"
+ " </attributes>"
+ " </child>"
+ " </object>"
+ " </child>"
+ " </object>"
+ "</interface>";
+ GObject *combobox;
+ GObject *renderer;
+ gchar *text;
+
+ builder = builder_new_from_string (buffer, -1, NULL);
+ combobox = gtk_builder_get_object (builder, "combobox1");
+ g_return_val_if_fail (combobox, FALSE);
+ gtk_widget_realize (GTK_WIDGET (combobox));
+
+ renderer = gtk_builder_get_object (builder, "renderer2");
+ g_assert (renderer);
+ g_object_get (renderer, "text", &text, NULL);
+ g_assert (text);
+ g_return_val_if_fail (strcmp (text, "Bar") == 0, FALSE);
+ g_free (text);
+
+ renderer = gtk_builder_get_object (builder, "renderer1");
+ g_assert (renderer);
+ g_object_get (renderer, "text", &text, NULL);
+ g_assert (text);
+ g_return_val_if_fail (strcmp (text, "2") == 0, FALSE);
+ g_free (text);
+
+ g_object_unref (builder);
+ return TRUE;
+}
+
+gboolean test_combo_box_entry (void)
+{
+ GtkBuilder *builder;
+ const gchar buffer[] =
+ "<interface>"
+ " <object class=\"GtkListStore\" id=\"liststore1\">"
+ " <columns>"
+ " <column type=\"guint\"/>"
+ " <column type=\"gchararray\"/>"
+ " </columns>"
+ " <data>"
+ " <row>"
+ " <col id=\"0\">1</col>"
+ " <col id=\"1\">Foo</col>"
+ " </row>"
+ " <row>"
+ " <col id=\"0\">2</col>"
+ " <col id=\"1\">Bar</col>"
+ " </row>"
+ " </data>"
+ " </object>"
+ " <object class=\"GtkWindow\" id=\"window1\">"
+ " <child>"
+ " <object class=\"GtkComboBoxEntry\" id=\"comboboxentry1\">"
+ " <property name=\"model\">liststore1</property>"
+ " <property name=\"visible\">True</property>"
+ " <child>"
+ " <object class=\"GtkCellRendererText\" id=\"renderer1\"/>"
+ " <attributes>"
+ " <attribute name=\"text\">0</attribute>"
+ " </attributes>"
+ " </child>"
+ " <child>"
+ " <object class=\"GtkCellRendererText\" id=\"renderer2\"/>"
+ " <attributes>"
+ " <attribute name=\"text\">1</attribute>"
+ " </attributes>"
+ " </child>"
+ " </object>"
+ " </child>"
+ " </object>"
+ "</interface>";
+ GObject *combobox;
+ GObject *renderer;
+ gchar *text;
+
+ builder = builder_new_from_string (buffer, -1, NULL);
+ combobox = gtk_builder_get_object (builder, "comboboxentry1");
+ g_return_val_if_fail (combobox, FALSE);
+
+ renderer = gtk_builder_get_object (builder, "renderer2");
+ g_assert (renderer);
+ g_object_get (renderer, "text", &text, NULL);
+ g_assert (text);
+ g_return_val_if_fail (strcmp (text, "Bar") == 0, FALSE);
+ g_free (text);
+
+ renderer = gtk_builder_get_object (builder, "renderer1");
+ g_assert (renderer);
+ g_object_get (renderer, "text", &text, NULL);
+ g_assert (text);
+ g_return_val_if_fail (strcmp (text, "2") == 0, FALSE);
+ g_free (text);
+
+ g_object_unref (builder);
+ return TRUE;
+}
+
+gboolean test_cell_view (void)
+{
+ GtkBuilder *builder;
+ gchar *buffer =
+ "<interface>"
+ " <object class=\"GtkListStore\" id=\"liststore1\">"
+ " <columns>"
+ " <column type=\"gchararray\"/>"
+ " </columns>"
+ " <data>"
+ " <row>"
+ " <col id=\"0\">test</col>"
+ " </row>"
+ " </data>"
+ " </object>"
+ " <object class=\"GtkWindow\" id=\"window1\">"
+ " <child>"
+ " <object class=\"GtkCellView\" id=\"cellview1\">"
+ " <property name=\"visible\">True</property>"
+ " <property name=\"model\">liststore1</property>"
+ " <child>"
+ " <object class=\"GtkCellRendererText\" id=\"renderer1\"/>"
+ " <attributes>"
+ " <attribute name=\"text\">0</attribute>"
+ " </attributes>"
+ " </child>"
+ " </object>"
+ " </child>"
+ " </object>"
+ "</interface>";
+ GObject *cellview;
+ GObject *model;
+ GtkTreePath *path;
+ GList *renderers;
+ GObject *renderer;
+ gchar *text;
+
+ builder = builder_new_from_string (buffer, -1, NULL);
+ g_assert (builder);
+ cellview = gtk_builder_get_object (builder, "cellview1");
+ g_assert (cellview);
+ g_return_val_if_fail (GTK_IS_CELL_VIEW (cellview), FALSE);
+ g_object_get (cellview, "model", &model, NULL);
+ g_assert (model);
+ g_return_val_if_fail (GTK_IS_TREE_MODEL (model), FALSE);
+ path = gtk_tree_path_new_first ();
+ gtk_cell_view_set_displayed_row (GTK_CELL_VIEW (cellview), path);
+
+ renderers = gtk_cell_view_get_cell_renderers (GTK_CELL_VIEW (cellview));
+ g_assert (renderers);
+ g_return_val_if_fail (g_list_length (renderers) == 1, FALSE);
+
+ gtk_widget_realize (GTK_WIDGET (cellview));
+
+ renderer = g_list_nth_data (renderers, 0);
+ g_list_free (renderers);
+ g_assert (renderer);
+ g_object_get (renderer, "text", &text, NULL);
+ g_return_val_if_fail (strcmp (text, "test") == 0, FALSE);
+ g_free (text);
+ gtk_tree_path_free (path);
+ g_object_unref (builder);
+ return TRUE;
+}
+
+gboolean test_dialog (void)
+{
+ GtkBuilder * builder;
+ const gchar buffer1[] =
+ "<interface>"
+ " <object class=\"GtkDialog\" id=\"dialog1\">"
+ " <child internal-child=\"vbox\">"
+ " <object class=\"GtkVBox\" id=\"dialog1-vbox\">"
+ " <child internal-child=\"action_area\">"
+ " <object class=\"GtkHButtonBox\" id=\"dialog1-action_area\">"
+ " <child>"
+ " <object class=\"GtkButton\" id=\"button_cancel\"/>"
+ " </child>"
+ " <child>"
+ " <object class=\"GtkButton\" id=\"button_ok\"/>"
+ " </child>"
+ " </object>"
+ " </child>"
+ " </object>"
+ " </child>"
+ " <action-widgets>"
+ " <action-widget response=\"3\">button_ok</action-widget>"
+ " <action-widget response=\"-5\">button_cancel</action-widget>"
+ " </action-widgets>"
+ " </object>"
+ "</interface>";
+
+ GObject *dialog1;
+ GObject *button_ok;
+ GObject *button_cancel;
+
+ builder = builder_new_from_string (buffer1, -1, NULL);
+ dialog1 = gtk_builder_get_object (builder, "dialog1");
+ button_ok = gtk_builder_get_object (builder, "button_ok");
+ g_return_val_if_fail (gtk_dialog_get_response_for_widget
+ (GTK_DIALOG (dialog1),
+ GTK_WIDGET (button_ok)) == 3, FALSE);
+ button_cancel = gtk_builder_get_object (builder, "button_cancel");
+ g_return_val_if_fail (gtk_dialog_get_response_for_widget
+ (GTK_DIALOG (dialog1),
+ GTK_WIDGET (button_cancel)) == -5, FALSE);
+
+ g_object_unref (builder);
+
+ return TRUE;
+}
+
+gboolean test_accelerators (void)
+{
+ GtkBuilder *builder;
+ gchar *buffer =
+ "<interface>"
+ " <object class=\"GtkWindow\" id=\"window1\">"
+ " <child>"
+ " <object class=\"GtkButton\" id=\"button1\">"
+ " <accelerator key=\"q\" modifiers=\"GDK_CONTROL_MASK\" signal=\"clicked\"/>"
+ " </object>"
+ " </child>"
+ " </object>"
+ "</interface>";
+ gchar *buffer2 =
+ "<interface>"
+ " <object class=\"GtkWindow\" id=\"window1\">"
+ " <child>"
+ " <object class=\"GtkTreeView\" id=\"treeview1\">"
+ " <signal name=\"cursor-changed\" handler=\"gtk_main_quit\"/>"
+ " <accelerator key=\"f\" modifiers=\"GDK_CONTROL_MASK\" signal=\"grab_focus\"/>"
+ " </object>"
+ " </child>"
+ " </object>"
+ "</interface>";
+ GObject *window1;
+ GSList *accel_groups;
+ GObject *accel_group;
+
+ builder = builder_new_from_string (buffer, -1, NULL);
+ window1 = gtk_builder_get_object (builder, "window1");
+ g_assert (window1);
+ g_assert (GTK_IS_WINDOW (window1));
+
+ accel_groups = gtk_accel_groups_from_object (window1);
+ g_return_val_if_fail (g_slist_length (accel_groups) == 1, FALSE);
+ accel_group = g_slist_nth_data (accel_groups, 0);
+ g_assert (accel_group);
+
+ g_object_unref (builder);
+
+ builder = builder_new_from_string (buffer2, -1, NULL);
+ window1 = gtk_builder_get_object (builder, "window1");
+ g_assert (window1);
+ g_assert (GTK_IS_WINDOW (window1));
+
+ accel_groups = gtk_accel_groups_from_object (window1);
+ g_return_val_if_fail (g_slist_length (accel_groups) == 1, FALSE);
+ accel_group = g_slist_nth_data (accel_groups, 0);
+ g_assert (accel_group);
+
+ g_object_unref (builder);
+ return TRUE;
+}
+
+gboolean test_widget (void)
+{
+ gchar *buffer =
+ "<interface>"
+ " <object class=\"GtkWindow\" id=\"window1\">"
+ " <child>"
+ " <object class=\"GtkButton\" id=\"button1\">"
+ " <property name=\"can-focus\">True</property>"
+ " <property name=\"has-focus\">True</property>"
+ " </object>"
+ " </child>"
+ " </object>"
+ "</interface>";
+ gchar *buffer2 =
+ "<interface>"
+ " <object class=\"GtkWindow\" id=\"window1\">"
+ " <child>"
+ " <object class=\"GtkButton\" id=\"button1\">"
+ " <property name=\"can-default\">True</property>"
+ " <property name=\"has-default\">True</property>"
+ " </object>"
+ " </child>"
+ " </object>"
+ "</interface>";
+ GtkBuilder *builder;
+ GObject *button1;
+
+ builder = builder_new_from_string (buffer, -1, NULL);
+ button1 = gtk_builder_get_object (builder, "button1");
+
+#if 0
+ g_return_val_if_fail (GTK_WIDGET_HAS_FOCUS (GTK_WIDGET (button1)), FALSE);
+#endif
+ g_object_unref (builder);
+
+ builder = builder_new_from_string (buffer2, -1, NULL);
+ button1 = gtk_builder_get_object (builder, "button1");
+
+ g_return_val_if_fail (GTK_WIDGET_RECEIVES_DEFAULT (GTK_WIDGET (button1)), FALSE);
+
+ g_object_unref (builder);
+ return TRUE;
+}
+
+int
+main (int argc, char **argv)
+{
+ gtk_init (&argc, &argv);
+
+ g_print ("Testing parser\n");
+ if (!test_parser ())
+ g_error ("test_parser failed");
+
+ g_print ("Testing types\n");
+ if (!test_types ())
+ g_error ("test_types failed");
+
+ g_print ("Testing construct-only property\n");
+ if (!test_construct_only_property ())
+ g_error ("test_construct_only_property failed");
+
+ g_print ("Testing children\n");
+ if (!test_children ())
+ g_error ("test_children failed");
+
+ g_print ("Testing child properties\n");
+ if (!test_child_properties ())
+ g_error ("test_child_properties failed");
+
+ g_print ("Testing notebook\n");
+ if (!test_notebook ())
+ g_error ("test_notebook failed");
+
+ g_print ("Testing domain\n");
+ if (!test_domain ())
+ g_error ("test_domain failed");
+
+ g_print ("Testing signal autoconnect\n");
+ if (!test_connect_signals ())
+ g_error ("test_connect_signals failed");
+
+ g_print ("Testing uimanager simple\n");
+ if (!test_uimanager_simple ())
+ g_error ("test_uimanager_simple failed");
+
+ g_print ("Testing spin button\n");
+ if (!test_spin_button ())
+ g_error ("test_spin_button failed");
+
+ g_print ("Testing sizegroup\n");
+ if (!test_sizegroup ())
+ g_error ("test_sizegroup failed");
+
+ g_print ("Testing list store\n");
+ if (!test_list_store ())
+ g_error ("test_list_store failed");
+
+ g_print ("Testing tree store\n");
+ if (!test_tree_store ())
+ g_error ("test_tree_store failed");
+
+ g_print ("Testing treeview column\n");
+ if (!test_treeview_column ())
+ g_error ("test_treeview_column failed");
+
+ g_print ("Testing iconview\n");
+ if (!test_icon_view ())
+ g_error ("test_icon_view failed");
+
+ g_print ("Testing combobox\n");
+ if (!test_combo_box ())
+ g_error ("test_combo_box failed");
+
+ g_print ("Testing combobox entry\n");
+ if (!test_combo_box_entry ())
+ g_error ("test_combo_box_entry failed");
+
+ g_print ("Testing cell view\n");
+ if (!test_cell_view ())
+ g_error ("test_cell_view failed");
+
+ g_print ("Testing dialog\n");
+ if (!test_dialog ())
+ g_error ("test_dialog failed");
+
+ g_print ("Testing accelerators\n");
+ if (!test_accelerators ())
+ g_error ("test_accelerators failed");
+
+ g_print ("Testing widget\n");
+ if (!test_widget ())
+ g_error ("test_widget failed");
+
+ return 0;
+}