Merge branch 'wip/otte/builder' into 'master'

Reorganize various GtkBuilder things

See merge request GNOME/gtk!1204
This commit is contained in:
Benjamin Otte 2019-11-23 17:09:15 +00:00
commit e3c3cbbbcb
26 changed files with 448 additions and 391 deletions

View File

@ -59,7 +59,6 @@ do_builder (GtkWidget *do_widget)
builder = gtk_builder_new_from_resource ("/builder/demo.ui"); builder = gtk_builder_new_from_resource ("/builder/demo.ui");
gtk_builder_connect_signals (builder, NULL);
window = GTK_WIDGET (gtk_builder_get_object (builder, "window1")); window = GTK_WIDGET (gtk_builder_get_object (builder, "window1"));
gtk_window_set_display (GTK_WINDOW (window), gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget)); gtk_widget_get_display (do_widget));

View File

@ -24,7 +24,6 @@ do_cursors (GtkWidget *do_widget)
GtkBuilder *builder; GtkBuilder *builder;
builder = gtk_builder_new_from_resource ("/cursors/cursors.ui"); builder = gtk_builder_new_from_resource ("/cursors/cursors.ui");
gtk_builder_connect_signals (builder, NULL);
window = GTK_WIDGET (gtk_builder_get_object (builder, "window")); window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));
gtk_window_set_display (GTK_WINDOW (window), gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget)); gtk_widget_get_display (do_widget));

View File

@ -122,7 +122,6 @@ do_filtermodel (GtkWidget *do_widget)
GtkBuilder *builder; GtkBuilder *builder;
builder = gtk_builder_new_from_resource ("/filtermodel/filtermodel.ui"); builder = gtk_builder_new_from_resource ("/filtermodel/filtermodel.ui");
gtk_builder_connect_signals (builder, NULL);
window = GTK_WIDGET (gtk_builder_get_object (builder, "window1")); window = GTK_WIDGET (gtk_builder_get_object (builder, "window1"));
gtk_window_set_display (GTK_WINDOW (window), gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget)); gtk_widget_get_display (do_widget));

View File

@ -287,13 +287,13 @@ do_fishbowl (GtkWidget *do_widget)
g_type_ensure (GTK_TYPE_FISHBOWL); g_type_ensure (GTK_TYPE_FISHBOWL);
builder = gtk_builder_new_from_resource ("/fishbowl/fishbowl.ui"); builder = gtk_builder_new ();
gtk_builder_add_callback_symbols (builder, gtk_builder_add_callback_symbols (builder,
"next_button_clicked_cb", G_CALLBACK (next_button_clicked_cb), "next_button_clicked_cb", G_CALLBACK (next_button_clicked_cb),
"prev_button_clicked_cb", G_CALLBACK (prev_button_clicked_cb), "prev_button_clicked_cb", G_CALLBACK (prev_button_clicked_cb),
"changes_toggled_cb", G_CALLBACK (changes_toggled_cb), "changes_toggled_cb", G_CALLBACK (changes_toggled_cb),
NULL); NULL);
gtk_builder_connect_signals (builder, NULL); gtk_builder_add_from_resource (builder, "/fishbowl/fishbowl.ui", NULL);
window = GTK_WIDGET (gtk_builder_get_object (builder, "window")); window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));
g_signal_connect (window, "destroy", g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &window); G_CALLBACK (gtk_widget_destroyed), &window);

View File

@ -1213,15 +1213,14 @@ do_font_features (GtkWidget *do_widget)
GtkWidget *feature_list; GtkWidget *feature_list;
GtkEventController *controller; GtkEventController *controller;
builder = gtk_builder_new_from_resource ("/font_features/font-features.ui"); builder = gtk_builder_new ();
gtk_builder_add_callback_symbol (builder, "update_display", update_display); gtk_builder_add_callback_symbol (builder, "update_display", update_display);
gtk_builder_add_callback_symbol (builder, "font_changed", font_changed); gtk_builder_add_callback_symbol (builder, "font_changed", font_changed);
gtk_builder_add_callback_symbol (builder, "script_changed", script_changed); gtk_builder_add_callback_symbol (builder, "script_changed", script_changed);
gtk_builder_add_callback_symbol (builder, "reset", reset_features); gtk_builder_add_callback_symbol (builder, "reset", reset_features);
gtk_builder_add_callback_symbol (builder, "stop_edit", G_CALLBACK (stop_edit)); gtk_builder_add_callback_symbol (builder, "stop_edit", G_CALLBACK (stop_edit));
gtk_builder_add_callback_symbol (builder, "toggle_edit", G_CALLBACK (toggle_edit)); gtk_builder_add_callback_symbol (builder, "toggle_edit", G_CALLBACK (toggle_edit));
gtk_builder_connect_signals (builder, NULL); gtk_builder_add_from_resource (builder, "/font_features/font-features.ui", NULL);
window = GTK_WIDGET (gtk_builder_get_object (builder, "window")); window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));
feature_list = GTK_WIDGET (gtk_builder_get_object (builder, "feature_list")); feature_list = GTK_WIDGET (gtk_builder_get_object (builder, "feature_list"));

View File

@ -248,7 +248,6 @@ do_fontrendering (GtkWidget *do_widget)
GtkBuilder *builder; GtkBuilder *builder;
builder = gtk_builder_new_from_resource ("/fontrendering/fontrendering.ui"); builder = gtk_builder_new_from_resource ("/fontrendering/fontrendering.ui");
gtk_builder_connect_signals (builder, NULL);
window = GTK_WIDGET (gtk_builder_get_object (builder, "window")); window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));
gtk_window_set_display (GTK_WINDOW (window), gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget)); gtk_widget_get_display (do_widget));

View File

@ -205,12 +205,12 @@ do_iconscroll (GtkWidget *do_widget)
{ {
GtkBuilder *builder; GtkBuilder *builder;
builder = gtk_builder_new_from_resource ("/iconscroll/iconscroll.ui"); builder = gtk_builder_new ();
gtk_builder_add_callback_symbols (builder, gtk_builder_add_callback_symbols (builder,
"next_clicked_cb", G_CALLBACK (next_clicked_cb), "next_clicked_cb", G_CALLBACK (next_clicked_cb),
"prev_clicked_cb", G_CALLBACK (prev_clicked_cb), "prev_clicked_cb", G_CALLBACK (prev_clicked_cb),
NULL); NULL);
gtk_builder_connect_signals (builder, NULL); gtk_builder_add_from_resource (builder, "/iconscroll/iconscroll.ui", NULL);
window = GTK_WIDGET (gtk_builder_get_object (builder, "window")); window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));
g_signal_connect (window, "destroy", g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &window); G_CALLBACK (gtk_widget_destroyed), &window);

View File

@ -39,9 +39,9 @@ do_modelbutton (GtkWidget *do_widget)
GtkBuilder *builder; GtkBuilder *builder;
GActionGroup *actions; GActionGroup *actions;
builder = gtk_builder_new_from_resource ("/modelbutton/modelbutton.ui"); builder = gtk_builder_new ();
gtk_builder_add_callback_symbol (builder, "tool_clicked", G_CALLBACK (tool_clicked)); gtk_builder_add_callback_symbol (builder, "tool_clicked", G_CALLBACK (tool_clicked));
gtk_builder_connect_signals (builder, NULL); gtk_builder_add_from_resource (builder, "/modelbutton/modelbutton.ui", NULL);
window = GTK_WIDGET (gtk_builder_get_object (builder, "window1")); window = GTK_WIDGET (gtk_builder_get_object (builder, "window1"));
gtk_window_set_display (GTK_WINDOW (window), gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget)); gtk_widget_get_display (do_widget));

View File

@ -69,7 +69,6 @@ do_revealer (GtkWidget *do_widget)
GtkBuilder *builder; GtkBuilder *builder;
builder = gtk_builder_new_from_resource ("/revealer/revealer.ui"); builder = gtk_builder_new_from_resource ("/revealer/revealer.ui");
gtk_builder_connect_signals (builder, NULL);
window = GTK_WIDGET (gtk_builder_get_object (builder, "window")); window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));
gtk_window_set_display (GTK_WINDOW (window), gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget)); gtk_widget_get_display (do_widget));

View File

