Compare commits

...

8 Commits

Author SHA1 Message Date
Tristan Van Berkom
f2e1df6066 Fixing dialog separator property to be construct-only 2010-06-11 13:34:11 -04:00
Tristan Van Berkom
a22821390a Enhanced documentation for gtk_container_class_set_template() 2010-06-07 15:31:57 -04:00
Tristan Van Berkom
fabc18d551 Fixing some new GtkBuilder documentation 2010-06-07 15:20:28 -04:00
Tristan Van Berkom
1441fc5fb0 Merge branch 'master' into composite-widget-templates 2010-06-07 14:54:08 -04:00
Tristan Van Berkom
67310786cb Made GtkDialog and GtkMessageDialog composite widgets using
gtk_container_class_set_template().
2010-06-07 14:44:17 -04:00
Tristan Van Berkom
0409e5958f Made the default minimum wrap width larger for the sake of default dialog
sizes.
2010-06-07 14:43:31 -04:00
Tristan Van Berkom
48d8d2c819 Added semantics to build composite children automatically from an assigned template.
This patch adds gtk_container_class_set_template[_file](),
gtk_container_class_set_connect_func() and the GtkParamSpecComposite
type. Setting the class template will result in GtkContainer building
the instance's children from the template at construct time, composite
properties will be assigned to their composite children by matching
the property names with the child GtkBuildable ids. The exposed connect
function is there to allow language bindings to automatically assign
methods for the interface callbacks when they assign templates to classes.
2010-06-07 14:37:34 -04:00
Tristan Van Berkom
6a8a584a95 Added gtk_builder_expose_object(), gtk_builder_add_to_parent_from_file() and
gtk_builder_add_to_parent_from_string().

Adding the needed GtkBuilder framework for composite containers. First the
expose_object() api is based on the work Marco Diego Aurélio Mesquita did
in bug 447972 with some bugs fixed and things cleared up. Next the
gtk_builder_add_to_parent_from_[file/string]() variants are used to extend
containers inline by adding themselves and letting the builder add the
children defined in a template file.
2010-06-07 14:30:28 -04:00
9 changed files with 946 additions and 141 deletions

View File