@ -18,7 +18,6 @@ do_scale (GtkWidget *do_widget)
GtkBuilder *builder; GtkBuilder *builder;
builder = gtk_builder_new_from_resource ("/scale/scale.ui"); builder = gtk_builder_new_from_resource ("/scale/scale.ui");
gtk_builder_connect_signals (builder, NULL);
window = GTK_WIDGET (gtk_builder_get_object (builder, "window1")); window = GTK_WIDGET (gtk_builder_get_object (builder, "window1"));
gtk_window_set_display (GTK_WINDOW (window), gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget)); gtk_widget_get_display (do_widget));

View File

@ -85,7 +85,7 @@ do_shortcuts (GtkWidget *do_widget)
{ {
GtkBuilder *builder; GtkBuilder *builder;
builder = gtk_builder_new_from_resource ("/shortcuts/shortcuts.ui"); builder = gtk_builder_new ();
gtk_builder_add_callback_symbols (builder, gtk_builder_add_callback_symbols (builder,
"builder_shortcuts", G_CALLBACK (builder_shortcuts), "builder_shortcuts", G_CALLBACK (builder_shortcuts),
"gedit_shortcuts", G_CALLBACK (gedit_shortcuts), "gedit_shortcuts", G_CALLBACK (gedit_shortcuts),
@ -95,7 +95,7 @@ do_shortcuts (GtkWidget *do_widget)
"boxes_shortcuts_wizard", G_CALLBACK (boxes_shortcuts_wizard), "boxes_shortcuts_wizard", G_CALLBACK (boxes_shortcuts_wizard),
"boxes_shortcuts_display", G_CALLBACK (boxes_shortcuts_display), "boxes_shortcuts_display", G_CALLBACK (boxes_shortcuts_display),
NULL); NULL);
gtk_builder_connect_signals (builder, NULL); gtk_builder_add_from_resource (builder, "/shortcuts/shortcuts.ui", NULL);
window = GTK_WIDGET (gtk_builder_get_object (builder, "window1")); window = GTK_WIDGET (gtk_builder_get_object (builder, "window1"));
gtk_window_set_display (GTK_WINDOW (window), gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget)); gtk_widget_get_display (do_widget));

View File

@ -190,7 +190,7 @@ do_spinbutton (GtkWidget *do_widget)
GtkAdjustment *adj; GtkAdjustment *adj;
GtkWidget *label; GtkWidget *label;
builder = gtk_builder_new_from_resource ("/spinbutton/spinbutton.ui"); builder = gtk_builder_new ();
gtk_builder_add_callback_symbols (builder, gtk_builder_add_callback_symbols (builder,
"hex_spin_input", G_CALLBACK (hex_spin_input), "hex_spin_input", G_CALLBACK (hex_spin_input),
"hex_spin_output", G_CALLBACK (hex_spin_output), "hex_spin_output", G_CALLBACK (hex_spin_output),
@ -199,7 +199,7 @@ do_spinbutton (GtkWidget *do_widget)
"month_spin_input", G_CALLBACK (month_spin_input), "month_spin_input", G_CALLBACK (month_spin_input),
"month_spin_output", G_CALLBACK (month_spin_output), "month_spin_output", G_CALLBACK (month_spin_output),
NULL); NULL);
gtk_builder_connect_signals (builder, NULL); gtk_builder_add_from_resource (builder, "/spinbutton/spinbutton.ui", NULL);
window = GTK_WIDGET (gtk_builder_get_object (builder, "window")); window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));
gtk_window_set_display (GTK_WINDOW (window), gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget)); gtk_widget_get_display (do_widget));

View File

@ -18,7 +18,6 @@ do_stack (GtkWidget *do_widget)
GtkBuilder *builder; GtkBuilder *builder;
builder = gtk_builder_new_from_resource ("/stack/stack.ui"); builder = gtk_builder_new_from_resource ("/stack/stack.ui");
gtk_builder_connect_signals (builder, NULL);
window = GTK_WIDGET (gtk_builder_get_object (builder, "window1")); window = GTK_WIDGET (gtk_builder_get_object (builder, "window1"));
gtk_window_set_display (GTK_WINDOW (window), gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget)); gtk_widget_get_display (do_widget));

View File

@ -1715,7 +1715,7 @@ activate (GApplication *app)
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
g_object_unref (provider); g_object_unref (provider);
builder = gtk_builder_new_from_resource ("/org/gtk/WidgetFactory4/widget-factory.ui"); builder = gtk_builder_new ();
gtk_builder_add_callback_symbol (builder, "on_entry_icon_release", (GCallback)on_entry_icon_release); gtk_builder_add_callback_symbol (builder, "on_entry_icon_release", (GCallback)on_entry_icon_release);
gtk_builder_add_callback_symbol (builder, "on_scale_button_value_changed", (GCallback)on_scale_button_value_changed); gtk_builder_add_callback_symbol (builder, "on_scale_button_value_changed", (GCallback)on_scale_button_value_changed);
gtk_builder_add_callback_symbol (builder, "on_scale_button_query_tooltip", (GCallback)on_scale_button_query_tooltip); gtk_builder_add_callback_symbol (builder, "on_scale_button_query_tooltip", (GCallback)on_scale_button_query_tooltip);
@ -1728,8 +1728,7 @@ activate (GApplication *app)
gtk_builder_add_callback_symbol (builder, "decrease_icon_size", (GCallback)decrease_icon_size); gtk_builder_add_callback_symbol (builder, "decrease_icon_size", (GCallback)decrease_icon_size);
gtk_builder_add_callback_symbol (builder, "reset_icon_size", (GCallback)reset_icon_size); gtk_builder_add_callback_symbol (builder, "reset_icon_size", (GCallback)reset_icon_size);
gtk_builder_add_callback_symbol (builder, "osd_frame_pressed", (GCallback)osd_frame_pressed); gtk_builder_add_callback_symbol (builder, "osd_frame_pressed", (GCallback)osd_frame_pressed);
gtk_builder_add_from_resource (builder, "/org/gtk/WidgetFactory4/widget-factory.ui", NULL);
gtk_builder_connect_signals (builder, NULL);
window = (GtkWindow *)gtk_builder_get_object (builder, "window"); window = (GtkWindow *)gtk_builder_get_object (builder, "window");
gtk_application_add_window (GTK_APPLICATION (app), window); gtk_application_add_window (GTK_APPLICATION (app), window);

View File

@ -520,7 +520,7 @@ GTK_BUILDABLE_GET_IFACE
<FILE>gtkbuilder</FILE> <FILE>gtkbuilder</FILE>
<TITLE>GtkBuilder</TITLE> <TITLE>GtkBuilder</TITLE>
GtkBuilder GtkBuilder
GtkBuilderConnectFunc GtkBuilderClosureFunc
GtkBuilderError GtkBuilderError
gtk_builder_new gtk_builder_new
gtk_builder_new_from_file gtk_builder_new_from_file
@ -529,6 +529,8 @@ gtk_builder_new_from_string
gtk_builder_add_callback_symbol gtk_builder_add_callback_symbol
gtk_builder_add_callback_symbols gtk_builder_add_callback_symbols
gtk_builder_lookup_callback_symbol gtk_builder_lookup_callback_symbol
gtk_builder_create_closure
gtk_builder_create_cclosure
gtk_builder_add_from_file gtk_builder_add_from_file
gtk_builder_add_from_resource gtk_builder_add_from_resource
gtk_builder_add_from_string gtk_builder_add_from_string
@ -539,13 +541,10 @@ gtk_builder_extend_with_template
gtk_builder_get_object gtk_builder_get_object
gtk_builder_get_objects gtk_builder_get_objects
gtk_builder_expose_object gtk_builder_expose_object
gtk_builder_connect_signals
gtk_builder_connect_signals_full
gtk_builder_set_translation_domain gtk_builder_set_translation_domain
gtk_builder_get_translation_domain gtk_builder_get_translation_domain
gtk_builder_set_application
gtk_builder_get_application
gtk_builder_get_type_from_name gtk_builder_get_type_from_name
gtk_builder_set_closure_func
gtk_builder_value_from_string gtk_builder_value_from_string
gtk_builder_value_from_string_type gtk_builder_value_from_string_type
GTK_BUILDER_WARN_INVALID_CHILD_TYPE GTK_BUILDER_WARN_INVALID_CHILD_TYPE
@ -4667,7 +4666,7 @@ gtk_widget_class_bind_template_child_internal_private
gtk_widget_class_bind_template_child_full gtk_widget_class_bind_template_child_full
gtk_widget_class_bind_template_callback gtk_widget_class_bind_template_callback
gtk_widget_class_bind_template_callback_full gtk_widget_class_bind_template_callback_full
gtk_widget_class_set_connect_func gtk_widget_class_set_closure_func
<SUBSECTION> <SUBSECTION>
gtk_widget_observe_children gtk_widget_observe_children

View File

@ -137,18 +137,6 @@
* Internally builder implements this using GBinding objects. * Internally builder implements this using GBinding objects.
* For more information see g_object_bind_property() * For more information see g_object_bind_property()
* *
* Signal handlers are set up with the <signal> element. The name
* attribute specifies the name of the signal, and the handler attribute
* specifies the function to connect to the signal. By default, GTK+ tries
* to find the handler using g_module_symbol(), but this can be changed by
* passing a custom #GtkBuilderConnectFunc to
* gtk_builder_connect_signals_full(). The remaining attributes, after,
* swapped and object, have the same meaning as the corresponding
* parameters of the g_signal_connect_object() or
* g_signal_connect_data() functions. A last_modification_time
* attribute is also allowed, but it does not have a meaning to the
* builder.
*
* Sometimes it is necessary to refer to widgets which have implicitly * Sometimes it is necessary to refer to widgets which have implicitly
* been constructed by GTK+ as part of a composite widget, to set * been constructed by GTK+ as part of a composite widget, to set
* properties on them or to add further children (e.g. the @vbox of * properties on them or to add further children (e.g. the @vbox of
@ -163,6 +151,43 @@
* The possible values for the type attribute are described in the * The possible values for the type attribute are described in the
* sections describing the widget-specific portions of UI definitions. * sections describing the widget-specific portions of UI definitions.
* *
* # Signal handlers and function pointers
*
* Signal handlers are set up with the <signal> element. The name
* attribute specifies the name of the signal, and the handler attribute
* specifies the function to connect to the signal.
* The remaining attributes, after, swapped and object, have the
* same meaning as the corresponding parameters of the
* g_signal_connect_object() or g_signal_connect_data() functions. A
* last_modification_time attribute is also allowed, but it does not
* have a meaning to the builder.
*
* By default, GTK+ tries to find functions (like the handlers for
* signals) by using g_module_symbol(), but this can be changed by
* passing a custom #GtkBuilderClosureFunc to gtk_builder_set_closure_func().
* Bindings in particular will want to make use of this functionality to
* allow language-specific name mangling and namespacing.
*
* The default closure function uses symbols explicitly added to @builder
* with prior calls to gtk_builder_add_callback_symbol(). In the case that
* symbols are not explicitly added; it uses #GModules introspective
* features (by opening the module %NULL) to look at the applications symbol
* table. From here it tries to match the signal function names given in the
* interface description with symbols in the application.
*
* Note that unless gtk_builder_add_callback_symbol() is called for
* all signal callbacks which are referenced by the loaded XML, this
* functionality will require that #GModule be supported on the platform.
*
* If you rely on #GModule support to lookup callbacks in the symbol table,
* the following details should be noted:
*
* When compiling applications for Windows, you must declare signal callbacks
* with #G_MODULE_EXPORT, or they will not be put in the symbol table.
* On Linux and Unices, this is not necessary; applications should instead
* be compiled with the -Wl,--export-dynamic CFLAGS, and linked against
* gmodule-export-2.0.
*
* # A GtkBuilder UI Definition * # A GtkBuilder UI Definition
* *
* |[ * |[
@ -216,7 +241,6 @@
#include "gtkicontheme.h" #include "gtkicontheme.h"
#include "gtktestutils.h" #include "gtktestutils.h"
static void gtk_builder_finalize (GObject *object); static void gtk_builder_finalize (GObject *object);
static void gtk_builder_set_property (GObject *object, static void gtk_builder_set_property (GObject *object,
guint prop_id, guint prop_id,
@ -226,8 +250,6 @@ static void gtk_builder_get_property (GObject *object,
guint prop_id, guint prop_id,
GValue *value, GValue *value,
GParamSpec *pspec); GParamSpec *pspec);
static GType gtk_builder_real_get_type_from_name (GtkBuilder *builder,
const gchar *type_name);
enum { enum {
PROP_0, PROP_0,
@ -237,6 +259,16 @@ enum {
static GParamSpec *builder_props[LAST_PROP]; static GParamSpec *builder_props[LAST_PROP];
struct _GtkBuilder
{
GObject parent_instance;
};
struct _GtkBuilderClass
{
GObjectClass parent_class;
};
typedef struct typedef struct
{ {
gchar *domain; gchar *domain;
@ -245,10 +277,14 @@ typedef struct
GSList *delayed_properties; GSList *delayed_properties;
GSList *signals; GSList *signals;
GSList *bindings; GSList *bindings;
GModule *module;
gchar *filename; gchar *filename;
gchar *resource_prefix; gchar *resource_prefix;
GType template_type; GType template_type;
GtkApplication *application;
GtkBuilderClosureFunc closure_func;
gpointer closure_data;
GDestroyNotify closure_destroy;
} GtkBuilderPrivate; } GtkBuilderPrivate;
G_DEFINE_TYPE_WITH_PRIVATE (GtkBuilder, gtk_builder, G_TYPE_OBJECT) G_DEFINE_TYPE_WITH_PRIVATE (GtkBuilder, gtk_builder, G_TYPE_OBJECT)
@ -256,16 +292,12 @@ G_DEFINE_TYPE_WITH_PRIVATE (GtkBuilder, gtk_builder, G_TYPE_OBJECT)
static void static void
gtk_builder_class_init (GtkBuilderClass *klass) gtk_builder_class_init (GtkBuilderClass *klass)
{ {
GObjectClass *gobject_class; GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class = G_OBJECT_CLASS (klass);
gobject_class->finalize = gtk_builder_finalize; gobject_class->finalize = gtk_builder_finalize;
gobject_class->set_property = gtk_builder_set_property; gobject_class->set_property = gtk_builder_set_property;
gobject_class->get_property = gtk_builder_get_property; gobject_class->get_property = gtk_builder_get_property;
klass->get_type_from_name = gtk_builder_real_get_type_from_name;
/** /**
* GtkBuilder:translation-domain: * GtkBuilder:translation-domain:
* *
@ -304,6 +336,11 @@ gtk_builder_finalize (GObject *object)
{ {
GtkBuilderPrivate *priv = gtk_builder_get_instance_private (GTK_BUILDER (object)); GtkBuilderPrivate *priv = gtk_builder_get_instance_private (GTK_BUILDER (object));
if (priv->closure_destroy)
priv->closure_destroy (priv->closure_data);
g_clear_pointer (&priv->module, g_module_close);
g_free (priv->domain); g_free (priv->domain);
g_free (priv->filename); g_free (priv->filename);
g_free (priv->resource_prefix); g_free (priv->resource_prefix);
@ -390,16 +427,34 @@ type_name_mangle (const gchar *name)
return g_string_free (symbol_name, FALSE); return g_string_free (symbol_name, FALSE);
} }
static GType GModule *
_gtk_builder_resolve_type_lazily (const gchar *name) gtk_builder_get_module (GtkBuilder *builder)
{ {
static GModule *module = NULL; GtkBuilderPrivate *priv = gtk_builder_get_instance_private (builder);
if (priv->module == NULL)
{
if (!g_module_supported ())
return NULL;
priv->module = g_module_open (NULL, G_MODULE_BIND_LAZY);
}
return priv->module;
}
static GType
gtk_builder_resolve_type_lazily (GtkBuilder *builder,
const gchar *name)
{
GModule *module;
GTypeGetFunc func; GTypeGetFunc func;
gchar *symbol; gchar *symbol;
GType gtype = G_TYPE_INVALID; GType gtype = G_TYPE_INVALID;
module = gtk_builder_get_module (builder);
if (!module) if (!module)
module = g_module_open (NULL, 0); return G_TYPE_INVALID;
symbol = type_name_mangle (name); symbol = type_name_mangle (name);
@ -415,24 +470,6 @@ _gtk_builder_resolve_type_lazily (const gchar *name)
* GtkBuilder virtual methods * GtkBuilder virtual methods
*/ */
static GType
gtk_builder_real_get_type_from_name (GtkBuilder *builder,
const gchar *type_name)
{
GType gtype;
gtype = g_type_from_name (type_name);
if (gtype != G_TYPE_INVALID)
return gtype;
gtype = _gtk_builder_resolve_type_lazily (type_name);
if (gtype != G_TYPE_INVALID)
return gtype;
gtk_test_register_all_types ();
return g_type_from_name (type_name);
}
typedef struct typedef struct
{ {
gchar *object; gchar *object;
@ -1027,13 +1064,6 @@ gtk_builder_create_bindings (GtkBuilder *builder)
priv->bindings = NULL; priv->bindings = NULL;
} }
void
_gtk_builder_finish (GtkBuilder *builder)
{
gtk_builder_apply_delayed_properties (builder);
gtk_builder_create_bindings (builder);
}
/** /**
* gtk_builder_new: * gtk_builder_new:
* *
@ -1629,153 +1659,54 @@ gtk_builder_expose_object (GtkBuilder *builder,
g_object_ref (object)); g_object_ref (object));
} }
typedef struct {
GModule *module;
gpointer data;
} ConnectArgs;
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;
ConnectArgs *args = (ConnectArgs*) user_data;
func = gtk_builder_lookup_callback_symbol (builder, handler_name);
if (!func)
{
/* Only error out for missing GModule support if we've not
* found the symbols explicitly added with gtk_builder_add_callback_symbol()
*/
if (args->module == NULL)
g_error ("gtk_builder_connect_signals() requires working GModule");
if (!g_module_symbol (args->module, handler_name, (gpointer)&func))
{
g_warning ("Could not find signal handler '%s'. Did you compile with -rdynamic?", 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: * GtkBuilderClosureFunc:
* @builder: a #GtkBuilder * @builder: a #GtkBuilder
* @user_data: user data to pass back with all signals * @function_name: name of the function to create a closure for
* @swapped: if the closure should swap user data and instance
* @object: (nullable): object to use as user data for the closure
* @user_data: user data passed when setting the function
* @error: location for error when creating the closure fails
* *
* This method is a simpler variation of gtk_builder_connect_signals_full(). * Prototype of function used to create closures by @builder. It is meant
* It uses symbols explicitly added to @builder with prior calls to * for influencing how @function_name is resolved.
* gtk_builder_add_callback_symbol(). In the case that symbols are not
* explicitly added; it uses #GModules introspective features (by opening the module %NULL)
* to look at the applications 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 can only be called once, subsequent calls will do nothing.
* *
* Note that unless gtk_builder_add_callback_symbol() is called for * This function is most useful for bindings and can be used with
* all signal callbacks which are referenced by the loaded XML, this * gtk_builder_set_closure_func() or gtk_widget_class_set_closure_func()
* function will require that #GModule be supported on the platform. * to allow creating closures for functions defined in the binding's
* language.
* *
* If you rely on #GModule support to lookup callbacks in the symbol table, * If the given @function_name does not match a function name or when the
* the following details should be noted: * arguments cannot be supported by the bindings, bindings should return
* %NULL and set @error. Usually %GTK_BUILDER_ERROR_INVALID_FUNCTION will
* be the right error code to use.
* *
* When compiling applications for Windows, you must declare signal callbacks * Returns: (nullable): a new #GClosure or %NULL when no closure could
* with #G_MODULE_EXPORT, or they will not be put in the symbol table. * be created and @error was set.
* On Linux and Unices, this is not necessary; applications should instead
* be compiled with the -Wl,--export-dynamic CFLAGS, and linked against
* gmodule-export-2.0.
**/
void
gtk_builder_connect_signals (GtkBuilder *builder,
gpointer user_data)
{
ConnectArgs args;
g_return_if_fail (GTK_IS_BUILDER (builder));
args.data = user_data;
if (g_module_supported ())
args.module = g_module_open (NULL, G_MODULE_BIND_LAZY);
else
args.module = NULL;
gtk_builder_connect_signals_full (builder,
gtk_builder_connect_signals_default,
&args);
if (args.module)
g_module_close (args.module);
}
/**
* GtkBuilderConnectFunc:
* @builder: a #GtkBuilder
* @object: object to connect a signal to
* @signal_name: name of the signal
* @handler_name: name of the handler
* @connect_object: (nullable): a #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. Note that this function can only be called once,
* subsequent calls will do nothing.
*/ */
/** static gboolean
* gtk_builder_connect_signals_full: gtk_builder_connect_signals (GtkBuilder *builder,
* @builder: a #GtkBuilder GError **error)
* @func: (scope call): 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_connect_signals(), except that it does not
* require GModule to function correctly.
*/
void
gtk_builder_connect_signals_full (GtkBuilder *builder,
GtkBuilderConnectFunc func,
gpointer user_data)
{ {
GtkBuilderPrivate *priv = gtk_builder_get_instance_private (builder); GtkBuilderPrivate *priv = gtk_builder_get_instance_private (builder);
GSList *l; GSList *l;
GObject *object; GObject *object;
GObject *connect_object; GObject *connect_object;
GString *detailed_id = NULL; gboolean result = FALSE;
g_return_if_fail (GTK_IS_BUILDER (builder));
g_return_if_fail (func != NULL);
if (!priv->signals) if (!priv->signals)
return; return TRUE;
priv->signals = g_slist_reverse (priv->signals); priv->signals = g_slist_reverse (priv->signals);
for (l = priv->signals; l; l = l->next) for (l = priv->signals; l; l = l->next)
{ {
SignalInfo *signal = (SignalInfo*)l->data; SignalInfo *signal = (SignalInfo*)l->data;
const gchar *signal_name; GClosure *closure;
g_assert (signal != NULL); g_assert (signal != NULL);
g_assert (signal->id != 0); g_assert (signal->id != 0);
signal_name = g_signal_name (signal->id);
object = g_hash_table_lookup (priv->objects, signal->object_name); object = g_hash_table_lookup (priv->objects, signal->object_name);
g_assert (object != NULL); g_assert (object != NULL);
@ -1786,30 +1717,47 @@ gtk_builder_connect_signals_full (GtkBuilder *builder,
connect_object = g_hash_table_lookup (priv->objects, connect_object = g_hash_table_lookup (priv->objects,
signal->connect_object_name); signal->connect_object_name);
if (!connect_object) if (!connect_object)
g_warning ("Could not lookup object %s on signal %s of object %s", {
signal->connect_object_name, signal_name, g_set_error (error,
signal->object_name); GTK_BUILDER_ERROR, GTK_BUILDER_ERROR_INVALID_ID,
"Could not lookup object %s on signal %s of object %s",
signal->connect_object_name, g_signal_name (signal->id),
signal->object_name);
break;
}
} }
if (signal->detail) closure = gtk_builder_create_closure (builder,
{ signal->handler,
if (detailed_id == NULL) signal->flags & G_CONNECT_SWAPPED ? TRUE : FALSE,
detailed_id = g_string_new (""); connect_object,
error);
g_string_printf (detailed_id, "%s::%s", signal_name, if (closure == NULL)
g_quark_to_string (signal->detail)); break;
signal_name = detailed_id->str;
}
func (builder, object, signal_name, signal->handler, g_signal_connect_closure_by_id (object,
connect_object, signal->flags, user_data); signal->id,
signal->detail,
closure,
signal->flags & G_CONNECT_AFTER ? TRUE : FALSE);
} }
if (l == NULL)
result = TRUE;
g_slist_free_full (priv->signals, (GDestroyNotify)_free_signal_info); g_slist_free_full (priv->signals, (GDestroyNotify)_free_signal_info);
priv->signals = NULL; priv->signals = NULL;
if (detailed_id) return result;
g_string_free (detailed_id, TRUE); }
gboolean
_gtk_builder_finish (GtkBuilder *builder,
GError **error)
{
gtk_builder_apply_delayed_properties (builder);
gtk_builder_create_bindings (builder);
return gtk_builder_connect_signals (builder, error);
} }
/** /**
@ -2493,7 +2441,16 @@ gtk_builder_get_type_from_name (GtkBuilder *builder,
g_return_val_if_fail (GTK_IS_BUILDER (builder), G_TYPE_INVALID); g_return_val_if_fail (GTK_IS_BUILDER (builder), G_TYPE_INVALID);
g_return_val_if_fail (type_name != NULL, G_TYPE_INVALID); g_return_val_if_fail (type_name != NULL, G_TYPE_INVALID);
type = GTK_BUILDER_GET_CLASS (builder)->get_type_from_name (builder, type_name); type = g_type_from_name (type_name);
if (type == G_TYPE_INVALID)
{
type = gtk_builder_resolve_type_lazily (builder, type_name);
if (type == G_TYPE_INVALID)
{
gtk_test_register_all_types ();
type = g_type_from_name (type_name);
}
}
if (G_TYPE_IS_CLASSED (type)) if (G_TYPE_IS_CLASSED (type))
g_type_class_unref (g_type_class_ref (type)); g_type_class_unref (g_type_class_ref (type));
@ -2569,7 +2526,7 @@ _gtk_builder_get_template_type (GtkBuilder *builder)
* *
* Adds the @callback_symbol to the scope of @builder under the given @callback_name. * Adds the @callback_symbol to the scope of @builder under the given @callback_name.
* *
* Using this function overrides the behavior of gtk_builder_connect_signals() * Using this function overrides the behavior of gtk_builder_create_closure()
* for any callback symbols that are added. Using this method allows for better * for any callback symbols that are added. Using this method allows for better
* encapsulation as it does not require that callback symbols be declared in * encapsulation as it does not require that callback symbols be declared in
* the global namespace. * the global namespace.
@ -2645,7 +2602,7 @@ gtk_builder_add_callback_symbols (GtkBuilder *builder,
* *
* This function is intended for possible use in language bindings * This function is intended for possible use in language bindings
* or for any case that one might be customizing signal connections * or for any case that one might be customizing signal connections
* using gtk_builder_connect_signals_full() * using gtk_builder_set_closure_func().
* *
* Returns: (nullable): The callback symbol in @builder for @callback_name, or %NULL * Returns: (nullable): The callback symbol in @builder for @callback_name, or %NULL
*/ */
@ -2664,6 +2621,159 @@ gtk_builder_lookup_callback_symbol (GtkBuilder *builder,
return g_hash_table_lookup (priv->callbacks, callback_name); return g_hash_table_lookup (priv->callbacks, callback_name);
} }
/**
* gtk_builder_set_closure_func: (skip)
* @builder: a #GtkBuilder
* @closure_func: (allow-none) function to call when creating
* closures or %NULL to use the default
* @user_data: (nullable): user data to pass to @closure_func
* @user_destroy: destroy function for user data
*
* Sets the function to call for creating closures.
* gtk_builder_create_closure() will use this function instead
* of gtk_builder_create_cclosure().
*
* This is useful for bindings.
**/
void
gtk_builder_set_closure_func (GtkBuilder *builder,
GtkBuilderClosureFunc closure_func,
gpointer user_data,
GDestroyNotify user_destroy)
{
GtkBuilderPrivate *priv = gtk_builder_get_instance_private (builder);
g_return_if_fail (GTK_IS_BUILDER (builder));
if (priv->closure_destroy)
priv->closure_destroy (priv->closure_data);
priv->closure_func = closure_func;
priv->closure_data = user_data;
priv->closure_destroy = user_destroy;
}
static GClosure *
gtk_builder_create_closure_for_funcptr (GtkBuilder *builder,
GCallback callback,
gboolean swapped,
GObject *object)
{
GClosure *closure;
if (object)
{
if (swapped)
closure = g_cclosure_new_object_swap (callback, object);
else
closure = g_cclosure_new_object (callback, object);
}
else
{
if (swapped)
closure = g_cclosure_new_swap (callback, NULL, NULL);
else
closure = g_cclosure_new (callback, NULL, NULL);
}
return closure;
}
/**
* gtk_builder_create_closure:
* @builder: a #GtkBuilder
* @function_name: name of the function to look up
* @swapped: %TRUE to create a swapped closure
* @object: (nullable): Object to create the closure with
* @error: (allow-none): return location for an error, or %NULL
*
* Creates a closure to invoke the function called @function_name.
*
* If a closure function was set via gtk_builder_set_closure_func(),
* will be invoked.
* Otherwise, gtk_builder_create_cclosure() will be called.
*
* If no closure could be created, %NULL will be returned and @error will
* be set.
*
* Returns: (nullable): A new closure for invoking @function_name
**/
GClosure *
gtk_builder_create_closure (GtkBuilder *builder,
const char *function_name,
gboolean swapped,
GObject *object,
GError **error)
{
GtkBuilderPrivate *priv = gtk_builder_get_instance_private (builder);
g_return_val_if_fail (GTK_IS_BUILDER (builder), NULL);
g_return_val_if_fail (function_name, NULL);
g_return_val_if_fail (object == NULL || G_IS_OBJECT (object), NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
if (priv->closure_func)
return priv->closure_func (builder, function_name, swapped, object, priv->closure_data, error);
else
return gtk_builder_create_cclosure (builder, function_name, swapped, object, error);
}
/**
* gtk_builder_create_cclosure: (skip)
* @builder: a #GtkBuilder
* @function_name: name of the function to look up
* @swapped: %TRUE to create a swapped closure
* @object: (nullable): Object to create the closure with
* @error: (allow-none): return location for an error, or %NULL
*
* This is the default function used by gtk_builder_set_closure_func(). Some bindings
* with C support may want to call this function as a fallback from their closure
* function.
*
* This function has no purpose otherwise.
*
* This function will prefer callbacks added via gtk_builder_add_callback_symbol()
* to looking up public symbols.
*
* Returns: (nullable): A new closure for invoking @function_name
**/
GClosure *
gtk_builder_create_cclosure (GtkBuilder *builder,
const char *function_name,
gboolean swapped,
GObject *object,
GError **error)
{
GModule *module = gtk_builder_get_module (builder);
GCallback func;
func = gtk_builder_lookup_callback_symbol (builder, function_name);
if (func)
return gtk_builder_create_closure_for_funcptr (builder, func, swapped, object);
if (module == NULL)
{
g_set_error (error,
GTK_BUILDER_ERROR,
GTK_BUILDER_ERROR_INVALID_FUNCTION,
"Could not look up function `%s`: GModule is not supported.",
function_name);
return NULL;
}
if (!g_module_symbol (module, function_name, (gpointer)&func))
{
g_set_error (error,
GTK_BUILDER_ERROR,
GTK_BUILDER_ERROR_INVALID_FUNCTION,
"No function named `%s`.",
function_name);
return NULL;
}
return gtk_builder_create_closure_for_funcptr (builder, func, swapped, object);
}
/** /**
* gtk_builder_new_from_file: * gtk_builder_new_from_file:
* @filename: filename of user interface description file * @filename: filename of user interface description file
@ -2746,66 +2856,6 @@ gtk_builder_new_from_string (const gchar *string,
return builder; return builder;
} }
/**
* gtk_builder_set_application:
* @builder: a #GtkBuilder
* @application: a #GtkApplication
*
* Sets the application associated with @builder.
*
* You only need this function if there is more than one #GApplication
* in your process. @application cannot be %NULL.
**/
void
gtk_builder_set_application (GtkBuilder *builder,
GtkApplication *application)
{
GtkBuilderPrivate *priv = gtk_builder_get_instance_private (builder);
g_return_if_fail (GTK_IS_BUILDER (builder));
g_return_if_fail (GTK_IS_APPLICATION (application));
if (priv->application)
g_object_unref (priv->application);
priv->application = g_object_ref (application);
}
/**
* gtk_builder_get_application:
* @builder: a #GtkBuilder
*
* Gets the #GtkApplication associated with the builder.
*
* The #GtkApplication is used for creating action proxies as requested
* from XML that the builder is loading.
*
* By default, the builder uses the default application: the one from
* g_application_get_default(). If you want to use another application
* for constructing proxies, use gtk_builder_set_application().
*
* Returns: (nullable) (transfer none): the application being used by the builder,
* or %NULL
**/
GtkApplication *
gtk_builder_get_application (GtkBuilder *builder)
{
GtkBuilderPrivate *priv = gtk_builder_get_instance_private (builder);
g_return_val_if_fail (GTK_IS_BUILDER (builder), NULL);
if (!priv->application)
{
GApplication *application;
application = g_application_get_default ();
if (application && GTK_IS_APPLICATION (application))
priv->application = g_object_ref (GTK_APPLICATION (application));
}
return priv->application;
}
/*< private > /*< private >
* _gtk_builder_prefix_error: * _gtk_builder_prefix_error:
* @builder: a #GtkBuilder * @builder: a #GtkBuilder

View File

@ -63,7 +63,10 @@ typedef struct _GtkBuilderClass GtkBuilderClass;
* @GTK_BUILDER_ERROR_TEMPLATE_MISMATCH: The wrong type was specified in a composite classs template XML * @GTK_BUILDER_ERROR_TEMPLATE_MISMATCH: The wrong type was specified in a composite classs template XML
* @GTK_BUILDER_ERROR_INVALID_PROPERTY: The specified property is unknown for the object class. * @GTK_BUILDER_ERROR_INVALID_PROPERTY: The specified property is unknown for the object class.
* @GTK_BUILDER_ERROR_INVALID_SIGNAL: The specified signal is unknown for the object class. * @GTK_BUILDER_ERROR_INVALID_SIGNAL: The specified signal is unknown for the object class.
* @GTK_BUILDER_ERROR_INVALID_ID: An object id is unknown * @GTK_BUILDER_ERROR_INVALID_ID: An object id is unknown.
* @GTK_BUILDER_ERROR_INVALID_FUNCTION: A function could not be found. This often happens
* when symbols are set to be kept private. Compiling code with -rdynamic or using the
* `gmodule-export-2.0` pkgconfig module can fix this problem.
* *
* Error codes that identify various errors that can occur while using * Error codes that identify various errors that can occur while using
* #GtkBuilder. * #GtkBuilder.
@ -83,34 +86,23 @@ typedef enum
GTK_BUILDER_ERROR_TEMPLATE_MISMATCH, GTK_BUILDER_ERROR_TEMPLATE_MISMATCH,
GTK_BUILDER_ERROR_INVALID_PROPERTY, GTK_BUILDER_ERROR_INVALID_PROPERTY,
GTK_BUILDER_ERROR_INVALID_SIGNAL, GTK_BUILDER_ERROR_INVALID_SIGNAL,
GTK_BUILDER_ERROR_INVALID_ID GTK_BUILDER_ERROR_INVALID_ID,
GTK_BUILDER_ERROR_INVALID_FUNCTION
} GtkBuilderError; } GtkBuilderError;
GDK_AVAILABLE_IN_ALL GDK_AVAILABLE_IN_ALL
GQuark gtk_builder_error_quark (void); GQuark gtk_builder_error_quark (void);
struct _GtkBuilder
{
GObject parent_instance;
};
struct _GtkBuilderClass
{
GObjectClass parent_class;
GType (* get_type_from_name) (GtkBuilder *builder,
const char *type_name);
/*< private >*/
gpointer padding[8];
};
GDK_AVAILABLE_IN_ALL GDK_AVAILABLE_IN_ALL
GType gtk_builder_get_type (void) G_GNUC_CONST; GType gtk_builder_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_ALL GDK_AVAILABLE_IN_ALL
GtkBuilder* gtk_builder_new (void); GtkBuilder* gtk_builder_new (void);
GDK_AVAILABLE_IN_ALL
void gtk_builder_set_closure_func (GtkBuilder *builder,
GtkBuilderClosureFunc closure_func,
gpointer user_data,
GDestroyNotify user_destroy);
GDK_AVAILABLE_IN_ALL GDK_AVAILABLE_IN_ALL
gboolean gtk_builder_add_from_file (GtkBuilder *builder, gboolean gtk_builder_add_from_file (GtkBuilder *builder,
const gchar *filename, const gchar *filename,
@ -150,13 +142,6 @@ void gtk_builder_expose_object (GtkBuilder *builder,
const gchar *name, const gchar *name,
GObject *object); GObject *object);
GDK_AVAILABLE_IN_ALL GDK_AVAILABLE_IN_ALL
void gtk_builder_connect_signals (GtkBuilder *builder,
gpointer user_data);
GDK_AVAILABLE_IN_ALL
void gtk_builder_connect_signals_full (GtkBuilder *builder,
GtkBuilderConnectFunc func,
gpointer user_data);
GDK_AVAILABLE_IN_ALL
void gtk_builder_set_translation_domain (GtkBuilder *builder, void gtk_builder_set_translation_domain (GtkBuilder *builder,
const gchar *domain); const gchar *domain);
GDK_AVAILABLE_IN_ALL GDK_AVAILABLE_IN_ALL
@ -197,13 +182,19 @@ void gtk_builder_add_callback_symbols (GtkBuilder *builder,
GDK_AVAILABLE_IN_ALL GDK_AVAILABLE_IN_ALL
GCallback gtk_builder_lookup_callback_symbol (GtkBuilder *builder, GCallback gtk_builder_lookup_callback_symbol (GtkBuilder *builder,
const gchar *callback_name); const gchar *callback_name);
GDK_AVAILABLE_IN_ALL GDK_AVAILABLE_IN_ALL
void gtk_builder_set_application (GtkBuilder *builder, GClosure * gtk_builder_create_closure (GtkBuilder *builder,
GtkApplication *application); const char *function_name,
gboolean swapped,
GObject *object,
GError **error);
GDK_AVAILABLE_IN_ALL GDK_AVAILABLE_IN_ALL
GtkApplication * gtk_builder_get_application (GtkBuilder *builder); GClosure * gtk_builder_create_cclosure (GtkBuilder *builder,
const char *function_name,
gboolean swapped,
GObject *object,
GError **error);
/** /**

View File

@ -1594,7 +1594,9 @@ _gtk_builder_parser_parse_buffer (GtkBuilder *builder,
if (!gtk_buildable_parse_context_parse (&data.ctx, buffer, length, error)) if (!gtk_buildable_parse_context_parse (&data.ctx, buffer, length, error))
goto out; goto out;
_gtk_builder_finish (builder); if (!_gtk_builder_finish (builder, error))
goto out;
if (_gtk_builder_lookup_failed (builder, error)) if (_gtk_builder_lookup_failed (builder, error))
goto out; goto out;

View File

@ -175,7 +175,8 @@ void _gtk_builder_add (GtkBuilder *builder,
ChildInfo *child_info); ChildInfo *child_info);
void _gtk_builder_add_signals (GtkBuilder *builder, void _gtk_builder_add_signals (GtkBuilder *builder,
GSList *signals); GSList *signals);
void _gtk_builder_finish (GtkBuilder *builder); gboolean _gtk_builder_finish (GtkBuilder *builder,
GError **error);
void _free_signal_info (SignalInfo *info, void _free_signal_info (SignalInfo *info,
gpointer user_data); gpointer user_data);
@ -227,6 +228,7 @@ GObject *_gtk_builder_lookup_object (GtkBuilder *builder,
gint col); gint col);
gboolean _gtk_builder_lookup_failed (GtkBuilder *builder, gboolean _gtk_builder_lookup_failed (GtkBuilder *builder,
GError **error); GError **error);
GModule *gtk_builder_get_module (GtkBuilder *builder);

View File

@ -51,14 +51,12 @@ typedef struct _GtkWidget GtkWidget;
typedef struct _GtkWidgetPath GtkWidgetPath; typedef struct _GtkWidgetPath GtkWidgetPath;
typedef struct _GtkWindow GtkWindow; typedef struct _GtkWindow GtkWindow;
typedef GClosure* (* GtkBuilderClosureFunc) (GtkBuilder *builder,
typedef void (*GtkBuilderConnectFunc) (GtkBuilder *builder, const char *function_name,
GObject *object, gboolean swapped,
const gchar *signal_name, GObject *object,
const gchar *handler_name, gpointer user_data,
GObject *connect_object, GError **error);
GConnectFlags flags,
gpointer user_data);
G_END_DECLS G_END_DECLS

View File

@ -490,9 +490,9 @@ typedef struct {
GBytes *data; GBytes *data;
GSList *children; GSList *children;
GSList *callbacks; GSList *callbacks;
GtkBuilderConnectFunc connect_func; GtkBuilderClosureFunc closure_func;
gpointer connect_data; gpointer closure_data;
GDestroyNotify destroy_notify; GDestroyNotify closure_destroy;
} GtkWidgetTemplate; } GtkWidgetTemplate;
struct _GtkWidgetClassPrivate struct _GtkWidgetClassPrivate
@ -12027,9 +12027,9 @@ template_data_free (GtkWidgetTemplate *template_data)
g_slist_free_full (template_data->children, (GDestroyNotify)template_child_class_free); g_slist_free_full (template_data->children, (GDestroyNotify)template_child_class_free);
g_slist_free_full (template_data->callbacks, (GDestroyNotify)callback_symbol_free); g_slist_free_full (template_data->callbacks, (GDestroyNotify)callback_symbol_free);
if (template_data->connect_data && if (template_data->closure_data &&
template_data->destroy_notify) template_data->closure_destroy)
template_data->destroy_notify (template_data->connect_data); template_data->closure_destroy (template_data->closure_data);
g_slice_free (GtkWidgetTemplate, template_data); g_slice_free (GtkWidgetTemplate, template_data);
} }
@ -12113,6 +12113,24 @@ setup_template_child (GtkWidgetTemplate *template_data,
return TRUE; return TRUE;
} }
static GClosure *
gtk_widget_template_closure_func (GtkBuilder *builder,
const char *function_name,
gboolean swapped,
GObject *object,
gpointer user_data,
GError **error)
{
if (object == NULL)
object = user_data;
return gtk_builder_create_cclosure (builder,
function_name,
swapped,
object,
error);
}
/** /**
* gtk_widget_init_template: * gtk_widget_init_template:
* @widget: a #GtkWidget * @widget: a #GtkWidget
@ -12154,6 +12172,17 @@ gtk_widget_init_template (GtkWidget *widget)
builder = gtk_builder_new (); builder = gtk_builder_new ();
/* Setup closure handling. All signal data from a template receive the
* template instance as user data automatically.
*
* A GtkBuilderClosureFunc can be provided to gtk_widget_class_set_signal_closure_func()
* in order for templates to be usable by bindings.
*/
if (template->closure_func)
gtk_builder_set_closure_func (builder, template->closure_func, template->closure_data, NULL);
else
gtk_builder_set_closure_func (builder, gtk_widget_template_closure_func, widget, NULL);
/* Add any callback symbols declared for this GType to the GtkBuilder namespace */ /* Add any callback symbols declared for this GType to the GtkBuilder namespace */
for (l = template->callbacks; l; l = l->next) for (l = template->callbacks; l; l = l->next)
{ {
@ -12203,17 +12232,6 @@ gtk_widget_init_template (GtkWidget *widget)
} }
} }
/* Connect signals. All signal data from a template receive the
* template instance as user data automatically.
*
* A GtkBuilderConnectFunc can be provided to gtk_widget_class_set_signal_connect_func()
* in order for templates to be usable by bindings.
*/
if (template->connect_func)
gtk_builder_connect_signals_full (builder, template->connect_func, template->connect_data);
else
gtk_builder_connect_signals (builder, object);
g_object_unref (builder); g_object_unref (builder);
} }
@ -12332,36 +12350,36 @@ gtk_widget_class_bind_template_callback_full (GtkWidgetClass *widget_class,
} }
/** /**
* gtk_widget_class_set_connect_func: * gtk_widget_class_set_closure_func:
* @widget_class: A #GtkWidgetClass * @widget_class: A #GtkWidgetClass
* @connect_func: The #GtkBuilderConnectFunc to use when connecting signals in the class template * @closure_func: The #GtkBuilderClosureFunc to use when creating closure in the class template
* @connect_data: The data to pass to @connect_func * @closure_data: The data to pass to @closure_func
* @connect_data_destroy: The #GDestroyNotify to free @connect_data, this will only be used at * @closure_data_destroy: The #GDestroyNotify to free @closure_data, this will only be used at
* class finalization time, when no classes of type @widget_type are in use anymore. * class finalization time, when no classes of type @widget_type are in use anymore.
* *
* For use in language bindings, this will override the default #GtkBuilderConnectFunc to be * For use in language bindings, this will override the default #GtkBuilderClosureFunc to be
* used when parsing GtkBuilder XML from this classs template data. * used when parsing GtkBuilder XML from this classs template data.
* *
* Note that this must be called from a composite widget classes class * Note that this must be called from a composite widget classes class
* initializer after calling gtk_widget_class_set_template(). * initializer after calling gtk_widget_class_set_template().
*/ */
void void
gtk_widget_class_set_connect_func (GtkWidgetClass *widget_class, gtk_widget_class_set_closure_func (GtkWidgetClass *widget_class,
GtkBuilderConnectFunc connect_func, GtkBuilderClosureFunc closure_func,
gpointer connect_data, gpointer closure_data,
GDestroyNotify connect_data_destroy) GDestroyNotify closure_data_destroy)
{ {
g_return_if_fail (GTK_IS_WIDGET_CLASS (widget_class)); g_return_if_fail (GTK_IS_WIDGET_CLASS (widget_class));
g_return_if_fail (widget_class->priv->template != NULL); g_return_if_fail (widget_class->priv->template != NULL);
/* Defensive, destroy any previously set data */ /* Defensive, destroy any previously set data */
if (widget_class->priv->template->connect_data && if (widget_class->priv->template->closure_data &&
widget_class->priv->template->destroy_notify) widget_class->priv->template->closure_destroy)
widget_class->priv->template->destroy_notify (widget_class->priv->template->connect_data); widget_class->priv->template->closure_destroy (widget_class->priv->template->closure_data);
widget_class->priv->template->connect_func = connect_func; widget_class->priv->template->closure_func = closure_func;
widget_class->priv->template->connect_data = connect_data; widget_class->priv->template->closure_data = closure_data;
widget_class->priv->template->destroy_notify = connect_data_destroy; widget_class->priv->template->closure_destroy = closure_data_destroy;
} }
/** /**

View File

@ -956,10 +956,10 @@ void gtk_widget_class_bind_template_callback_full (GtkWidgetClass *
const gchar *callback_name, const gchar *callback_name,
GCallback callback_symbol); GCallback callback_symbol);
GDK_AVAILABLE_IN_ALL GDK_AVAILABLE_IN_ALL
void gtk_widget_class_set_connect_func (GtkWidgetClass *widget_class, void gtk_widget_class_set_closure_func (GtkWidgetClass *widget_class,
GtkBuilderConnectFunc connect_func, GtkBuilderClosureFunc closure_func,
gpointer connect_data, gpointer closure_data,
GDestroyNotify connect_data_destroy); GDestroyNotify closure_destroy);
GDK_AVAILABLE_IN_ALL GDK_AVAILABLE_IN_ALL
void gtk_widget_class_bind_template_child_full (GtkWidgetClass *widget_class, void gtk_widget_class_bind_template_child_full (GtkWidgetClass *widget_class,
const gchar *name, const gchar *name,

View File

@ -34,7 +34,6 @@ main (int argc, char *argv[])
gtk_builder_add_callback_symbol (builder, "back_to_main", G_CALLBACK (back_to_main)); gtk_builder_add_callback_symbol (builder, "back_to_main", G_CALLBACK (back_to_main));
gtk_builder_add_callback_symbol (builder, "go_to_secondary", G_CALLBACK (go_to_secondary)); gtk_builder_add_callback_symbol (builder, "go_to_secondary", G_CALLBACK (go_to_secondary));
gtk_builder_add_from_file (builder, "teststackedheaders.ui", NULL); gtk_builder_add_from_file (builder, "teststackedheaders.ui", NULL);
gtk_builder_connect_signals (builder, NULL);
win = (GtkWidget *)gtk_builder_get_object (builder, "window"); win = (GtkWidget *)gtk_builder_get_object (builder, "window");
header_stack = (GtkWidget *)gtk_builder_get_object (builder, "header_stack"); header_stack = (GtkWidget *)gtk_builder_get_object (builder, "header_stack");

View File

@ -68,7 +68,6 @@ main (int argc, char *argv[])
builder = gtk_builder_new (); builder = gtk_builder_new ();
gtk_builder_add_from_file (builder, filename, NULL); gtk_builder_add_from_file (builder, filename, NULL);
gtk_builder_connect_signals (builder, NULL);
window = GTK_WIDGET (gtk_builder_get_object (builder, "window1")); window = GTK_WIDGET (gtk_builder_get_object (builder, "window1"));
g_object_unref (G_OBJECT (builder)); g_object_unref (G_OBJECT (builder));

View File

@ -244,7 +244,6 @@ test_connect_signals (void)
"</interface>"; "</interface>";
builder = builder_new_from_string (buffer, -1, NULL); builder = builder_new_from_string (buffer, -1, NULL);
gtk_builder_connect_signals (builder, NULL);
window = gtk_builder_get_object (builder, "window1"); window = gtk_builder_get_object (builder, "window1");
gtk_window_set_title (GTK_WINDOW (window), "test"); gtk_window_set_title (GTK_WINDOW (window), "test");
@ -258,7 +257,6 @@ test_connect_signals (void)
g_object_unref (builder); g_object_unref (builder);
builder = builder_new_from_string (buffer_order, -1, NULL); builder = builder_new_from_string (buffer_order, -1, NULL);
gtk_builder_connect_signals (builder, NULL);
window = gtk_builder_get_object (builder, "window1"); window = gtk_builder_get_object (builder, "window1");
normal = 0; normal = 0;
gtk_window_set_title (GTK_WINDOW (window), "test"); gtk_window_set_title (GTK_WINDOW (window), "test");
@ -270,7 +268,6 @@ test_connect_signals (void)
strlen (buffer_extra), NULL); strlen (buffer_extra), NULL);
gtk_builder_add_from_string (builder, buffer_extra2, gtk_builder_add_from_string (builder, buffer_extra2,
strlen (buffer_extra2), NULL); strlen (buffer_extra2), NULL);
gtk_builder_connect_signals (builder, NULL);
window = gtk_builder_get_object (builder, "window2"); window = gtk_builder_get_object (builder, "window2");
gtk_window_set_title (GTK_WINDOW (window), "test"); gtk_window_set_title (GTK_WINDOW (window), "test");
g_assert (normal == 30); g_assert (normal == 30);
@ -289,7 +286,6 @@ test_connect_signals (void)
builder = builder_new_from_string (buffer_after_child, -1, NULL); builder = builder_new_from_string (buffer_after_child, -1, NULL);
window = gtk_builder_get_object (builder, "window1"); window = gtk_builder_get_object (builder, "window1");
gtk_builder_connect_signals (builder, NULL);
gtk_window_set_title (GTK_WINDOW (window), "test"); gtk_window_set_title (GTK_WINDOW (window), "test");
g_assert (normal == 1); g_assert (normal == 1);
@ -2601,7 +2597,6 @@ test_anaconda_signal (void)
"</interface>"; "</interface>";
builder = builder_new_from_string (buffer, -1, NULL); builder = builder_new_from_string (buffer, -1, NULL);
gtk_builder_connect_signals (builder, NULL);
g_object_unref (builder); g_object_unref (builder);
} }

View File

@ -145,14 +145,13 @@ snapshot_widget (GtkWidget *widget)
return surface; return surface;
} }
static void static GClosure *
connect_signals (GtkBuilder *builder, create_closure (GtkBuilder *builder,
GObject *object, const char *function_name,
const gchar *signal_name, gboolean swapped,
const gchar *handler_name, GObject *object,
GObject *connect_object, gpointer user_data,
GConnectFlags flags, GError **error)
gpointer user_data)
{ {
ReftestModule *module; ReftestModule *module;
const char *directory; const char *directory;
@ -161,7 +160,7 @@ connect_signals (GtkBuilder *builder,
char **split; char **split;
directory = user_data; directory = user_data;
split = g_strsplit (handler_name, ":", -1); split = g_strsplit (function_name, ":", -1);
switch (g_strv_length (split)) switch (g_strv_length (split))
{ {
@ -177,14 +176,20 @@ connect_signals (GtkBuilder *builder,
module = reftest_module_new_self (); module = reftest_module_new_self ();
if (module == NULL) if (module == NULL)
{ {
g_error ("glib compiled without module support."); g_set_error (error,
return; GTK_BUILDER_ERROR,
GTK_BUILDER_ERROR_INVALID_FUNCTION,
"glib compiled without module support.");
return NULL;
} }
func = reftest_module_lookup (module, split[0]); func = reftest_module_lookup (module, split[0]);
if (!func) if (!func)
{ {
g_error ("failed to lookup handler for name '%s' when connecting signals", split[0]); g_set_error (error,
return; GTK_BUILDER_ERROR,
GTK_BUILDER_ERROR_INVALID_FUNCTION,
"failed to lookup function for name '%s'", split[0]);
return NULL;
} }
} }
break; break;
@ -194,33 +199,42 @@ connect_signals (GtkBuilder *builder,
module = reftest_module_new (directory, split[0]); module = reftest_module_new (directory, split[0]);
if (module == NULL) if (module == NULL)
{ {
g_error ("Could not load module '%s' from '%s' when looking up '%s': %s", split[0], directory, handler_name, g_module_error ()); g_set_error (error,
return; GTK_BUILDER_ERROR,
GTK_BUILDER_ERROR_INVALID_FUNCTION,
"Could not load module '%s' from '%s' when looking up '%s': %s", split[0], directory, function_name, g_module_error ());
return NULL;
} }
func = reftest_module_lookup (module, split[1]); func = reftest_module_lookup (module, split[1]);
if (!func) if (!func)
{ {
g_error ("failed to lookup handler for name '%s' in module '%s'", split[1], split[0]); g_set_error (error,
return; GTK_BUILDER_ERROR,
GTK_BUILDER_ERROR_INVALID_FUNCTION,
"failed to lookup function for name '%s' in module '%s'", split[1], split[0]);
return NULL;
} }
break; break;
default: default:
g_error ("Could not connect signal handler named '%s'", handler_name); g_set_error (error,
return; GTK_BUILDER_ERROR,
GTK_BUILDER_ERROR_INVALID_FUNCTION,
"Could not find function named '%s'", function_name);
return NULL;
} }
g_strfreev (split); g_strfreev (split);
if (connect_object) if (object)
{ {
if (flags & G_CONNECT_SWAPPED) if (swapped)
closure = g_cclosure_new_object_swap (func, connect_object); closure = g_cclosure_new_object_swap (func, object);
else else
closure = g_cclosure_new_object (func, connect_object); closure = g_cclosure_new_object (func, object);
} }
else else
{ {
if (flags & G_CONNECT_SWAPPED) if (swapped)
closure = g_cclosure_new_swap (func, NULL, NULL); closure = g_cclosure_new_swap (func, NULL, NULL);
else else
closure = g_cclosure_new (func, NULL, NULL); closure = g_cclosure_new (func, NULL, NULL);
@ -229,7 +243,7 @@ connect_signals (GtkBuilder *builder,
if (module) if (module)
g_closure_add_finalize_notifier (closure, module, (GClosureNotify) reftest_module_unref); g_closure_add_finalize_notifier (closure, module, (GClosureNotify) reftest_module_unref);
g_signal_connect_closure (object, signal_name, closure, flags & G_CONNECT_AFTER ? TRUE : FALSE); return closure;
} }
cairo_surface_t * cairo_surface_t *
@ -243,12 +257,11 @@ reftest_snapshot_ui_file (const char *ui_file)
directory = g_path_get_dirname (ui_file); directory = g_path_get_dirname (ui_file);
builder = gtk_builder_new (); builder = gtk_builder_new ();
gtk_builder_set_closure_func (builder, create_closure, directory, g_free);
gtk_builder_add_from_file (builder, ui_file, &error); gtk_builder_add_from_file (builder, ui_file, &error);
g_assert_no_error (error); g_assert_no_error (error);
gtk_builder_connect_signals_full (builder, connect_signals, directory);
window = builder_get_toplevel (builder); window = builder_get_toplevel (builder);
g_object_unref (builder); g_object_unref (builder);
g_free (directory);
g_assert (window); g_assert (window);
gtk_widget_show (window); gtk_widget_show (window);