@@ -81,12 +81,14 @@
* <!ATTLIST property name #REQUIRED
* translatable #IMPLIED
* comments #IMPLIED
* context #IMPLIED >
* context #IMPLIED
* external-object #IMPLIED >
* <!ATTLIST signal name #REQUIRED
* handler #REQUIRED
* after #IMPLIED
* swapped #IMPLIED
* object #IMPLIED
* external-object #IMPLIED
* last_modification_time #IMPLIED >
* <!ATTLIST child type #IMPLIED
* internal-child #IMPLIED >
@@ -148,22 +150,27 @@
* (can be specified by their name, nick or integer value), flags (can be
* specified by their name, nick, integer value, optionally combined with "|",
* e.g. "GTK_VISIBLE|GTK_REALIZED") and colors (in a format understood by
* gdk_color_parse()). Objects can be referred to by their name. Pixbufs can be
* specified as a filename of an image file to load. In general, GtkBuilder
* allows forward references to objects &mdash; an object doesn't have to be
* constructed before it can be referred to. The exception to this rule is that
* an object has to be constructed before it can be used as the value of a
* construct-only property.
* gdk_color_parse()). Pixbufs can be specified as a filename of an image file to load.
* Objects can be referred to by their name and by default refer to objects declared
* in the local xml fragment, however external objects exposed via gtk_builder_expose_object()
* can be referred to by specifying the "external-object" attribute.
*
* In general, GtkBuilder allows forward references to objects &mdash declared
* in the local xml; an object doesn't have to be constructed before it can be referred to.
* The exception to this rule is that an object has to be constructed before
* it can be used as the value of a construct-only property.
*
* Signal handlers are set up with the &lt;signal&gt; 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
* 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.
* g_signal_connect_data() functions. Extenral objects can also be referred
* to by specifying the "external-object" attribute in the same way as described
* with the &lt;property&gt; element. 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 been
* constructed by GTK+ as part of a composite widget, to set properties on them
@@ -278,6 +285,7 @@ struct _GtkBuilderPrivate
{
gchar *domain;
GHashTable *objects;
GHashTable *external_objects;
GSList *delayed_properties;
GSList *signals;
gchar *filename;
@@ -327,6 +335,8 @@ gtk_builder_init (GtkBuilder *builder)
builder->priv->domain = NULL;
builder->priv->objects = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, g_object_unref);
builder->priv->external_objects = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, g_object_unref);
}
@@ -343,6 +353,7 @@ gtk_builder_finalize (GObject *object)
g_free (priv->filename);
g_hash_table_destroy (priv->objects);
g_hash_table_destroy (priv->external_objects);
g_slist_foreach (priv->signals, (GFunc) _free_signal_info, NULL);
g_slist_free (priv->signals);
@@ -498,10 +509,27 @@ gtk_builder_get_parameters (GtkBuilder *builder,
if (G_IS_PARAM_SPEC_OBJECT (pspec) &&
(G_PARAM_SPEC_VALUE_TYPE (pspec) != GDK_TYPE_PIXBUF))
{
if (pspec->flags & G_PARAM_CONSTRUCT_ONLY)
GObject *object;
if (prop->external)
{
object = g_hash_table_lookup (builder->priv->external_objects, prop->data);
if (!object)
{
g_warning ("Failed to get external object 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, object);
}
else if (pspec->flags & G_PARAM_CONSTRUCT_ONLY)
{
GObject *object;
object = gtk_builder_get_object (builder, prop->data);
object = gtk_builder_get_object (builder, prop->data);
if (!object)
{
g_warning ("Failed to get constuct only property "
@@ -512,7 +540,7 @@ gtk_builder_get_parameters (GtkBuilder *builder,
g_value_init (&parameter.value, G_OBJECT_TYPE (object));
g_value_set_object (&parameter.value, object);
}
else
else
{
property = g_slice_new (DelayedProperty);
property->object = g_strdup (object_name);
@@ -570,6 +598,9 @@ gtk_builder_get_internal_child (GtkBuilder *builder,
obj = gtk_buildable_get_internal_child (GTK_BUILDABLE (info->object),
builder,
childname);
if (!obj && GTK_IS_CONTAINER (info->object))
obj = (GObject *)gtk_container_get_composite_child (GTK_CONTAINER (info->object), childname);
};
if (!obj)
@@ -893,7 +924,64 @@ gtk_builder_add_from_file (GtkBuilder *builder,
g_free (builder->priv->filename);
builder->priv->filename = g_strdup (filename);
_gtk_builder_parser_parse_buffer (builder, filename,
_gtk_builder_parser_parse_buffer (builder, NULL, filename,
buffer, length,
NULL,
&tmp_error);
g_free (buffer);
if (tmp_error != NULL)
{
g_propagate_error (error, tmp_error);
return 0;
}
return 1;
}
/**
* gtk_builder_add_to_parent_from_file:
* @builder: a #GtkBuilder
* @parent: the parent object to be assumed in context while parsing the file
* @filename: the name of the file to parse
* @error: (allow-none): return location for an error, or %NULL
*
* Like gtk_builder_add_from_file() except the format will expect
* <child> instead of <object> as its first elements and expose
* @parent in the build context, children defined in the UI fragment
* will be added to @parent.
*
* Returns: A positive value on success, 0 if an error occurred
*
* Since: ...
**/
guint
gtk_builder_add_to_parent_from_file (GtkBuilder *builder,
GObject *parent,
const gchar *filename,
GError **error)
{
gchar *buffer;
gsize length;
GError *tmp_error;
g_return_val_if_fail (GTK_IS_BUILDER (builder), 0);
g_return_val_if_fail (filename != NULL, 0);
g_return_val_if_fail (error == NULL || *error == NULL, 0);
tmp_error = NULL;
if (!g_file_get_contents (filename, &buffer, &length, &tmp_error))
{
g_propagate_error (error, tmp_error);
return 0;
}
g_free (builder->priv->filename);
builder->priv->filename = g_strdup (filename);
_gtk_builder_parser_parse_buffer (builder, parent, filename,
buffer, length,
NULL,
&tmp_error);
@@ -960,7 +1048,7 @@ gtk_builder_add_objects_from_file (GtkBuilder *builder,
g_free (builder->priv->filename);
builder->priv->filename = g_strdup (filename);
_gtk_builder_parser_parse_buffer (builder, filename,
_gtk_builder_parser_parse_buffer (builder, NULL, filename,
buffer, length,
object_ids,
&tmp_error);
@@ -1010,7 +1098,56 @@ gtk_builder_add_from_string (GtkBuilder *builder,
g_free (builder->priv->filename);
builder->priv->filename = g_strdup (".");
_gtk_builder_parser_parse_buffer (builder, "<input>",
_gtk_builder_parser_parse_buffer (builder, NULL, "<input>",
buffer, length,
NULL,
&tmp_error);
if (tmp_error != NULL)
{
g_propagate_error (error, tmp_error);
return 0;
}
return 1;
}
/**
* gtk_builder_add_to_parent_from_string:
* @builder: a #GtkBuilder
* @parent: the parent object to be assumed in context while parsing
* @buffer: the string to parse
* @length: the length of @buffer (may be -1 if @buffer is nul-terminated)
* @error: (allow-none): return location for an error, or %NULL
*
* Like gtk_builder_add_from_string() except the format will expect
* <child> instead of <object> as its first elements and expose
* @parent in the build context, children defined in the UI fragment
* will be added to @parent.
*
* Returns: A positive value on success, 0 if an error occurred
*
* Since: ...
**/
guint
gtk_builder_add_to_parent_from_string (GtkBuilder *builder,
GObject *parent,
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);
g_return_val_if_fail (error == NULL || *error == NULL, 0);
tmp_error = NULL;
g_free (builder->priv->filename);
builder->priv->filename = g_strdup (".");
_gtk_builder_parser_parse_buffer (builder, parent, "<input>",
buffer, length,
NULL,
&tmp_error);
@@ -1067,7 +1204,7 @@ gtk_builder_add_objects_from_string (GtkBuilder *builder,
g_free (builder->priv->filename);
builder->priv->filename = g_strdup (".");
_gtk_builder_parser_parse_buffer (builder, "<input>",
_gtk_builder_parser_parse_buffer (builder, NULL, "<input>",
buffer, length,
object_ids,
&tmp_error);
@@ -1182,6 +1319,30 @@ gtk_builder_get_translation_domain (GtkBuilder *builder)
return builder->priv->domain;
}
/**
* gtk_builder_expose_object:
* @builder: a #GtkBuilder
* @name: the name of the object exposed to the builder
* @object: the object to expose
*
* Adds @object to a pool of objects external to the
* objects built by builder. Objects exposed in the pool
* can be referred to by xml fragments in the builder.
*/
void
gtk_builder_expose_object (GtkBuilder *builder,
const gchar *name,
GObject *object)
{
g_return_if_fail (GTK_IS_BUILDER (builder));
g_return_if_fail (name && name[0]);
g_return_if_fail (G_IS_OBJECT (object));
g_hash_table_insert (builder->priv->external_objects,
g_strdup (name), g_object_ref (object));
}
typedef struct {
GModule *module;
gpointer data;
@@ -1211,7 +1372,6 @@ gtk_builder_connect_signals_default (GtkBuilder *builder,
g_signal_connect_data (object, signal_name, func, args->data, NULL, flags);
}
/**
* gtk_builder_connect_signals:
* @builder: a #GtkBuilder
@@ -1307,7 +1467,7 @@ gtk_builder_connect_signals_full (GtkBuilder *builder,
for (l = builder->priv->signals; l; l = l->next)
{
SignalInfo *signal = (SignalInfo*)l->data;
g_assert (signal != NULL);
g_assert (signal->name != NULL);
@@ -1319,14 +1479,19 @@ gtk_builder_connect_signals_full (GtkBuilder *builder,
if (signal->connect_object_name)
{
connect_object = g_hash_table_lookup (builder->priv->objects,
signal->connect_object_name);
if (signal->external)
connect_object = g_hash_table_lookup (builder->priv->external_objects,
signal->connect_object_name);
else
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);
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);
}

View File

@@ -133,9 +133,21 @@ guint gtk_builder_add_objects_from_string (GtkBuilder *builder,
gsize length,
gchar **object_ids,
GError **error);
guint gtk_builder_add_to_parent_from_file (GtkBuilder *builder,
GObject *parent,
const gchar *filename,
GError **error);
guint gtk_builder_add_to_parent_from_string (GtkBuilder *builder,
GObject *parent,
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_expose_object (GtkBuilder *builder,
const gchar *name,
GObject *object);
void gtk_builder_connect_signals (GtkBuilder *builder,
gpointer user_data);
void gtk_builder_connect_signals_full (GtkBuilder *builder,

View File

@@ -437,6 +437,7 @@ parse_child (ParserData *data,
{
ObjectInfo* object_info;
ChildInfo *child_info;
GObject *object;
guint i;
object_info = state_peek_info (data, ObjectInfo);
@@ -445,6 +446,9 @@ parse_child (ParserData *data,
error_invalid_tag (data, element_name, NULL, error);
return;
}
GTK_NOTE (BUILDER, g_print ("parsing child of parent type %s\n",
object_info->object ? G_OBJECT_TYPE_NAME (object_info->object) : "(none)"));
child_info = g_slice_new0 (ChildInfo);
state_push (data, child_info);
@@ -461,7 +465,9 @@ parse_child (ParserData *data,
child_info->parent = (CommonInfo*)object_info;
object_info->object = builder_construct (data, object_info, error);
object = builder_construct (data, object_info, error);
object_info->object = object;
}
static void
@@ -483,6 +489,7 @@ parse_property (ParserData *data,
gchar *name = NULL;
gchar *context = NULL;
gboolean translatable = FALSE;
gboolean external = FALSE;
ObjectInfo *object_info;
int i;
@@ -511,6 +518,11 @@ parse_property (ParserData *data,
{
context = g_strdup (values[i]);
}
else if (strcmp (names[i], "external-object") == 0)
{
if (!_gtk_builder_boolean_from_string (values[i], &external, error))
return;
}
else
{
error_invalid_attribute (data, element_name, names[i], error);
@@ -525,10 +537,11 @@ parse_property (ParserData *data,
}
info = g_slice_new0 (PropertyInfo);
info->name = name;
info->name = name;
info->translatable = translatable;
info->context = context;
info->text = g_string_new ("");
info->context = context;
info->text = g_string_new ("");
info->external = external;
state_push (data, info);
info->tag.name = element_name;
@@ -556,6 +569,7 @@ parse_signal (ParserData *data,
gboolean after = FALSE;
gboolean swapped = FALSE;
gboolean swapped_set = FALSE;
gboolean external = FALSE;
ObjectInfo *object_info;
int i;
@@ -583,6 +597,11 @@ parse_signal (ParserData *data,
return;
swapped_set = TRUE;
}
else if (strcmp (names[i], "external-object") == 0)
{
if (!_gtk_builder_boolean_from_string (values[i], &external, error))
return;
}
else if (strcmp (names[i], "object") == 0)
object = g_strdup (values[i]);
else if (strcmp (names[i], "last_modification_time") == 0)
@@ -617,6 +636,7 @@ parse_signal (ParserData *data,
info->flags |= G_CONNECT_AFTER;
if (swapped)
info->flags |= G_CONNECT_SWAPPED;
info->external = external;
info->connect_object_name = object;
state_push (data, info);
@@ -1113,6 +1133,7 @@ static const GMarkupParser parser = {
void
_gtk_builder_parser_parse_buffer (GtkBuilder *builder,
GObject *parent,
const gchar *filename,
const gchar *buffer,
gsize length,
@@ -1137,6 +1158,18 @@ _gtk_builder_parser_parse_buffer (GtkBuilder *builder,
data->object_ids = g_hash_table_new_full (g_str_hash, g_str_equal,
(GDestroyNotify)g_free, NULL);
if (parent)
{
ObjectInfo *object_info = g_slice_new0 (ObjectInfo);
GTK_NOTE (BUILDER, g_print ("parsing with contextual parent info ptr %p\n", object_info));
object_info->object = parent;
object_info->id = g_strdup ("__container");
state_push (data, object_info);
object_info->tag.name = "object";
}
data->requested_objects = NULL;
if (requested_objs)
{

View File

@@ -57,8 +57,9 @@ typedef struct {
gchar *name;
GString *text;
gchar *data;
gboolean translatable;
gchar *context;
guint8 translatable : 1;
guint8 external : 1;
} PropertyInfo;
typedef struct {
@@ -66,6 +67,7 @@ typedef struct {
gchar *object_name;
gchar *name;
gchar *handler;
gboolean external;
GConnectFlags flags;
gchar *connect_object_name;
} SignalInfo;
@@ -109,6 +111,7 @@ typedef GType (*GTypeGetFunc) (void);
/* Things only GtkBuilder should use */
void _gtk_builder_parser_parse_buffer (GtkBuilder *builder,
GObject *parent,
const gchar *filename,
const gchar *buffer,
gsize length,

View File

@@ -67,6 +67,9 @@ static void gtk_container_base_class_init (GtkContainerClass *klass);
static void gtk_container_base_class_finalize (GtkContainerClass *klass);
static void gtk_container_class_init (GtkContainerClass *klass);
static void gtk_container_init (GtkContainer *container);
static GObject *gtk_container_constructor (GType type,
guint n_construct_properties,
GObjectConstructParam *construct_properties);
static void gtk_container_destroy (GtkObject *object);
static void gtk_container_set_property (GObject *object,
guint prop_id,
@@ -181,6 +184,9 @@ gtk_container_base_class_init (GtkContainerClass *class)
/* reset instance specifc class fields that don't get inherited */
class->set_child_property = NULL;
class->get_child_property = NULL;
class->tmpl = NULL;
class->tmpl_file = NULL;
class->connect_func = NULL;
}
static void
@@ -198,6 +204,9 @@ gtk_container_base_class_finalize (GtkContainerClass *class)
g_param_spec_unref (pspec);
}
g_list_free (list);
g_free (class->tmpl);
g_free (class->tmpl_file);
}
static void
@@ -212,6 +221,7 @@ gtk_container_class_init (GtkContainerClass *class)
vadjustment_key_id = g_quark_from_static_string (vadjustment_key);
hadjustment_key_id = g_quark_from_static_string (hadjustment_key);
gobject_class->constructor = gtk_container_constructor;
gobject_class->set_property = gtk_container_set_property;
gobject_class->get_property = gtk_container_get_property;
@@ -1025,6 +1035,132 @@ gtk_container_class_list_child_properties (GObjectClass *cclass,
return pspecs;
}
/**
* gtk_container_get_composite_child:
* @container: a #GtkContainer
* @composite_name: the name of a composite child as defined by installation of a #GtkParamSpecComposite property
*
* Retrieves a composite child by name by checking installed composite typed properties.
*
* Returns: the composite child of @container with the name @composite_name
*/
GtkWidget *
gtk_container_get_composite_child (GtkContainer *container,
const gchar *composite_name)
{
GParamSpec **pspecs;
guint n_pspecs = 0, i;
GtkWidget *composite_child = NULL;
g_return_val_if_fail (GTK_IS_CONTAINER (container), NULL);
g_return_val_if_fail (composite_name && composite_name[0], NULL);
pspecs = g_object_class_list_properties (G_OBJECT_GET_CLASS (container), &n_pspecs);
for (i = 0; i < n_pspecs; i++)
{
if (strcmp (pspecs[i]->name, composite_name) == 0)
{
if (GTK_IS_PARAM_SPEC_COMPOSITE (pspecs[i]) &&
(pspecs[i]->flags & G_PARAM_WRITABLE) != 0)
{
g_object_get (G_OBJECT (container),
composite_name, &composite_child,
NULL);
if (composite_child)
g_object_unref (composite_child);
else
g_warning ("Failed to get composite child named %s for type %s",
composite_name, G_OBJECT_TYPE_NAME (container));
}
break;
}
}
g_free (pspecs);
return composite_child;
}
/**
* gtk_container_class_set_template:
* @container_class: a #GtkContainerClass
* @tmpl: the #GtkBuilder xml fragment used to build children
*
* This is used when implementing new composite widget types
* to setup a UI template for instances of this type.
*
* Templates are in the <link linkend="BUILDER-UI">GtkBuilder UI description</link>
* format and are used to implement composite widget types in
* an automated way.
*
* Instances with an assigned template will have thier children
* built at object construct time.
*
* The provided xml fragment is expected to start with <child>
* instead of <object> and will be parsed with a fresh instance
* of the implementing composite widget type in context as the
* parent container. The composite instance itself will be exposed
* to the GtkBuilder as an external object named "container" and in this way can
* be referred to in child signal and property declarations.
*
* Since: 3.0
*/
void
gtk_container_class_set_template (GtkContainerClass *container_class,
const gchar *tmpl)
{
g_return_if_fail (GTK_IS_CONTAINER_CLASS(container_class));
g_return_if_fail (tmpl && tmpl[0]);
g_free (container_class->tmpl);
g_free (container_class->tmpl_file);
container_class->tmpl = g_strdup (tmpl);
container_class->tmpl_file = NULL;
}
/**
* gtk_container_class_set_template_file:
* @container_class: a #GtkContainerClass
* @tmpl_file: the #GtkBuilder xml file used to build children
*
* Sets a file to be used as this class's template; see gtk_container_class_set_template().
*
*/
void
gtk_container_class_set_template_file (GtkContainerClass *container_class,
const gchar *tmpl_file)
{
g_return_if_fail (GTK_IS_CONTAINER_CLASS(container_class));
g_return_if_fail (tmpl_file && tmpl_file[0]);
g_free (container_class->tmpl);
g_free (container_class->tmpl_file);
container_class->tmpl = NULL;
container_class->tmpl_file = g_strdup (tmpl_file);
}
/**
* gtk_container_class_set_connect_func:
* @container_class: a #GtkContainerClass
* @connect_func: the #GtkBuilderConnectFunc to use when connecting signals internally.
*
* Sets the function to be used when automatically connecting signals
* defined by this class's GtkBuilder template.
*/
void
gtk_container_class_set_connect_func (GtkContainerClass *container_class,
GtkBuilderConnectFunc connect_func)
{
g_return_if_fail (GTK_IS_CONTAINER_CLASS(container_class));
g_return_if_fail (connect_func != NULL);
container_class->connect_func = connect_func;
}
static void
gtk_container_add_unimplemented (GtkContainer *container,
GtkWidget *widget)
@@ -1068,6 +1204,94 @@ gtk_container_destroy (GtkObject *object)
GTK_OBJECT_CLASS (parent_class)->destroy (object);
}
static GObject *
gtk_container_constructor (GType type,
guint n_construct_properties,
GObjectConstructParam *construct_properties)
{
GtkBuilder *builder;
GParamSpec **pspecs;
GError *error = NULL;
guint ret = 0, n_pspecs = 0, i;
GObject *ret_obj;
GtkContainer *container;
GObjectClass *oclass;
GSList *classes = NULL, *l;
ret_obj = G_OBJECT_CLASS (parent_class)->constructor
(type, n_construct_properties, construct_properties);
container = GTK_CONTAINER (ret_obj);
/* Collect an ordered list of class which have templates to build */
for (oclass = G_OBJECT_GET_CLASS (container);
GTK_IS_CONTAINER_CLASS (oclass);
oclass = g_type_class_peek_parent (oclass))
{
if (GTK_CONTAINER_CLASS (oclass)->tmpl ||
GTK_CONTAINER_CLASS (oclass)->tmpl_file)
classes = g_slist_prepend (classes, oclass);
}
/* Build the templates for each class starting with the superclass descending */
for (l = classes; l; l = l->next)
{
GtkContainerClass *cclass = l->data;
builder = gtk_builder_new ();
gtk_builder_expose_object (builder, "container", ret_obj);
if (cclass->tmpl)
ret = gtk_builder_add_to_parent_from_string (builder, ret_obj,
cclass->tmpl, -1, &error);
else
ret = gtk_builder_add_to_parent_from_file (builder, ret_obj,
cclass->tmpl_file, &error);
if (!ret)
{
g_critical ("Unable to build GtkContainer class %s from template: %s",
G_OBJECT_TYPE_NAME (container),
error->message);
g_error_free (error);
g_object_unref (builder);
return ret_obj;
}
pspecs = g_object_class_list_properties (G_OBJECT_CLASS (cclass), &n_pspecs);
for (i = 0; i < n_pspecs; i++)
{
if (GTK_IS_PARAM_SPEC_COMPOSITE (pspecs[i]) &&
pspecs[i]->owner_type == G_OBJECT_CLASS_TYPE (cclass))
{
GObject *composite_child;
composite_child = gtk_builder_get_object (builder, (pspecs[i])->name);
if (composite_child)
/* Let GObject fire a warning if there is an object type mismatch */
g_object_set (container, (pspecs[i])->name, composite_child, NULL);
else
g_critical ("Expected internal child %s not found for container class %s",
(pspecs[i])->name, G_OBJECT_TYPE_NAME (container));
}
}
g_free (pspecs);
if (cclass->connect_func)
gtk_builder_connect_signals_full (builder, GTK_CONTAINER_GET_CLASS (container)->connect_func, container);
else
gtk_builder_connect_signals (builder, container);
g_object_unref (builder);
}
g_slist_free (classes);
return ret_obj;
}
static void
gtk_container_set_property (GObject *object,
guint prop_id,
@@ -2685,5 +2909,121 @@ gtk_container_propagate_expose (GtkContainer *container,
}
}
/* ---------- Declaration of GtkParamSpecComposite
*/
static void
param_composite_init (GParamSpec *pspec)
{
/* GtkParamSpecComposite *ospec = GTK_PARAM_SPEC_COMPOSITE (pspec); */
}
static void
param_composite_set_default (GParamSpec *pspec,
GValue *value)
{
value->data[0].v_pointer = NULL;
}
static gboolean
param_composite_validate (GParamSpec *pspec,
GValue *value)
{
GtkParamSpecComposite *ospec = GTK_PARAM_SPEC_COMPOSITE (pspec);
GObject *object = value->data[0].v_pointer;
guint changed = 0;
if (object && !g_value_type_compatible (G_OBJECT_TYPE (object), G_PARAM_SPEC_VALUE_TYPE (ospec)))
{
g_object_unref (object);
value->data[0].v_pointer = NULL;
changed++;
}
return changed;
}
static gint
param_composite_values_cmp (GParamSpec *pspec,
const GValue *value1,
const GValue *value2)
{
guint8 *p1 = value1->data[0].v_pointer;
guint8 *p2 = value2->data[0].v_pointer;
/* not much to compare here, try to at least provide stable lesser/greater result */
return p1 < p2 ? -1 : p1 > p2;
}
GType
gtk_param_composite_get_type (void)
{
static GType composite_type = 0;
if (composite_type == 0)
{
static const GParamSpecTypeInfo pspec_info = {
sizeof (GtkParamSpecComposite), /* instance_size */
0, /* n_preallocs */
param_composite_init, /* instance_init */
G_TYPE_OBJECT, /* value_type */
NULL, /* finalize */
param_composite_set_default, /* value_set_default */
param_composite_validate, /* value_validate */
param_composite_values_cmp, /* values_cmp */
};
composite_type =
g_param_type_register_static (g_intern_static_string ("GtkParamComposite"), &pspec_info);
}
return composite_type;
}
/**
* gtk_param_spec_composite:
* @name: canonical name of the property specified
* @nick: nick name for the property specified
* @blurb: description of the property specified
* @object_type: %G_TYPE_OBJECT derived type of this property
*
* Creates a new #GtkParamSpecComposite instance specifying a %G_TYPE_OBJECT
* derived property, these work exactly the same as #GParamSpecObject properties
* except that #GtkContainer will automatically assign all properties defined
* as composite object properties to instances built from the composite derived
* class's #GtkBuilder UI template.
*
* See g_param_spec_internal() for details on property names.
*
* Composite child properties must all be writable a rule but can be private
* if they are declared without the readable flag.
* Dynamic widget contents should generally not be advertized as composite children
* although at times they can be writable for the purpose of being overridden by a
* third party. Such dynamic composite children should not be refferred to by child
* UIs that extend a widget, but can be mentioned in templates which include a widget
* and override it's child.
*
* Returns: a newly created parameter specification
*/
GParamSpec*
gtk_param_spec_composite (const gchar *name,
const gchar *nick,
const gchar *blurb,
GType object_type,
GParamFlags flags)
{
GParamSpecObject *ospec;
g_return_val_if_fail (g_type_is_a (object_type, G_TYPE_OBJECT), NULL);
ospec = g_param_spec_internal (GTK_TYPE_PARAM_COMPOSITE,
name,
nick,
blurb,
flags | G_PARAM_WRITABLE);
G_PARAM_SPEC (ospec)->value_type = object_type;
return G_PARAM_SPEC (ospec);
}
#define __GTK_CONTAINER_C__
#include "gtkaliasdef.c"

View File

@@ -34,10 +34,44 @@
#include <gtk/gtkwidget.h>
#include <gtk/gtkadjustment.h>
#include <gtk/gtkbuilder.h>
G_BEGIN_DECLS
/**
* GTK_TYPE_PARAM_COMPOSITE:
*
* The #GType of #GtkParamSpecComposite.
*
* Since: 3.0
*/
#define GTK_TYPE_PARAM_COMPOSITE (gtk_param_composite_get_type())
/**
* GTK_IS_PARAM_SPEC_COMPOSITE:
* @pspec: a valid #GParamSpec instance
*
* Checks whether the given #GParamSpec is of type %GTK_TYPE_PARAM_COMPOSITE.
*
* Returns: %TRUE on success.
*
* Since: 3.0
*/
#define GTK_IS_PARAM_SPEC_COMPOSITE(pspec) \
(G_TYPE_CHECK_INSTANCE_TYPE ((pspec), GTK_TYPE_PARAM_COMPOSITE))
/**
* GTK_PARAM_SPEC_COMPOSITE:
* @pspec: a valid #GParamSpec instance
*
* Casts a #GParamSpec instance into a #GtkParamSpecComposite.
*
* Since: 3.0
*/
#define GTK_PARAM_SPEC_COMPOSITE(pspec) \
(G_TYPE_CHECK_INSTANCE_CAST ((pspec), GTK_TYPE_PARAM_COMPOSITE, GtkParamSpecComposite))
#define GTK_TYPE_CONTAINER (gtk_container_get_type ())
#define GTK_CONTAINER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_CONTAINER, GtkContainer))
#define GTK_CONTAINER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_CONTAINER, GtkContainerClass))
@@ -48,8 +82,22 @@ G_BEGIN_DECLS
#define GTK_IS_RESIZE_CONTAINER(widget) (GTK_IS_CONTAINER (widget) && ((GtkContainer*) (widget))->resize_mode != GTK_RESIZE_PARENT)
typedef struct _GtkContainer GtkContainer;
typedef struct _GtkContainerClass GtkContainerClass;
typedef struct _GtkContainer GtkContainer;
typedef struct _GtkContainerClass GtkContainerClass;
typedef struct _GtkParamSpecComposite GtkParamSpecComposite;
/**
* GtkParamSpecComposite:
* @parent_instance: private #GParamSpec portion
*
* A #GParamSpec derived structure that contains the meta data for composite child object properties.
*
* Since: 3.0
*/
struct _GtkParamSpecComposite
{
GParamSpec parent_instance;
};
struct _GtkContainer
{
@@ -95,15 +143,24 @@ struct _GtkContainerClass
GValue *value,
GParamSpec *pspec);
/* GtkBuilder templates for automated composite classes */
gchar *GSEAL (tmpl);
gchar *GSEAL (tmpl_file);
GtkBuilderConnectFunc GSEAL (connect_func);
/* Padding for future expansion */
void (*_gtk_reserved1) (void);
void (*_gtk_reserved2) (void);
void (*_gtk_reserved3) (void);
void (*_gtk_reserved4) (void);
};
/* Application-level methods */
GType gtk_param_composite_get_type (void) G_GNUC_CONST;
GParamSpec *gtk_param_spec_composite (const gchar *name,
const gchar *nick,
const gchar *blurb,
GType object_type,
GParamFlags flags);
GType gtk_container_get_type (void) G_GNUC_CONST;
void gtk_container_set_border_width (GtkContainer *container,
guint border_width);
@@ -198,6 +255,17 @@ void gtk_container_forall (GtkContainer *container,
GtkCallback callback,
gpointer callback_data);
GtkWidget *gtk_container_get_composite_child (GtkContainer *container,
const gchar *composite_name);
/* Class-level functions */
void gtk_container_class_set_template (GtkContainerClass *container_class,
const gchar *tmpl);
void gtk_container_class_set_template_file (GtkContainerClass *container_class,
const gchar *tmpl_file);
void gtk_container_class_set_connect_func (GtkContainerClass *container_class,
GtkBuilderConnectFunc connect_func);
/* Non-public methods */
void _gtk_container_queue_resize (GtkContainer *container);
void _gtk_container_clear_resize_widgets (GtkContainer *container);

View File

@@ -81,9 +81,6 @@ 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,
@@ -97,9 +94,44 @@ static void gtk_dialog_buildable_custom_finished (GtkBuildable *buildab
gpointer user_data);
static const gchar *gtk_dialog_template =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
"<interface>"
" <requires lib=\"gtk+\" version=\"2.20\"/>"
" <child>"
" <object class=\"GtkVBox\" id=\"vbox\">"
" <property name=\"visible\">True</property>"
" <child>"
" <object class=\"GtkHSeparator\" id=\"separator\">"
" <property name=\"visible\">True</property>"
" </object>"
" <packing>"
" <property name=\"expand\">False</property>"
" <property name=\"pack_type\">end</property>"
" <property name=\"position\">1</property>"
" </packing>"
" </child>"
" <child>"
" <object class=\"GtkHButtonBox\" id=\"action-area\">"
" <property name=\"visible\">True</property>"
" <property name=\"layout_style\">end</property>"
" </object>"
" <packing>"
" <property name=\"expand\">False</property>"
" <property name=\"pack_type\">end</property>"
" <property name=\"position\">0</property>"
" </packing>"
" </child>"
" </object>"
" </child>"
"</interface>";
enum {
PROP_0,
PROP_HAS_SEPARATOR
PROP_HAS_SEPARATOR,
PROP_SEPARATOR,
PROP_VBOX,
PROP_ACTION_AREA
};
enum {
@@ -147,6 +179,51 @@ gtk_dialog_class_init (GtkDialogClass *class)
TRUE,
GTK_PARAM_READWRITE));
/**
* GtkDialog:separator:
*
* The separator above the action buttons.
*
* Since: 3.0
*/
g_object_class_install_property (gobject_class,
PROP_SEPARATOR,
gtk_param_spec_composite ("separator",
P_("Separator"),
P_("The separator above the action buttons"),
GTK_TYPE_SEPARATOR,
GTK_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
/**
* GtkDialog:vbox:
*
* The dialog content area.
*
* Since: 3.0
*/
g_object_class_install_property (gobject_class,
PROP_VBOX,
gtk_param_spec_composite ("vbox",
P_("Content Area"),
P_("The dialog content area"),
GTK_TYPE_BOX,
GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
/**
* GtkDialog:action-area:
*
* The dialog action area.
*
* Since: 3.0
*/
g_object_class_install_property (gobject_class,
PROP_ACTION_AREA,
gtk_param_spec_composite ("action-area",
P_("Action Area"),
P_("The dialog action area"),
GTK_TYPE_BUTTON_BOX,
GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
/**
* GtkDialog::response:
* @dialog: the object on which the signal is emitted
@@ -233,6 +310,8 @@ gtk_dialog_class_init (GtkDialogClass *class)
binding_set = gtk_binding_set_by_class (class);
gtk_binding_entry_add_signal (binding_set, GDK_Escape, 0, "close", 0);
gtk_container_class_set_template (GTK_CONTAINER_CLASS (class), gtk_dialog_template);
}
static void
@@ -280,24 +359,6 @@ gtk_dialog_init (GtkDialog *dialog)
G_CALLBACK (gtk_dialog_delete_event_handler),
NULL);
dialog->vbox = gtk_vbox_new (FALSE, 0);
gtk_container_add (GTK_CONTAINER (dialog), dialog->vbox);
gtk_widget_show (dialog->vbox);
dialog->action_area = gtk_hbutton_box_new ();
gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog->action_area),
GTK_BUTTONBOX_END);
gtk_box_pack_end (GTK_BOX (dialog->vbox), dialog->action_area,
FALSE, TRUE, 0);
gtk_widget_show (dialog->action_area);
dialog->separator = gtk_hseparator_new ();
gtk_box_pack_end (GTK_BOX (dialog->vbox), dialog->separator, FALSE, TRUE, 0);
gtk_widget_show (dialog->separator);
gtk_window_set_type_hint (GTK_WINDOW (dialog),
GDK_WINDOW_TYPE_HINT_DIALOG);
gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER_ON_PARENT);
@@ -309,26 +370,10 @@ static void
gtk_dialog_buildable_interface_init (GtkBuildableIface *iface)
{
parent_buildable_iface = g_type_interface_peek_parent (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 parent_buildable_iface->get_internal_child (buildable,
builder,
childname);
}
static void
gtk_dialog_set_property (GObject *object,
guint prop_id,
@@ -345,6 +390,18 @@ gtk_dialog_set_property (GObject *object,
gtk_dialog_set_has_separator (dialog, g_value_get_boolean (value));
break;
case PROP_SEPARATOR:
dialog->separator = g_value_get_object (value);
break;
case PROP_VBOX:
dialog->vbox = g_value_get_object (value);
break;
case PROP_ACTION_AREA:
dialog->action_area = g_value_get_object (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -367,6 +424,14 @@ gtk_dialog_get_property (GObject *object,
g_value_set_boolean (value, dialog->separator != NULL);
break;
case PROP_VBOX:
g_value_set_object (value, dialog->vbox);
break;
case PROP_ACTION_AREA:
g_value_set_object (value, dialog->action_area);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;

View File

@@ -3084,7 +3084,7 @@ get_label_wrap_width (GtkLabel *label)
PangoLayout *layout;
layout = gtk_widget_create_pango_layout (GTK_WIDGET (label),
"This string is just about long enough.");
"The minimum width for a wrapping label is long enough for a dialog");
pango_layout_get_size (layout, &priv->wrap_width, NULL);
g_object_unref (layout);
}

View File

@@ -95,23 +95,100 @@ struct _GtkMessageDialogPrivate
{
GtkWidget *secondary_label;
guint message_type : 3;
guint buttons_type : 3;
guint has_primary_markup : 1;
guint has_secondary_text : 1;
};
static void gtk_message_dialog_style_set (GtkWidget *widget,
GtkStyle *prev_style);
static void gtk_message_dialog_style_set (GtkWidget *widget,
GtkStyle *prev_style);
static GObject *gtk_message_dialog_constructor (GType type,
guint n_construct_properties,
GObjectConstructParam *construct_params);
static void gtk_message_dialog_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec);
static void gtk_message_dialog_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec);
static void gtk_message_dialog_add_buttons (GtkMessageDialog *message_dialog,
GtkButtonsType buttons);
static void gtk_message_dialog_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec);
static void gtk_message_dialog_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec);
static void gtk_message_dialog_add_buttons (GtkMessageDialog *message_dialog,
GtkButtonsType buttons);
static const gchar *gtk_message_dialog_template =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
"<interface>"
" <requires lib=\"gtk+\" version=\"2.20\"/>"
" <child internal-child=\"vbox\">"
" <object class=\"GtkVBox\" id=\"vbox\">"
" <property name=\"spacing\">14</property>"
" <child>"
" <object class=\"GtkHBox\" id=\"hbox1\">"
" <property name=\"visible\">True</property>"
" <property name=\"border_width\">5</property>"
" <property name=\"spacing\">12</property>"
" <child>"
" <object class=\"GtkImage\" id=\"image\">"
" <property name=\"visible\">True</property>"
" <property name=\"yalign\">0</property>"
" <property name=\"icon-size\">6</property>"
" </object>"
" <packing>"
" <property name=\"expand\">False</property>"
" <property name=\"fill\">False</property>"
" <property name=\"position\">0</property>"
" </packing>"
" </child>"
" <child>"
" <object class=\"GtkVBox\" id=\"vbox1\">"
" <property name=\"visible\">True</property>"
" <property name=\"spacing\">12</property>"
" <child>"
" <object class=\"GtkLabel\" id=\"label\">"
" <property name=\"visible\">True</property>"
" <property name=\"xalign\">0</property>"
" <property name=\"yalign\">0</property>"
" <property name=\"label\" translatable=\"yes\">primary message</property>"
" <property name=\"wrap\">True</property>"
" <property name=\"selectable\">True</property>"
" </object>"
" <packing>"
" <property name=\"expand\">False</property>"
" <property name=\"fill\">False</property>"
" <property name=\"position\">0</property>"
" </packing>"
" </child>"
" <child>"
" <object class=\"GtkLabel\" id=\"secondary-label\">"
" <property name=\"visible\">False</property>"
" <property name=\"no_show_all\">True</property>"
" <property name=\"xalign\">0</property>"
" <property name=\"yalign\">0</property>"
" <property name=\"label\" translatable=\"yes\">secondary message</property>"
" <property name=\"wrap\">True</property>"
" <property name=\"selectable\">True</property>"
" </object>"
" <packing>"
" <property name=\"position\">1</property>"
" </packing>"
" </child>"
" </object>"
" <packing>"
" <property name=\"position\">1</property>"
" </packing>"
" </child>"
" </object>"
" </child>"
" </object>"
" </child>"
" <child internal-child=\"action-area\">"
" <object class=\"GtkHButtonBox\" id=\"action-area\">"
" <property name=\"border_width\">5</property>"
" <property name=\"spacing\">6</property>"
" </object>"
" </child>"
"</interface>";
enum {
PROP_0,
@@ -121,7 +198,9 @@ enum {
PROP_USE_MARKUP,
PROP_SECONDARY_TEXT,
PROP_SECONDARY_USE_MARKUP,
PROP_IMAGE
PROP_IMAGE,
PROP_LABEL,
PROP_SECONDARY_LABEL
};
G_DEFINE_TYPE (GtkMessageDialog, gtk_message_dialog, GTK_TYPE_DIALOG)
@@ -137,6 +216,7 @@ gtk_message_dialog_class_init (GtkMessageDialogClass *class)
widget_class->style_set = gtk_message_dialog_style_set;
gobject_class->constructor = gtk_message_dialog_constructor;
gobject_class->set_property = gtk_message_dialog_set_property;
gobject_class->get_property = gtk_message_dialog_get_property;
@@ -176,7 +256,7 @@ gtk_message_dialog_class_init (GtkMessageDialogClass *class)
P_("The type of message"),
GTK_TYPE_MESSAGE_TYPE,
GTK_MESSAGE_INFO,
GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT));
GTK_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PROP_BUTTONS,
g_param_spec_enum ("buttons",
@@ -258,20 +338,54 @@ gtk_message_dialog_class_init (GtkMessageDialogClass *class)
*/
g_object_class_install_property (gobject_class,
PROP_IMAGE,
g_param_spec_object ("image",
P_("Image"),
P_("The image"),
GTK_TYPE_WIDGET,
GTK_PARAM_READWRITE));
gtk_param_spec_composite ("image",
P_("Image"),
P_("The image"),
GTK_TYPE_WIDGET,
GTK_PARAM_READWRITE));
/**
* GtkMessageDialog:label:
*
* The message label for this dialog.
*
* Since: 3.0
*/
g_object_class_install_property (gobject_class,
PROP_LABEL,
gtk_param_spec_composite ("label",
P_("Label"),
P_("The label"),
GTK_TYPE_LABEL,
GTK_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
/**
* GtkMessageDialog:secondary-label:
*
* The secondary message label for this dialog.
*
* Since: 3.0
*/
g_object_class_install_property (gobject_class,
PROP_SECONDARY_LABEL,
gtk_param_spec_composite ("secondary-label",
P_("Secondary Label"),
P_("The secondary message label"),
GTK_TYPE_LABEL,
GTK_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
g_type_class_add_private (gobject_class,
sizeof (GtkMessageDialogPrivate));
gtk_container_class_set_template (GTK_CONTAINER_CLASS (class), gtk_message_dialog_template);
}
static void
gtk_message_dialog_init (GtkMessageDialog *dialog)
{
GtkWidget *hbox, *vbox;
GtkMessageDialogPrivate *priv;
priv = GTK_MESSAGE_DIALOG_GET_PRIVATE (dialog);
@@ -282,47 +396,8 @@ gtk_message_dialog_init (GtkMessageDialog *dialog)
priv->has_primary_markup = FALSE;
priv->has_secondary_text = FALSE;
priv->secondary_label = gtk_label_new (NULL);
gtk_widget_set_no_show_all (priv->secondary_label, TRUE);
dialog->label = gtk_label_new (NULL);
dialog->image = gtk_image_new_from_stock (NULL, GTK_ICON_SIZE_DIALOG);
gtk_misc_set_alignment (GTK_MISC (dialog->image), 0.5, 0.0);
gtk_label_set_line_wrap (GTK_LABEL (dialog->label), TRUE);
gtk_label_set_selectable (GTK_LABEL (dialog->label), TRUE);
gtk_misc_set_alignment (GTK_MISC (dialog->label), 0.0, 0.0);
gtk_label_set_line_wrap (GTK_LABEL (priv->secondary_label), TRUE);
gtk_label_set_selectable (GTK_LABEL (priv->secondary_label), TRUE);
gtk_misc_set_alignment (GTK_MISC (priv->secondary_label), 0.0, 0.0);
hbox = gtk_hbox_new (FALSE, 12);
vbox = gtk_vbox_new (FALSE, 12);
gtk_box_pack_start (GTK_BOX (vbox), dialog->label,
FALSE, FALSE, 0);
gtk_box_pack_start (GTK_BOX (vbox), priv->secondary_label,
TRUE, TRUE, 0);
gtk_box_pack_start (GTK_BOX (hbox), dialog->image,
FALSE, FALSE, 0);
gtk_box_pack_start (GTK_BOX (hbox), vbox,
TRUE, TRUE, 0);
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
hbox,
FALSE, FALSE, 0);
gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
gtk_container_set_border_width (GTK_CONTAINER (hbox), 5);
gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (dialog)->vbox), 14); /* 14 + 2 * 5 = 24 */
gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (dialog)->action_area), 5);
gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (dialog)->action_area), 6);
gtk_widget_show_all (hbox);
_gtk_dialog_set_ignore_separator (GTK_DIALOG (dialog), TRUE);
}
@@ -404,6 +479,30 @@ setup_type (GtkMessageDialog *dialog,
}
}
static GObject *
gtk_message_dialog_constructor (GType type,
guint n_construct_properties,
GObjectConstructParam *construct_params)
{
GObject *object;
GtkMessageDialog *dialog;
GtkMessageDialogPrivate *priv;
object =
G_OBJECT_CLASS (gtk_message_dialog_parent_class)->constructor (type,
n_construct_properties,
construct_params);
dialog = GTK_MESSAGE_DIALOG (object);
priv = GTK_MESSAGE_DIALOG_GET_PRIVATE (dialog);
/* Setup widget's now that they've been built */
setup_type (dialog, priv->message_type);
gtk_message_dialog_add_buttons (dialog, priv->buttons_type);
return object;
}
static void
gtk_message_dialog_set_property (GObject *object,
guint prop_id,
@@ -419,10 +518,17 @@ gtk_message_dialog_set_property (GObject *object,
switch (prop_id)
{
case PROP_MESSAGE_TYPE:
setup_type (dialog, g_value_get_enum (value));
if (dialog->image)
setup_type (dialog, g_value_get_enum (value));
else
/* Deffer assignment at construct time until image is built */
priv->message_type = g_value_get_enum (value);
break;
case PROP_BUTTONS:
gtk_message_dialog_add_buttons (dialog, g_value_get_enum (value));
priv->buttons_type = g_value_get_enum (value);
break;
case PROP_TEXT:
if (priv->has_primary_markup)
@@ -467,6 +573,12 @@ gtk_message_dialog_set_property (GObject *object,
case PROP_IMAGE:
gtk_message_dialog_set_image (dialog, g_value_get_object (value));
break;
case PROP_LABEL:
dialog->label = g_value_get_object (value);
break;
case PROP_SECONDARY_LABEL:
priv->secondary_label = g_value_get_object (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -685,12 +797,19 @@ gtk_message_dialog_set_image (GtkMessageDialog *dialog,
priv = GTK_MESSAGE_DIALOG_GET_PRIVATE (dialog);
priv->message_type = GTK_MESSAGE_OTHER;
/* Only change the message type and the image if
* the image is not already in the dialog (which is
* the case when GtkBuilder builds the image).
*/
if (dialog->image && dialog->image != image)
{
priv->message_type = GTK_MESSAGE_OTHER;
parent = dialog->image->parent;
gtk_container_add (GTK_CONTAINER (parent), image);
gtk_container_remove (GTK_CONTAINER (parent), dialog->image);
gtk_box_reorder_child (GTK_BOX (parent), image, 0);
parent = dialog->image->parent;
gtk_container_add (GTK_CONTAINER (parent), image);
gtk_container_remove (GTK_CONTAINER (parent), dialog->image);
gtk_box_reorder_child (GTK_BOX (parent), image, 0);
}
dialog->image = image;