diff options
Diffstat (limited to 'gobject')
-rw-r--r-- | gobject/gbinding.c | 95 | ||||
-rw-r--r-- | gobject/gboxed.c | 6 | ||||
-rw-r--r-- | gobject/gobject.c | 127 | ||||
-rw-r--r-- | gobject/gobject.h | 19 | ||||
-rw-r--r-- | gobject/gobject_trace.h | 4 | ||||
-rw-r--r-- | gobject/gparam.c | 81 | ||||
-rw-r--r-- | gobject/gparam.h | 2 | ||||
-rw-r--r-- | gobject/gparamspecs.c | 17 | ||||
-rw-r--r-- | gobject/gparamspecs.h | 2 | ||||
-rw-r--r-- | gobject/gsignal.c | 199 | ||||
-rw-r--r-- | gobject/gsignal.h | 4 | ||||
-rw-r--r-- | gobject/gtype-private.h | 4 | ||||
-rw-r--r-- | gobject/gtype.c | 4 | ||||
-rw-r--r-- | gobject/gtype.h | 22 | ||||
-rw-r--r-- | gobject/gvalue.c | 4 | ||||
-rw-r--r-- | gobject/tests/autoptr.c | 30 | ||||
-rw-r--r-- | gobject/tests/binding.c | 152 | ||||
-rw-r--r-- | gobject/tests/meson.build | 1 | ||||
-rw-r--r-- | gobject/tests/param.c | 97 | ||||
-rw-r--r-- | gobject/tests/reference.c | 30 | ||||
-rw-r--r-- | gobject/tests/signals.c | 213 | ||||
-rw-r--r-- | gobject/tests/testing.c | 71 |
22 files changed, 949 insertions, 235 deletions
diff --git a/gobject/gbinding.c b/gobject/gbinding.c index 16942c221..12475bcdd 100644 --- a/gobject/gbinding.c +++ b/gobject/gbinding.c @@ -423,6 +423,53 @@ g_binding_finalize (GObject *gobject) G_OBJECT_CLASS (g_binding_parent_class)->finalize (gobject); } +/* @key must have already been validated with is_valid() + * Modifies @key in place. */ +static void +canonicalize_key (gchar *key) +{ + gchar *p; + + for (p = key; *p != 0; p++) + { + gchar c = *p; + + if (c == '_') + *p = '-'; + } +} + +/* @key must have already been validated with is_valid() */ +static gboolean +is_canonical (const gchar *key) +{ + return (strchr (key, '_') == NULL); +} + +static gboolean +is_valid_property_name (const gchar *key) +{ + const gchar *p; + + /* First character must be a letter. */ + if ((key[0] < 'A' || key[0] > 'Z') && + (key[0] < 'a' || key[0] > 'z')) + return FALSE; + + for (p = key; *p != 0; p++) + { + const gchar c = *p; + + if (c != '-' && c != '_' && + (c < '0' || c > '9') && + (c < 'A' || c > 'Z') && + (c < 'a' || c > 'z')) + return FALSE; + } + + return TRUE; +} + static void g_binding_set_property (GObject *gobject, guint prop_id, @@ -437,17 +484,35 @@ g_binding_set_property (GObject *gobject, binding->source = g_value_get_object (value); break; - case PROP_SOURCE_PROPERTY: - binding->source_property = g_intern_string (g_value_get_string (value)); - break; - case PROP_TARGET: binding->target = g_value_get_object (value); break; + case PROP_SOURCE_PROPERTY: case PROP_TARGET_PROPERTY: - binding->target_property = g_intern_string (g_value_get_string (value)); - break; + { + gchar *name_copy = NULL; + const gchar *name = g_value_get_string (value); + const gchar **dest; + + /* Ensure the name we intern is canonical. */ + if (!is_canonical (name)) + { + name_copy = g_value_dup_string (value); + canonicalize_key (name_copy); + name = name_copy; + } + + if (prop_id == PROP_SOURCE_PROPERTY) + dest = &binding->source_property; + else + dest = &binding->target_property; + + *dest = g_intern_string (name); + + g_free (name_copy); + break; + } case PROP_FLAGS: binding->flags = g_value_get_flags (value); @@ -474,7 +539,8 @@ g_binding_get_property (GObject *gobject, break; case PROP_SOURCE_PROPERTY: - g_value_set_string (value, binding->source_property); + /* @source_property is interned, so we don’t need to take a copy */ + g_value_set_static_string (value, binding->source_property); break; case PROP_TARGET: @@ -482,7 +548,8 @@ g_binding_get_property (GObject *gobject, break; case PROP_TARGET_PROPERTY: - g_value_set_string (value, binding->target_property); + /* @target_property is interned, so we don’t need to take a copy */ + g_value_set_static_string (value, binding->target_property); break; case PROP_FLAGS: @@ -606,7 +673,10 @@ g_binding_class_init (GBindingClass *klass) * GBinding:source-property: * * The name of the property of #GBinding:source that should be used - * as the source of the binding + * as the source of the binding. + * + * This should be in [canonical form][canonical-parameter-names] to get the + * best performance. * * Since: 2.26 */ @@ -622,7 +692,10 @@ g_binding_class_init (GBindingClass *klass) * GBinding:target-property: * * The name of the property of #GBinding:target that should be used - * as the target of the binding + * as the target of the binding. + * + * This should be in [canonical form][canonical-parameter-names] to get the + * best performance. * * Since: 2.26 */ @@ -835,8 +908,10 @@ g_object_bind_property_full (gpointer source, g_return_val_if_fail (G_IS_OBJECT (source), NULL); g_return_val_if_fail (source_property != NULL, NULL); + g_return_val_if_fail (is_valid_property_name (source_property), NULL); g_return_val_if_fail (G_IS_OBJECT (target), NULL); g_return_val_if_fail (target_property != NULL, NULL); + g_return_val_if_fail (is_valid_property_name (target_property), NULL); if (source == target && g_strcmp0 (source_property, target_property) == 0) { diff --git a/gobject/gboxed.c b/gobject/gboxed.c index 4404de3d6..87cc5d2c2 100644 --- a/gobject/gboxed.c +++ b/gobject/gboxed.c @@ -346,8 +346,7 @@ g_boxed_copy (GType boxed_type, g_return_val_if_fail (src_boxed != NULL, NULL); value_table = g_type_value_table_peek (boxed_type); - if (!value_table) - g_return_val_if_fail (G_TYPE_IS_VALUE_TYPE (boxed_type), NULL); + g_assert (value_table != NULL); /* check if our proxying implementation is used, we can short-cut here */ if (value_table->value_copy == boxed_proxy_value_copy) @@ -404,8 +403,7 @@ g_boxed_free (GType boxed_type, g_return_if_fail (boxed != NULL); value_table = g_type_value_table_peek (boxed_type); - if (!value_table) - g_return_if_fail (G_TYPE_IS_VALUE_TYPE (boxed_type)); + g_assert (value_table != NULL); /* check if our proxying implementation is used, we can short-cut here */ if (value_table->value_free == boxed_proxy_value_free) diff --git a/gobject/gobject.c b/gobject/gobject.c index df27c36f7..07752cf25 100644 --- a/gobject/gobject.c +++ b/gobject/gobject.c @@ -162,6 +162,29 @@ enum { PROP_NONE }; +#define OPTIONAL_FLAG_IN_CONSTRUCTION 1<<0 +#define OPTIONAL_FLAG_HAS_SIGNAL_HANDLER 1<<1 /* Set if object ever had a signal handler */ + +#if SIZEOF_INT == 4 && GLIB_SIZEOF_VOID_P == 8 +#define HAVE_OPTIONAL_FLAGS +#endif + +typedef struct +{ + GTypeInstance g_type_instance; + + /*< private >*/ + volatile guint ref_count; +#ifdef HAVE_OPTIONAL_FLAGS + volatile guint optional_flags; +#endif + GData *qdata; +} GObjectReal; + +G_STATIC_ASSERT(sizeof(GObject) == sizeof(GObjectReal)); +G_STATIC_ASSERT(G_STRUCT_OFFSET(GObject, ref_count) == G_STRUCT_OFFSET(GObjectReal, ref_count)); +G_STATIC_ASSERT(G_STRUCT_OFFSET(GObject, qdata) == G_STRUCT_OFFSET(GObjectReal, qdata)); + /* --- prototypes --- */ static void g_object_base_class_init (GObjectClass *class); @@ -1008,10 +1031,83 @@ g_object_interface_list_properties (gpointer g_iface, return pspecs; } +static inline guint +object_get_optional_flags (GObject *object) +{ +#ifdef HAVE_OPTIONAL_FLAGS + GObjectReal *real = (GObjectReal *)object; + return (guint)g_atomic_int_get (&real->optional_flags); +#else + return 0; +#endif +} + +static inline void +object_set_optional_flags (GObject *object, + guint flags) +{ +#ifdef HAVE_OPTIONAL_FLAGS + GObjectReal *real = (GObjectReal *)object; + g_atomic_int_or (&real->optional_flags, flags); +#endif +} + +static inline void +object_unset_optional_flags (GObject *object, + guint flags) +{ +#ifdef HAVE_OPTIONAL_FLAGS + GObjectReal *real = (GObjectReal *)object; + g_atomic_int_and (&real->optional_flags, ~flags); +#endif +} + +gboolean +_g_object_has_signal_handler (GObject *object) +{ +#ifdef HAVE_OPTIONAL_FLAGS + return (object_get_optional_flags (object) & OPTIONAL_FLAG_HAS_SIGNAL_HANDLER) != 0; +#else + return TRUE; +#endif +} + +void +_g_object_set_has_signal_handler (GObject *object) +{ +#ifdef HAVE_OPTIONAL_FLAGS + object_set_optional_flags (object, OPTIONAL_FLAG_HAS_SIGNAL_HANDLER); +#endif +} + static inline gboolean object_in_construction (GObject *object) { +#ifdef HAVE_OPTIONAL_FLAGS + return (object_get_optional_flags (object) & OPTIONAL_FLAG_IN_CONSTRUCTION) != 0; +#else return g_datalist_id_get_data (&object->qdata, quark_in_construction) != NULL; +#endif +} + +static inline void +set_object_in_construction (GObject *object) +{ +#ifdef HAVE_OPTIONAL_FLAGS + object_set_optional_flags (object, OPTIONAL_FLAG_IN_CONSTRUCTION); +#else + g_datalist_id_set_data (&object->qdata, quark_in_construction, object); +#endif +} + +static inline void +unset_object_in_construction (GObject *object) +{ +#ifdef HAVE_OPTIONAL_FLAGS + object_unset_optional_flags (object, OPTIONAL_FLAG_IN_CONSTRUCTION); +#else + g_datalist_id_set_data (&object->qdata, quark_in_construction, NULL); +#endif } static void @@ -1030,7 +1126,7 @@ g_object_init (GObject *object, if (CLASS_HAS_CUSTOM_CONSTRUCTOR (class)) { /* mark object in-construction for notify_queue_thaw() and to allow construct-only properties */ - g_datalist_id_set_data (&object->qdata, quark_in_construction, object); + set_object_in_construction (object); } GOBJECT_IF_DEBUG (OBJECTS, @@ -1521,7 +1617,7 @@ object_interface_check_properties (gpointer check_data, /* We do a number of checks on the properties of an interface to * make sure that all classes implementing the interface are - * overriding the properties in a sane way. + * overriding the properties correctly. * * We do the checks in order of importance so that we can give * more useful error messages first. @@ -1651,6 +1747,20 @@ g_object_get_type (void) * Construction parameters (see #G_PARAM_CONSTRUCT, #G_PARAM_CONSTRUCT_ONLY) * which are not explicitly specified are set to their default values. * + * Note that in C, small integer types in variable argument lists are promoted + * up to #gint or #guint as appropriate, and read back accordingly. #gint is 32 + * bits on every platform on which GLib is currently supported. This means that + * you can use C expressions of type #gint with g_object_new() and properties of + * type #gint or #guint or smaller. Specifically, you can use integer literals + * with these property types. + * + * When using property types of #gint64 or #guint64, you must ensure that the + * value that you provide is 64 bit. This means that you should use a cast or + * make use of the %G_GINT64_CONSTANT or %G_GUINT64_CONSTANT macros. + * + * Similarly, #gfloat is promoted to #gdouble, so you must ensure that the value + * you provide is a #gdouble, even for a property of type #gfloat. + * * Returns: (transfer full) (type GObject.Object): a new instance of * @object_type */ @@ -1766,7 +1876,7 @@ g_object_new_with_custom_constructor (GObjectClass *class, */ newly_constructed = object_in_construction (object); if (newly_constructed) - g_datalist_id_set_data (&object->qdata, quark_in_construction, NULL); + unset_object_in_construction (object); if (CLASS_HAS_PROPS (class)) { @@ -2479,6 +2589,11 @@ g_object_get_valist (GObject *object, * * Sets properties on an object. * + * The same caveats about passing integer literals as varargs apply as with + * g_object_new(). In particular, any integer literals set as the values for + * properties of type #gint64 or #guint64 must be 64 bits wide, using the + * %G_GINT64_CONSTANT or %G_GUINT64_CONSTANT macros. + * * Note that the "notify" signals are queued and only emitted (in * reverse order) after all properties have been set. See * g_object_freeze_notify(). @@ -2515,20 +2630,22 @@ g_object_set (gpointer _object, * of three properties: an integer, a string and an object: * |[<!-- language="C" --> * gint intval; + * guint64 uint64val; * gchar *strval; * GObject *objval; * * g_object_get (my_object, * "int-property", &intval, + * "uint64-property", &uint64val, * "str-property", &strval, * "obj-property", &objval, * NULL); * - * // Do something with intval, strval, objval + * // Do something with intval, uint64val, strval, objval * * g_free (strval); * g_object_unref (objval); - * ]| + * ]| */ void g_object_get (gpointer _object, diff --git a/gobject/gobject.h b/gobject/gobject.h index 91b9f6328..2e07fa724 100644 --- a/gobject/gobject.h +++ b/gobject/gobject.h @@ -738,12 +738,31 @@ static inline gboolean return TRUE; } +/* We need GCC for __extension__, which we need to sort out strict aliasing of @object_ptr */ +#if defined(__GNUC__) + +#define g_set_object(object_ptr, new_object) \ + (G_GNUC_EXTENSION ({ \ + G_STATIC_ASSERT (sizeof *(object_ptr) == sizeof (new_object)); \ + /* Only one access, please; work around type aliasing */ \ + union { char *in; GObject **out; } _object_ptr; \ + _object_ptr.in = (char *) (object_ptr); \ + /* Check types match */ \ + (void) (0 ? *(object_ptr) = (new_object), FALSE : FALSE); \ + (g_set_object) (_object_ptr.out, (GObject *) new_object); \ + })) \ + GLIB_AVAILABLE_MACRO_IN_2_44 + +#else /* if !defined(__GNUC__) */ + #define g_set_object(object_ptr, new_object) \ (/* Check types match. */ \ 0 ? *(object_ptr) = (new_object), FALSE : \ (g_set_object) ((GObject **) (object_ptr), (GObject *) (new_object)) \ ) +#endif /* !defined(__GNUC__) */ + /** * g_assert_finalize_object: (skip) * @object: (transfer full) (type GObject.Object): an object diff --git a/gobject/gobject_trace.h b/gobject/gobject_trace.h index 30ef2fb5b..261fdac07 100644 --- a/gobject/gobject_trace.h +++ b/gobject/gobject_trace.h @@ -25,7 +25,9 @@ #error "config.h must be included prior to gobject_trace.h" #endif -#ifdef HAVE_DTRACE +/* Ignore probes when doing static analysis, as they do weird things which + * confuses the analyser. */ +#if defined(HAVE_DTRACE) && !defined(__clang_analyzer__) /* include the generated probes header and put markers in code */ #include "gobject_probes.h" diff --git a/gobject/gparam.c b/gobject/gparam.c index 5aa54c02c..b336125e4 100644 --- a/gobject/gparam.c +++ b/gobject/gparam.c @@ -41,11 +41,14 @@ * * ## Parameter names # {#canonical-parameter-names} * - * Parameter names need to start with a letter (a-z or A-Z). - * Subsequent characters can be letters, numbers or a '-'. - * All other characters are replaced by a '-' during construction. - * The result of this replacement is called the canonical name of - * the parameter. + * A property name consists of segments consisting of ASCII letters and + * digits, separated by either the `-` or `_` character. The first + * character of a property name must be a letter. These are the same rules as + * for signal naming (see g_signal_new()). + * + * When creating and looking up a #GParamSpec, either separator can be + * used, but they cannot be mixed. Using `-` is considerably more + * efficient, and is the ‘canonical form’. Using `_` is discouraged. */ @@ -355,6 +358,8 @@ g_param_spec_get_blurb (GParamSpec *pspec) return NULL; } +/* @key must have already been validated with is_valid() + * Modifies @key in place. */ static void canonicalize_key (gchar *key) { @@ -364,28 +369,37 @@ canonicalize_key (gchar *key) { gchar c = *p; - if (c != '-' && - (c < '0' || c > '9') && - (c < 'A' || c > 'Z') && - (c < 'a' || c > 'z')) - *p = '-'; + if (c == '_') + *p = '-'; } } +/* @key must have already been validated with is_valid() */ static gboolean is_canonical (const gchar *key) { + return (strchr (key, '_') == NULL); +} + +static gboolean +is_valid_property_name (const gchar *key) +{ const gchar *p; + /* First character must be a letter. */ + if ((key[0] < 'A' || key[0] > 'Z') && + (key[0] < 'a' || key[0] > 'z')) + return FALSE; + for (p = key; *p != 0; p++) { - gchar c = *p; + const gchar c = *p; - if (c != '-' && - (c < '0' || c > '9') && - (c < 'A' || c > 'Z') && - (c < 'a' || c > 'z')) - return FALSE; + if (c != '-' && c != '_' && + (c < '0' || c > '9') && + (c < 'A' || c > 'Z') && + (c < 'a' || c > 'z')) + return FALSE; } return TRUE; @@ -401,15 +415,9 @@ is_canonical (const gchar *key) * * Creates a new #GParamSpec instance. * - * A property name consists of segments consisting of ASCII letters and - * digits, separated by either the '-' or '_' character. The first - * character of a property name must be a letter. Names which violate these - * rules lead to undefined behaviour. - * - * When creating and looking up a #GParamSpec, either separator can be - * used, but they cannot be mixed. Using '-' is considerably more - * efficient and in fact required when using property names as detail - * strings for signals. + * See [canonical parameter names][canonical-parameter-names] for details of + * the rules for @name. Names which violate these rules lead to undefined + * behaviour. * * Beyond the name, #GParamSpecs have two more descriptive * strings associated with them, the @nick, which should be suitable @@ -431,7 +439,7 @@ g_param_spec_internal (GType param_type, g_return_val_if_fail (G_TYPE_IS_PARAM (param_type) && param_type != G_TYPE_PARAM, NULL); g_return_val_if_fail (name != NULL, NULL); - g_return_val_if_fail ((name[0] >= 'A' && name[0] <= 'Z') || (name[0] >= 'a' && name[0] <= 'z'), NULL); + g_return_val_if_fail (is_valid_property_name (name), NULL); g_return_val_if_fail (!(flags & G_PARAM_STATIC_NAME) || is_canonical (name), NULL); pspec = (gpointer) g_type_create_instance (param_type); @@ -595,7 +603,8 @@ g_param_spec_get_redirect_target (GParamSpec *pspec) /** * g_param_value_set_default: * @pspec: a valid #GParamSpec - * @value: a #GValue of correct type for @pspec + * @value: a #GValue of correct type for @pspec; since 2.64, you + * can also pass an empty #GValue, initialized with %G_VALUE_INIT * * Sets @value to its default value as specified in @pspec. */ @@ -604,10 +613,18 @@ g_param_value_set_default (GParamSpec *pspec, GValue *value) { g_return_if_fail (G_IS_PARAM_SPEC (pspec)); - g_return_if_fail (G_IS_VALUE (value)); - g_return_if_fail (PSPEC_APPLIES_TO_VALUE (pspec, value)); - g_value_reset (value); + if (G_VALUE_TYPE (value) == G_TYPE_INVALID) + { + g_value_init (value, G_PARAM_SPEC_VALUE_TYPE (pspec)); + } + else + { + g_return_if_fail (G_IS_VALUE (value)); + g_return_if_fail (PSPEC_APPLIES_TO_VALUE (pspec, value)); + g_value_reset (value); + } + G_PARAM_SPEC_GET_CLASS (pspec)->value_set_default (pspec, value); } @@ -621,8 +638,8 @@ g_param_value_set_default (GParamSpec *pspec, * Returns: whether @value contains the canonical default for this @pspec */ gboolean -g_param_value_defaults (GParamSpec *pspec, - GValue *value) +g_param_value_defaults (GParamSpec *pspec, + const GValue *value) { GValue dflt_value = G_VALUE_INIT; gboolean defaults; diff --git a/gobject/gparam.h b/gobject/gparam.h index 33f95f0c5..b6a554653 100644 --- a/gobject/gparam.h +++ b/gobject/gparam.h @@ -307,7 +307,7 @@ void g_param_value_set_default (GParamSpec *pspec, GValue *value); GLIB_AVAILABLE_IN_ALL gboolean g_param_value_defaults (GParamSpec *pspec, - GValue *value); + const GValue *value); GLIB_AVAILABLE_IN_ALL gboolean g_param_value_validate (GParamSpec *pspec, GValue *value); diff --git a/gobject/gparamspecs.c b/gobject/gparamspecs.c index 5d15c26e1..c45ebc548 100644 --- a/gobject/gparamspecs.c +++ b/gobject/gparamspecs.c @@ -912,8 +912,11 @@ param_value_array_validate (GParamSpec *pspec, g_param_value_set_default (element_spec, element); changed++; } - /* validate array value against element_spec */ - changed += g_param_value_validate (element_spec, element); + else + { + /* validate array value against element_spec */ + changed += g_param_value_validate (element_spec, element); + } } } } @@ -2092,7 +2095,10 @@ g_param_spec_enum (const gchar *name, blurb, flags); if (espec == NULL) - return NULL; + { + g_type_class_unref (enum_class); + return NULL; + } espec->enum_class = enum_class; espec->default_value = default_value; @@ -2140,7 +2146,10 @@ g_param_spec_flags (const gchar *name, blurb, flags); if (fspec == NULL) - return NULL; + { + g_type_class_unref (flags_class); + return NULL; + } fspec->flags_class = flags_class; fspec->default_value = default_value; diff --git a/gobject/gparamspecs.h b/gobject/gparamspecs.h index 0309f9bb3..d0e4d5953 100644 --- a/gobject/gparamspecs.h +++ b/gobject/gparamspecs.h @@ -1150,7 +1150,7 @@ GParamSpec* g_param_spec_variant (const gchar *name, # else /* !GOBJECT_STATIC_COMPILATION */ # ifdef GOBJECT_COMPILATION # ifdef DLL_EXPORT -# define GOBJECT_VAR __declspec(dllexport) +# define GOBJECT_VAR extern __declspec(dllexport) # else /* !DLL_EXPORT */ # define GOBJECT_VAR extern # endif /* !DLL_EXPORT */ diff --git a/gobject/gsignal.c b/gobject/gsignal.c index 77d8f211e..45effa92d 100644 --- a/gobject/gsignal.c +++ b/gobject/gsignal.c @@ -98,6 +98,10 @@ * detail part of the signal specification upon connection) serves as a * wildcard and matches any detail argument passed in to emission. * + * While the @detail argument is typically used to pass an object property name + * (as with #GObject::notify), no specific format is mandated for the detail + * string, other than that it must be non-empty. + * * ## Memory management of signal handlers # {#signal-memory-management} * * If you are connecting handlers to signals and using a #GObject instance as @@ -145,8 +149,8 @@ typedef enum /* --- prototypes --- */ -static inline guint signal_id_lookup (GQuark quark, - GType itype); +static inline guint signal_id_lookup (const gchar *name, + GType itype); static void signal_destroy_R (SignalNode *signal_node); static inline HandlerList* handler_list_ensure (guint signal_id, gpointer instance); @@ -340,14 +344,68 @@ LOOKUP_SIGNAL_NODE (guint signal_id) /* --- functions --- */ +/* @key must have already been validated with is_valid() + * Modifies @key in place. */ +static void +canonicalize_key (gchar *key) +{ + gchar *p; + + for (p = key; *p != 0; p++) + { + gchar c = *p; + + if (c == '_') + *p = '-'; + } +} + +/* @key must have already been validated with is_valid() */ +static gboolean +is_canonical (const gchar *key) +{ + return (strchr (key, '_') == NULL); +} + +static gboolean +is_valid_signal_name (const gchar *key) +{ + const gchar *p; + + /* FIXME: We allow this, against our own documentation (the leading `-` is + * invalid), because GTK has historically used this. */ + if (g_str_equal (key, "-gtk-private-changed")) + return TRUE; + + /* First character must be a letter. */ + if ((key[0] < 'A' || key[0] > 'Z') && + (key[0] < 'a' || key[0] > 'z')) + return FALSE; + + for (p = key; *p != 0; p++) + { + const gchar c = *p; + + if (c != '-' && c != '_' && + (c < '0' || c > '9') && + (c < 'A' || c > 'Z') && + (c < 'a' || c > 'z')) + return FALSE; + } + + return TRUE; +} + static inline guint -signal_id_lookup (GQuark quark, - GType itype) +signal_id_lookup (const gchar *name, + GType itype) { + GQuark quark; GType *ifaces, type = itype; SignalKey key; guint n_ifaces; + quark = g_quark_try_string (name); key.quark = quark; /* try looking up signals for this type and its ancestors */ @@ -381,7 +439,22 @@ signal_id_lookup (GQuark quark, } } g_free (ifaces); - + + /* If the @name is non-canonical, try again. This is the slow path — people + * should use canonical names in their queries if they want performance. */ + if (!is_canonical (name)) + { + guint signal_id; + gchar *name_copy = g_strdup (name); + canonicalize_key (name_copy); + + signal_id = signal_id_lookup (name_copy, itype); + + g_free (name_copy); + + return signal_id; + } + return 0; } @@ -711,7 +784,7 @@ handler_insert (guint signal_id, HandlerList *hlist; g_assert (handler->prev == NULL && handler->next == NULL); /* paranoid */ - + hlist = handler_list_ensure (signal_id, instance); if (!hlist->handlers) { @@ -1080,7 +1153,7 @@ signal_parse_name (const gchar *name, if (!colon) { - signal_id = signal_id_lookup (g_quark_try_string (name), itype); + signal_id = signal_id_lookup (name, itype); if (signal_id && detail_p) *detail_p = 0; } @@ -1089,11 +1162,14 @@ signal_parse_name (const gchar *name, gchar buffer[32]; guint l = colon - name; + if (colon[2] == '\0') + return 0; + if (l < 32) { memcpy (buffer, name, l); buffer[l] = 0; - signal_id = signal_id_lookup (g_quark_try_string (buffer), itype); + signal_id = signal_id_lookup (buffer, itype); } else { @@ -1101,12 +1177,12 @@ signal_parse_name (const gchar *name, memcpy (signal, name, l); signal[l] = 0; - signal_id = signal_id_lookup (g_quark_try_string (signal), itype); + signal_id = signal_id_lookup (signal, itype); g_free (signal); } if (signal_id && detail_p) - *detail_p = colon[2] ? (force_quark ? g_quark_from_string : g_quark_try_string) (colon + 2) : 0; + *detail_p = (force_quark ? g_quark_from_string : g_quark_try_string) (colon + 2); } else signal_id = 0; @@ -1224,6 +1300,10 @@ g_signal_stop_emission_by_name (gpointer instance, * * Also tries the ancestors of the given type. * + * The type class passed as @itype must already have been instantiated (for + * example, using g_type_class_ref()) for this function to work, as signals are + * always installed during class initialization. + * * See g_signal_new() for details on allowed signal names. * * Returns: the signal's identifying number, or 0 if no signal was found. @@ -1237,7 +1317,7 @@ g_signal_lookup (const gchar *name, g_return_val_if_fail (G_TYPE_IS_INSTANTIATABLE (itype) || G_TYPE_IS_INTERFACE (itype), 0); SIGNAL_LOCK (); - signal_id = signal_id_lookup (g_quark_try_string (name), itype); + signal_id = signal_id_lookup (name, itype); SIGNAL_UNLOCK (); if (!signal_id) { @@ -1245,12 +1325,9 @@ g_signal_lookup (const gchar *name, if (!g_type_name (itype)) g_warning (G_STRLOC ": unable to look up signal \"%s\" for invalid type id '%"G_GSIZE_FORMAT"'", name, itype); - else if (!G_TYPE_IS_INSTANTIATABLE (itype)) - g_warning (G_STRLOC ": unable to look up signal \"%s\" for non instantiatable type '%s'", - name, g_type_name (itype)); - else if (!g_type_class_peek (itype)) - g_warning (G_STRLOC ": unable to look up signal \"%s\" of unloaded type '%s'", - name, g_type_name (itype)); + else if (!is_valid_signal_name (name)) + g_warning (G_STRLOC ": unable to look up invalid signal name \"%s\" on type '%s'", + name, g_type_name (itype)); } return signal_id; @@ -1287,13 +1364,7 @@ g_signal_list_ids (GType itype, for (i = 0; i < n_nodes; i++) if (keys[i].itype == itype) { - const gchar *name = g_quark_to_string (keys[i].quark); - - /* Signal names with "_" in them are aliases to the same - * name with "-" instead of "_". - */ - if (!strchr (name, '_')) - g_array_append_val (result, keys[i].signal_id); + g_array_append_val (result, keys[i].signal_id); } *n_ids = result->len; SIGNAL_UNLOCK (); @@ -1399,12 +1470,14 @@ g_signal_query (guint signal_id, * Creates a new signal. (This is usually done in the class initializer.) * * A signal name consists of segments consisting of ASCII letters and - * digits, separated by either the '-' or '_' character. The first + * digits, separated by either the `-` or `_` character. The first * character of a signal name must be a letter. Names which violate these - * rules lead to undefined behaviour of the GSignal system. + * rules lead to undefined behaviour. These are the same rules as for property + * naming (see g_param_spec_internal()). * * When registering a signal and looking up a signal, either separator can - * be used, but they cannot be mixed. + * be used, but they cannot be mixed. Using `-` is considerably more efficient. + * Using `_` is discouraged. * * If 0 is used for @class_offset subclasses cannot override the class handler * in their class_init method by doing super_class->signal_handler = my_signal_handler. @@ -1630,7 +1703,8 @@ g_signal_newv (const gchar *signal_name, guint n_params, GType *param_types) { - gchar *name; + const gchar *name; + gchar *signal_name_copy = NULL; guint signal_id, i; SignalNode *node; GSignalCMarshaller builtin_c_marshaller; @@ -1638,6 +1712,7 @@ g_signal_newv (const gchar *signal_name, GSignalCVaMarshaller va_marshaller; g_return_val_if_fail (signal_name != NULL, 0); + g_return_val_if_fail (is_valid_signal_name (signal_name), 0); g_return_val_if_fail (G_TYPE_IS_INSTANTIATABLE (itype) || G_TYPE_IS_INTERFACE (itype), 0); if (n_params) g_return_val_if_fail (param_types != NULL, 0); @@ -1647,12 +1722,20 @@ g_signal_newv (const gchar *signal_name, if (!accumulator) g_return_val_if_fail (accu_data == NULL, 0); - name = g_strdup (signal_name); - g_strdelimit (name, G_STR_DELIMITERS ":^", '_'); /* FIXME do character checks like for types */ + if (!is_canonical (signal_name)) + { + signal_name_copy = g_strdup (signal_name); + canonicalize_key (signal_name_copy); + name = signal_name_copy; + } + else + { + name = signal_name; + } SIGNAL_LOCK (); - signal_id = signal_id_lookup (g_quark_try_string (name), itype); + signal_id = signal_id_lookup (name, itype); node = LOOKUP_SIGNAL_NODE (signal_id); if (node && !node->destroyed) { @@ -1660,7 +1743,7 @@ g_signal_newv (const gchar *signal_name, name, type_debug_name (node->itype), G_TYPE_IS_INTERFACE (node->itype) ? "interface" : "class ancestry"); - g_free (name); + g_free (signal_name_copy); SIGNAL_UNLOCK (); return 0; } @@ -1670,7 +1753,7 @@ g_signal_newv (const gchar *signal_name, name, type_debug_name (itype), type_debug_name (node->itype)); - g_free (name); + g_free (signal_name_copy); SIGNAL_UNLOCK (); return 0; } @@ -1679,7 +1762,7 @@ g_signal_newv (const gchar *signal_name, { g_warning (G_STRLOC ": parameter %d of type '%s' for signal \"%s::%s\" is not a value type", i + 1, type_debug_name (param_types[i]), type_debug_name (itype), name); - g_free (name); + g_free (signal_name_copy); SIGNAL_UNLOCK (); return 0; } @@ -1687,7 +1770,7 @@ g_signal_newv (const gchar *signal_name, { g_warning (G_STRLOC ": return value of type '%s' for signal \"%s::%s\" is not a value type", type_debug_name (return_type), type_debug_name (itype), name); - g_free (name); + g_free (signal_name_copy); SIGNAL_UNLOCK (); return 0; } @@ -1696,7 +1779,7 @@ g_signal_newv (const gchar *signal_name, { g_warning (G_STRLOC ": signal \"%s::%s\" has return type '%s' and is only G_SIGNAL_RUN_FIRST", type_debug_name (itype), name, type_debug_name (return_type)); - g_free (name); + g_free (signal_name_copy); SIGNAL_UNLOCK (); return 0; } @@ -1712,12 +1795,8 @@ g_signal_newv (const gchar *signal_name, g_signal_nodes = g_renew (SignalNode*, g_signal_nodes, g_n_signal_nodes); g_signal_nodes[signal_id] = node; node->itype = itype; - node->name = name; key.itype = itype; - key.quark = g_quark_from_string (node->name); key.signal_id = signal_id; - g_signal_key_bsa = g_bsearch_array_insert (g_signal_key_bsa, &g_signal_key_bconfig, &key); - g_strdelimit (name, "_", '-'); node->name = g_intern_string (name); key.quark = g_quark_from_string (name); g_signal_key_bsa = g_bsearch_array_insert (g_signal_key_bsa, &g_signal_key_bconfig, &key); @@ -1805,7 +1884,7 @@ g_signal_newv (const gchar *signal_name, SIGNAL_UNLOCK (); - g_free (name); + g_free (signal_name_copy); return signal_id; } @@ -2212,7 +2291,7 @@ g_signal_chain_from_overridden_handler (gpointer instance, g_free (error); /* we purposely leak the value here, it might not be - * in a sane state if an error condition occoured + * in a correct state if an error condition occurred */ while (i--) g_value_unset (param_values + i); @@ -2268,7 +2347,7 @@ g_signal_chain_from_overridden_handler (gpointer instance, g_free (error); /* we purposely leak the value here, it might not be - * in a sane state if an error condition occurred + * in a correct state if an error condition occurred */ } } @@ -2345,7 +2424,10 @@ g_signal_connect_closure_by_id (gpointer instance, else { Handler *handler = handler_new (signal_id, instance, after); - + + if (G_TYPE_IS_OBJECT (node->itype)) + _g_object_set_has_signal_handler ((GObject *)instance); + handler_seq_no = handler->sequential_number; handler->detail = detail; handler->closure = g_closure_ref (closure); @@ -2410,6 +2492,9 @@ g_signal_connect_closure (gpointer instance, { Handler *handler = handler_new (signal_id, instance, after); + if (G_TYPE_IS_OBJECT (node->itype)) + _g_object_set_has_signal_handler ((GObject *)instance); + handler_seq_no = handler->sequential_number; handler->detail = detail; handler->closure = g_closure_ref (closure); @@ -2511,6 +2596,9 @@ g_signal_connect_data (gpointer instance, { Handler *handler = handler_new (signal_id, instance, after); + if (G_TYPE_IS_OBJECT (node->itype)) + _g_object_set_has_signal_handler ((GObject *)instance); + handler_seq_no = handler->sequential_number; handler->detail = detail; handler->closure = g_closure_ref ((swapped ? g_cclosure_new_swap : g_cclosure_new) (c_handler, data, destroy_data)); @@ -3121,7 +3209,14 @@ g_signal_emitv (const GValue *instance_and_params, (node->single_va_closure == SINGLE_VA_CLOSURE_EMPTY_MAGIC || _g_closure_is_void (node->single_va_closure, instance))) { - HandlerList* hlist = handler_list_lookup (node->signal_id, instance); + HandlerList* hlist; + + /* single_va_closure is only true for GObjects, so fast path if no handler ever connected to the signal */ + if (_g_object_has_signal_handler ((GObject *)instance)) + hlist = handler_list_lookup (node->signal_id, instance); + else + hlist = NULL; + if (hlist == NULL || hlist->handlers == NULL) { /* nothing to do to emit this signal */ @@ -3204,7 +3299,7 @@ g_signal_emit_valist (gpointer instance, if (node->single_va_closure != NULL) { - HandlerList* hlist = handler_list_lookup (node->signal_id, instance); + HandlerList* hlist; Handler *fastpath_handler = NULL; Handler *l; GClosure *closure = NULL; @@ -3226,6 +3321,12 @@ g_signal_emit_valist (gpointer instance, fastpath = FALSE; } + /* single_va_closure is only true for GObjects, so fast path if no handler ever connected to the signal */ + if (_g_object_has_signal_handler ((GObject *)instance)) + hlist = handler_list_lookup (node->signal_id, instance); + else + hlist = NULL; + for (l = hlist ? hlist->handlers : NULL; fastpath && l != NULL; l = l->next) { if (!l->block_count && @@ -3345,7 +3446,7 @@ g_signal_emit_valist (gpointer instance, g_warning ("%s: %s", G_STRLOC, error); g_free (error); /* we purposely leak the value here, it might not be - * in a sane state if an error condition occurred + * in a correct state if an error condition occurred */ } } @@ -3382,7 +3483,7 @@ g_signal_emit_valist (gpointer instance, g_free (error); /* we purposely leak the value here, it might not be - * in a sane state if an error condition occoured + * in a correct state if an error condition occurred */ while (i--) g_value_unset (param_values + i); @@ -3418,7 +3519,7 @@ g_signal_emit_valist (gpointer instance, g_free (error); /* we purposely leak the value here, it might not be - * in a sane state if an error condition occurred + * in a correct state if an error condition occurred */ } } diff --git a/gobject/gsignal.h b/gobject/gsignal.h index a79b9f662..59f94d59a 100644 --- a/gobject/gsignal.h +++ b/gobject/gsignal.h @@ -160,11 +160,11 @@ typedef enum /** * GSignalMatchType: * @G_SIGNAL_MATCH_ID: The signal id must be equal. - * @G_SIGNAL_MATCH_DETAIL: The signal detail be equal. + * @G_SIGNAL_MATCH_DETAIL: The signal detail must be equal. * @G_SIGNAL_MATCH_CLOSURE: The closure must be the same. * @G_SIGNAL_MATCH_FUNC: The C closure callback must be the same. * @G_SIGNAL_MATCH_DATA: The closure data must be the same. - * @G_SIGNAL_MATCH_UNBLOCKED: Only unblocked signals may matched. + * @G_SIGNAL_MATCH_UNBLOCKED: Only unblocked signals may be matched. * * The match types specify what g_signal_handlers_block_matched(), * g_signal_handlers_unblock_matched() and g_signal_handlers_disconnect_matched() diff --git a/gobject/gtype-private.h b/gobject/gtype-private.h index 230dba03a..2e0afdd5d 100644 --- a/gobject/gtype-private.h +++ b/gobject/gtype-private.h @@ -23,6 +23,7 @@ #include "gboxed.h" #include "gclosure.h" +#include "gobject.h" /*< private > * GOBJECT_IF_DEBUG: @@ -92,6 +93,9 @@ void _g_closure_invoke_va (GClosure *closure, int n_params, GType *param_types); +gboolean _g_object_has_signal_handler (GObject *object); +void _g_object_set_has_signal_handler (GObject *object); + /** * _G_DEFINE_TYPE_EXTENDED_WITH_PRELUDE: * diff --git a/gobject/gtype.c b/gobject/gtype.c index 7d3789400..b5ef2d11e 100644 --- a/gobject/gtype.c +++ b/gobject/gtype.c @@ -2825,7 +2825,7 @@ g_type_register_dynamic (GType parent_type, * @info: #GInterfaceInfo structure for this * (@instance_type, @interface_type) combination * - * Adds the static @interface_type to @instantiable_type. + * Adds @interface_type to the static @instantiable_type. * The information contained in the #GInterfaceInfo structure * pointed to by @info is used to manage the relationship. */ @@ -2861,7 +2861,7 @@ g_type_add_interface_static (GType instance_type, * @interface_type: #GType value of an interface type * @plugin: #GTypePlugin structure to retrieve the #GInterfaceInfo from * - * Adds the dynamic @interface_type to @instantiable_type. The information + * Adds @interface_type to the dynamic @instantiable_type. The information * contained in the #GTypePlugin structure pointed to by @plugin * is used to manage the relationship. */ diff --git a/gobject/gtype.h b/gobject/gtype.h index d9e5d110c..479b405e9 100644 --- a/gobject/gtype.h +++ b/gobject/gtype.h @@ -1406,10 +1406,11 @@ guint g_type_get_type_registration_serial (void); typedef struct { ParentName##Class parent_class; } ModuleObjName##Class; \ \ _GLIB_DEFINE_AUTOPTR_CHAINUP (ModuleObjName, ParentName) \ + G_DEFINE_AUTOPTR_CLEANUP_FUNC (ModuleObjName##Class, g_type_class_unref) \ \ - static inline ModuleObjName * MODULE##_##OBJ_NAME (gpointer ptr) { \ + G_GNUC_UNUSED static inline ModuleObjName * MODULE##_##OBJ_NAME (gpointer ptr) { \ return G_TYPE_CHECK_INSTANCE_CAST (ptr, module_obj_name##_get_type (), ModuleObjName); } \ - static inline gboolean MODULE##_IS_##OBJ_NAME (gpointer ptr) { \ + G_GNUC_UNUSED static inline gboolean MODULE##_IS_##OBJ_NAME (gpointer ptr) { \ return G_TYPE_CHECK_INSTANCE_TYPE (ptr, module_obj_name##_get_type ()); } \ G_GNUC_END_IGNORE_DEPRECATIONS @@ -1497,16 +1498,17 @@ guint g_type_get_type_registration_serial (void); struct _##ModuleObjName { ParentName parent_instance; }; \ \ _GLIB_DEFINE_AUTOPTR_CHAINUP (ModuleObjName, ParentName) \ + G_DEFINE_AUTOPTR_CLEANUP_FUNC (ModuleObjName##Class, g_type_class_unref) \ \ - static inline ModuleObjName * MODULE##_##OBJ_NAME (gpointer ptr) { \ + G_GNUC_UNUSED static inline ModuleObjName * MODULE##_##OBJ_NAME (gpointer ptr) { \ return G_TYPE_CHECK_INSTANCE_CAST (ptr, module_obj_name##_get_type (), ModuleObjName); } \ - static inline ModuleObjName##Class * MODULE##_##OBJ_NAME##_CLASS (gpointer ptr) { \ + G_GNUC_UNUSED static inline ModuleObjName##Class * MODULE##_##OBJ_NAME##_CLASS (gpointer ptr) { \ return G_TYPE_CHECK_CLASS_CAST (ptr, module_obj_name##_get_type (), ModuleObjName##Class); } \ - static inline gboolean MODULE##_IS_##OBJ_NAME (gpointer ptr) { \ + G_GNUC_UNUSED static inline gboolean MODULE##_IS_##OBJ_NAME (gpointer ptr) { \ return G_TYPE_CHECK_INSTANCE_TYPE (ptr, module_obj_name##_get_type ()); } \ - static inline gboolean MODULE##_IS_##OBJ_NAME##_CLASS (gpointer ptr) { \ + G_GNUC_UNUSED static inline gboolean MODULE##_IS_##OBJ_NAME##_CLASS (gpointer ptr) { \ return G_TYPE_CHECK_CLASS_TYPE (ptr, module_obj_name##_get_type ()); } \ - static inline ModuleObjName##Class * MODULE##_##OBJ_NAME##_GET_CLASS (gpointer ptr) { \ + G_GNUC_UNUSED static inline ModuleObjName##Class * MODULE##_##OBJ_NAME##_GET_CLASS (gpointer ptr) { \ return G_TYPE_INSTANCE_GET_CLASS (ptr, module_obj_name##_get_type (), ModuleObjName##Class); } \ G_GNUC_END_IGNORE_DEPRECATIONS @@ -1576,11 +1578,11 @@ guint g_type_get_type_registration_serial (void); \ _GLIB_DEFINE_AUTOPTR_CHAINUP (ModuleObjName, PrerequisiteName) \ \ - static inline ModuleObjName * MODULE##_##OBJ_NAME (gpointer ptr) { \ + G_GNUC_UNUSED static inline ModuleObjName * MODULE##_##OBJ_NAME (gpointer ptr) { \ return G_TYPE_CHECK_INSTANCE_CAST (ptr, module_obj_name##_get_type (), ModuleObjName); } \ - static inline gboolean MODULE##_IS_##OBJ_NAME (gpointer ptr) { \ + G_GNUC_UNUSED static inline gboolean MODULE##_IS_##OBJ_NAME (gpointer ptr) { \ return G_TYPE_CHECK_INSTANCE_TYPE (ptr, module_obj_name##_get_type ()); } \ - static inline ModuleObjName##Interface * MODULE##_##OBJ_NAME##_GET_IFACE (gpointer ptr) { \ + G_GNUC_UNUSED static inline ModuleObjName##Interface * MODULE##_##OBJ_NAME##_GET_IFACE (gpointer ptr) { \ return G_TYPE_INSTANCE_GET_INTERFACE (ptr, module_obj_name##_get_type (), ModuleObjName##Interface); } \ G_GNUC_END_IGNORE_DEPRECATIONS diff --git a/gobject/gvalue.c b/gobject/gvalue.c index 6d10f61a2..468da2e7d 100644 --- a/gobject/gvalue.c +++ b/gobject/gvalue.c @@ -376,7 +376,7 @@ g_value_set_instance (GValue *value, g_free (error_msg); /* we purposely leak the value here, it might not be - * in a sane state if an error condition occoured + * in a correct state if an error condition occurred */ value_meminit (value, g_type); value_table->value_init (value); @@ -440,7 +440,7 @@ g_value_init_from_instance (GValue *value, g_free (error_msg); /* we purposely leak the value here, it might not be - * in a sane state if an error condition occoured + * in a correct state if an error condition occurred */ value_meminit (value, g_type); value_table->value_init (value); diff --git a/gobject/tests/autoptr.c b/gobject/tests/autoptr.c index cf7687d84..ec3c89ebc 100644 --- a/gobject/tests/autoptr.c +++ b/gobject/tests/autoptr.c @@ -29,6 +29,18 @@ struct _TestAutoCleanupBaseClass { GObjectClass parent_class; }; +G_DEFINE_TYPE (TestAutoCleanupBase, test_base_auto_cleanup, G_TYPE_OBJECT) + +static void +test_base_auto_cleanup_class_init (TestAutoCleanupBaseClass *class) +{ +} + +static void +test_base_auto_cleanup_init (TestAutoCleanupBase *tac) +{ +} + G_DECLARE_FINAL_TYPE (TestAutoCleanup, test_auto_cleanup, TEST, AUTO_CLEANUP, TestAutoCleanupBase) struct _TestAutoCleanup @@ -65,6 +77,7 @@ test_autoptr (void) { g_autoptr (TestAutoCleanup) tac = tac_ptr; + g_assert_nonnull (tac); } #ifdef __GNUC__ g_assert_null (tac_ptr); @@ -113,6 +126,9 @@ test_autolist (void) l = g_list_prepend (l, tac1); l = g_list_prepend (l, tac2); + + /* Squash warnings about dead stores */ + (void) l; } /* Only assert if autoptr works */ @@ -192,6 +208,19 @@ test_autoqueue (void) g_assert_null (tac3); } +static void +test_autoclass (void) +{ + g_autoptr (TestAutoCleanupBaseClass) base_class_ptr = NULL; + g_autoptr (TestAutoCleanupClass) class_ptr = NULL; + + base_class_ptr = g_type_class_ref (test_base_auto_cleanup_get_type ()); + class_ptr = g_type_class_ref (test_auto_cleanup_get_type ()); + + g_assert_nonnull (base_class_ptr); + g_assert_nonnull (class_ptr); +} + int main (int argc, gchar *argv[]) { @@ -202,6 +231,7 @@ main (int argc, gchar *argv[]) g_test_add_func ("/autoptr/autolist", test_autolist); g_test_add_func ("/autoptr/autoslist", test_autoslist); g_test_add_func ("/autoptr/autoqueue", test_autoqueue); + g_test_add_func ("/autoptr/autoclass", test_autoclass); return g_test_run (); } diff --git a/gobject/tests/binding.c b/gobject/tests/binding.c index 019fb280e..1d3ead481 100644 --- a/gobject/tests/binding.c +++ b/gobject/tests/binding.c @@ -8,7 +8,7 @@ typedef struct _BindingSource gint foo; gint bar; - gdouble value; + gdouble double_value; gboolean toggle; } BindingSource; @@ -23,7 +23,7 @@ enum PROP_SOURCE_FOO, PROP_SOURCE_BAR, - PROP_SOURCE_VALUE, + PROP_SOURCE_DOUBLE_VALUE, PROP_SOURCE_TOGGLE }; @@ -48,8 +48,8 @@ binding_source_set_property (GObject *gobject, source->bar = g_value_get_int (value); break; - case PROP_SOURCE_VALUE: - source->value = g_value_get_double (value); + case PROP_SOURCE_DOUBLE_VALUE: + source->double_value = g_value_get_double (value); break; case PROP_SOURCE_TOGGLE: @@ -79,8 +79,8 @@ binding_source_get_property (GObject *gobject, g_value_set_int (value, source->bar); break; - case PROP_SOURCE_VALUE: - g_value_set_double (value, source->value); + case PROP_SOURCE_DOUBLE_VALUE: + g_value_set_double (value, source->double_value); break; case PROP_SOURCE_TOGGLE: @@ -110,8 +110,8 @@ binding_source_class_init (BindingSourceClass *klass) -1, 100, 0, G_PARAM_READWRITE)); - g_object_class_install_property (gobject_class, PROP_SOURCE_VALUE, - g_param_spec_double ("value", "Value", "Value", + g_object_class_install_property (gobject_class, PROP_SOURCE_DOUBLE_VALUE, + g_param_spec_double ("double-value", "Value", "Value", -100.0, 200.0, 0.0, G_PARAM_READWRITE)); @@ -131,7 +131,7 @@ typedef struct _BindingTarget GObject parent_instance; gint bar; - gdouble value; + gdouble double_value; gboolean toggle; } BindingTarget; @@ -145,7 +145,7 @@ enum PROP_TARGET_0, PROP_TARGET_BAR, - PROP_TARGET_VALUE, + PROP_TARGET_DOUBLE_VALUE, PROP_TARGET_TOGGLE }; @@ -166,8 +166,8 @@ binding_target_set_property (GObject *gobject, target->bar = g_value_get_int (value); break; - case PROP_TARGET_VALUE: - target->value = g_value_get_double (value); + case PROP_TARGET_DOUBLE_VALUE: + target->double_value = g_value_get_double (value); break; case PROP_TARGET_TOGGLE: @@ -193,8 +193,8 @@ binding_target_get_property (GObject *gobject, g_value_set_int (value, target->bar); break; - case PROP_TARGET_VALUE: - g_value_set_double (value, target->value); + case PROP_TARGET_DOUBLE_VALUE: + g_value_set_double (value, target->double_value); break; case PROP_TARGET_TOGGLE: @@ -219,8 +219,8 @@ binding_target_class_init (BindingTargetClass *klass) -1, 100, 0, G_PARAM_READWRITE)); - g_object_class_install_property (gobject_class, PROP_TARGET_VALUE, - g_param_spec_double ("value", "Value", "Value", + g_object_class_install_property (gobject_class, PROP_TARGET_DOUBLE_VALUE, + g_param_spec_double ("double-value", "Value", "Value", -100.0, 200.0, 0.0, G_PARAM_READWRITE)); @@ -243,8 +243,8 @@ celsius_to_fahrenheit (GBinding *binding, { gdouble celsius, fahrenheit; - g_assert (G_VALUE_HOLDS (from_value, G_TYPE_DOUBLE)); - g_assert (G_VALUE_HOLDS (to_value, G_TYPE_DOUBLE)); + g_assert_true (G_VALUE_HOLDS (from_value, G_TYPE_DOUBLE)); + g_assert_true (G_VALUE_HOLDS (to_value, G_TYPE_DOUBLE)); celsius = g_value_get_double (from_value); fahrenheit = (9 * celsius / 5) + 32.0; @@ -265,8 +265,8 @@ fahrenheit_to_celsius (GBinding *binding, { gdouble celsius, fahrenheit; - g_assert (G_VALUE_HOLDS (from_value, G_TYPE_DOUBLE)); - g_assert (G_VALUE_HOLDS (to_value, G_TYPE_DOUBLE)); + g_assert_true (G_VALUE_HOLDS (from_value, G_TYPE_DOUBLE)); + g_assert_true (G_VALUE_HOLDS (to_value, G_TYPE_DOUBLE)); fahrenheit = g_value_get_double (from_value); celsius = 5 * (fahrenheit - 32.0) / 9; @@ -291,8 +291,8 @@ binding_default (void) G_BINDING_DEFAULT); g_object_add_weak_pointer (G_OBJECT (binding), (gpointer *) &binding); - g_assert ((BindingSource *) g_binding_get_source (binding) == source); - g_assert ((BindingTarget *) g_binding_get_target (binding) == target); + g_assert_true ((BindingSource *) g_binding_get_source (binding) == source); + g_assert_true ((BindingTarget *) g_binding_get_target (binding) == target); g_assert_cmpstr (g_binding_get_source_property (binding), ==, "foo"); g_assert_cmpstr (g_binding_get_target_property (binding), ==, "bar"); g_assert_cmpint (g_binding_get_flags (binding), ==, G_BINDING_DEFAULT); @@ -310,7 +310,38 @@ binding_default (void) g_object_unref (source); g_object_unref (target); - g_assert (binding == NULL); + g_assert_null (binding); +} + +static void +binding_canonicalisation (void) +{ + BindingSource *source = g_object_new (binding_source_get_type (), NULL); + BindingTarget *target = g_object_new (binding_target_get_type (), NULL); + GBinding *binding; + + g_test_summary ("Test that bindings set up with non-canonical property names work"); + + binding = g_object_bind_property (source, "double_value", + target, "double_value", + G_BINDING_DEFAULT); + + g_object_add_weak_pointer (G_OBJECT (binding), (gpointer *) &binding); + g_assert_true ((BindingSource *) g_binding_get_source (binding) == source); + g_assert_true ((BindingTarget *) g_binding_get_target (binding) == target); + g_assert_cmpstr (g_binding_get_source_property (binding), ==, "double-value"); + g_assert_cmpstr (g_binding_get_target_property (binding), ==, "double-value"); + g_assert_cmpint (g_binding_get_flags (binding), ==, G_BINDING_DEFAULT); + + g_object_set (source, "double-value", 24.0, NULL); + g_assert_cmpfloat (target->double_value, ==, source->double_value); + + g_object_set (target, "double-value", 69.0, NULL); + g_assert_cmpfloat (source->double_value, !=, target->double_value); + + g_object_unref (target); + g_object_unref (source); + g_assert_null (binding); } static void @@ -338,7 +369,7 @@ binding_bidirectional (void) g_object_unref (source); g_object_unref (target); - g_assert (binding == NULL); + g_assert_null (binding); } static void @@ -360,7 +391,7 @@ binding_transform_default (void) GBindingFlags flags; binding = g_object_bind_property (source, "foo", - target, "value", + target, "double-value", G_BINDING_BIDIRECTIONAL); g_object_add_weak_pointer (G_OBJECT (binding), (gpointer *) &binding); @@ -372,10 +403,10 @@ binding_transform_default (void) "target-property", &trg_prop, "flags", &flags, NULL); - g_assert (src == source); - g_assert (trg == target); + g_assert_true (src == source); + g_assert_true (trg == target); g_assert_cmpstr (src_prop, ==, "foo"); - g_assert_cmpstr (trg_prop, ==, "value"); + g_assert_cmpstr (trg_prop, ==, "double-value"); g_assert_cmpint (flags, ==, G_BINDING_BIDIRECTIONAL); g_object_unref (src); g_object_unref (trg); @@ -383,14 +414,14 @@ binding_transform_default (void) g_free (trg_prop); g_object_set (source, "foo", 24, NULL); - g_assert_cmpfloat (target->value, ==, 24.0); + g_assert_cmpfloat (target->double_value, ==, 24.0); - g_object_set (target, "value", 69.0, NULL); + g_object_set (target, "double-value", 69.0, NULL); g_assert_cmpint (source->foo, ==, 69); g_object_unref (target); g_object_unref (source); - g_assert (binding == NULL); + g_assert_null (binding); } static void @@ -401,23 +432,23 @@ binding_transform (void) GBinding *binding G_GNUC_UNUSED; gboolean unused_data = FALSE; - binding = g_object_bind_property_full (source, "value", - target, "value", + binding = g_object_bind_property_full (source, "double-value", + target, "double-value", G_BINDING_BIDIRECTIONAL, celsius_to_fahrenheit, fahrenheit_to_celsius, &unused_data, data_free); - g_object_set (source, "value", 24.0, NULL); - g_assert_cmpfloat (target->value, ==, ((9 * 24.0 / 5) + 32.0)); + g_object_set (source, "double-value", 24.0, NULL); + g_assert_cmpfloat (target->double_value, ==, ((9 * 24.0 / 5) + 32.0)); - g_object_set (target, "value", 69.0, NULL); - g_assert_cmpfloat (source->value, ==, (5 * (69.0 - 32.0) / 9)); + g_object_set (target, "double-value", 69.0, NULL); + g_assert_cmpfloat (source->double_value, ==, (5 * (69.0 - 32.0) / 9)); g_object_unref (source); g_object_unref (target); - g_assert (unused_data); + g_assert_true (unused_data); } static void @@ -433,23 +464,23 @@ binding_transform_closure (void) f2c_clos = g_cclosure_new (G_CALLBACK (fahrenheit_to_celsius), &unused_data_2, (GClosureNotify) data_free); - binding = g_object_bind_property_with_closures (source, "value", - target, "value", + binding = g_object_bind_property_with_closures (source, "double-value", + target, "double-value", G_BINDING_BIDIRECTIONAL, c2f_clos, f2c_clos); - g_object_set (source, "value", 24.0, NULL); - g_assert_cmpfloat (target->value, ==, ((9 * 24.0 / 5) + 32.0)); + g_object_set (source, "double-value", 24.0, NULL); + g_assert_cmpfloat (target->double_value, ==, ((9 * 24.0 / 5) + 32.0)); - g_object_set (target, "value", 69.0, NULL); - g_assert_cmpfloat (source->value, ==, (5 * (69.0 - 32.0) / 9)); + g_object_set (target, "double-value", 69.0, NULL); + g_assert_cmpfloat (source->double_value, ==, (5 * (69.0 - 32.0) / 9)); g_object_unref (source); g_object_unref (target); - g_assert (unused_data_1); - g_assert (unused_data_2); + g_assert_true (unused_data_1); + g_assert_true (unused_data_2); } static void @@ -477,9 +508,9 @@ binding_chain (void) /* unbind A -> B and B -> C */ g_object_unref (binding_1); - g_assert (binding_1 == NULL); + g_assert_null (binding_1); g_object_unref (binding_2); - g_assert (binding_2 == NULL); + g_assert_null (binding_2); /* bind A -> C directly */ binding_2 = g_object_bind_property (a, "foo", c, "foo", G_BINDING_BIDIRECTIONAL); @@ -544,16 +575,16 @@ binding_invert_boolean (void) target, "toggle", G_BINDING_BIDIRECTIONAL | G_BINDING_INVERT_BOOLEAN); - g_assert (source->toggle); - g_assert (!target->toggle); + g_assert_true (source->toggle); + g_assert_false (target->toggle); g_object_set (source, "toggle", FALSE, NULL); - g_assert (!source->toggle); - g_assert (target->toggle); + g_assert_false (source->toggle); + g_assert_true (target->toggle); g_object_set (target, "toggle", FALSE, NULL); - g_assert (source->toggle); - g_assert (!target->toggle); + g_assert_true (source->toggle); + g_assert_false (target->toggle); g_object_unref (binding); g_object_unref (source); @@ -582,7 +613,7 @@ binding_same_object (void) g_assert_cmpint (source->bar, ==, 30); g_object_unref (source); - g_assert (binding == NULL); + g_assert_null (binding); } static void @@ -604,7 +635,7 @@ binding_unbind (void) g_assert_cmpint (source->foo, !=, target->bar); g_binding_unbind (binding); - g_assert (binding == NULL); + g_assert_null (binding); g_object_set (source, "foo", 0, NULL); g_assert_cmpint (source->foo, !=, target->bar); @@ -621,7 +652,7 @@ binding_unbind (void) g_object_add_weak_pointer (G_OBJECT (binding), (gpointer *) &binding); g_binding_unbind (binding); - g_assert (binding == NULL); + g_assert_null (binding); g_object_unref (source); } @@ -711,19 +742,19 @@ binding_fail (void) GBinding *binding; /* double -> boolean is not supported */ - binding = g_object_bind_property (source, "value", + binding = g_object_bind_property (source, "double-value", target, "toggle", G_BINDING_DEFAULT); g_object_add_weak_pointer (G_OBJECT (binding), (gpointer *) &binding); g_test_expect_message ("GLib-GObject", G_LOG_LEVEL_WARNING, "*Unable to convert*double*boolean*"); - g_object_set (source, "value", 1.0, NULL); + g_object_set (source, "double-value", 1.0, NULL); g_test_assert_expected_messages (); g_object_unref (source); g_object_unref (target); - g_assert (binding == NULL); + g_assert_null (binding); } int @@ -734,6 +765,7 @@ main (int argc, char *argv[]) g_test_bug_base ("https://gitlab.gnome.org/GNOME/glib/issues/"); g_test_add_func ("/binding/default", binding_default); + g_test_add_func ("/binding/canonicalisation", binding_canonicalisation); g_test_add_func ("/binding/bidirectional", binding_bidirectional); g_test_add_func ("/binding/transform", binding_transform); g_test_add_func ("/binding/transform-default", binding_transform_default); diff --git a/gobject/tests/meson.build b/gobject/tests/meson.build index 9c6a6e034..1d0ef4a53 100644 --- a/gobject/tests/meson.build +++ b/gobject/tests/meson.build @@ -50,6 +50,7 @@ gobject_tests = { 'signals' : { 'source' : ['signals.c', marshalers_h, marshalers_c], }, + 'testing' : {}, } if cc.get_id() != 'msvc' diff --git a/gobject/tests/param.c b/gobject/tests/param.c index 758289bf8..93c3f4b94 100644 --- a/gobject/tests/param.c +++ b/gobject/tests/param.c @@ -10,19 +10,19 @@ test_param_value (void) GValue value = G_VALUE_INIT; g_value_init (&value, G_TYPE_PARAM); - g_assert (G_VALUE_HOLDS_PARAM (&value)); + g_assert_true (G_VALUE_HOLDS_PARAM (&value)); p = g_param_spec_int ("my-int", "My Int", "Blurb", 0, 20, 10, G_PARAM_READWRITE); g_value_take_param (&value, p); p2 = g_value_get_param (&value); - g_assert (p2 == p); + g_assert_true (p2 == p); pp = g_param_spec_uint ("my-uint", "My UInt", "Blurb", 0, 10, 5, G_PARAM_READWRITE); g_value_set_param (&value, pp); p2 = g_value_dup_param (&value); - g_assert (p2 == pp); /* param specs use ref/unref for copy/free */ + g_assert_true (p2 == pp); /* param specs use ref/unref for copy/free */ g_param_spec_unref (p2); g_value_unset (&value); @@ -57,7 +57,7 @@ test_param_qdata (void) g_assert_cmpint (destroy_count, ==, 1); g_assert_cmpstr (g_param_spec_steal_qdata (p, q), ==, "blabla"); g_assert_cmpint (destroy_count, ==, 1); - g_assert (g_param_spec_get_qdata (p, q) == NULL); + g_assert_null (g_param_spec_get_qdata (p, q)); g_param_spec_ref_sink (p); @@ -74,12 +74,12 @@ test_param_validate (void) g_value_init (&value, G_TYPE_INT); g_value_set_int (&value, 100); - g_assert (!g_param_value_defaults (p, &value)); - g_assert (g_param_value_validate (p, &value)); + g_assert_false (g_param_value_defaults (p, &value)); + g_assert_true (g_param_value_validate (p, &value)); g_assert_cmpint (g_value_get_int (&value), ==, 20); g_param_value_set_default (p, &value); - g_assert (g_param_value_defaults (p, &value)); + g_assert_true (g_param_value_defaults (p, &value)); g_assert_cmpint (g_value_get_int (&value), ==, 10); g_param_spec_unref (p); @@ -91,9 +91,9 @@ test_param_strings (void) GParamSpec *p; /* test canonicalization */ - p = g_param_spec_int ("my_int:bla", "My Int", "Blurb", 0, 20, 10, G_PARAM_READWRITE); + p = g_param_spec_int ("my_int", "My Int", "Blurb", 0, 20, 10, G_PARAM_READWRITE); - g_assert_cmpstr (g_param_spec_get_name (p), ==, "my-int-bla"); + g_assert_cmpstr (g_param_spec_get_name (p), ==, "my-int"); g_assert_cmpstr (g_param_spec_get_nick (p), ==, "My Int"); g_assert_cmpstr (g_param_spec_get_blurb (p), ==, "Blurb"); @@ -104,12 +104,32 @@ test_param_strings (void) g_assert_cmpstr (g_param_spec_get_name (p), ==, "my-int"); g_assert_cmpstr (g_param_spec_get_nick (p), ==, "my-int"); - g_assert (g_param_spec_get_blurb (p) == NULL); + g_assert_null (g_param_spec_get_blurb (p)); g_param_spec_unref (p); } static void +test_param_invalid_name (gconstpointer test_data) +{ + const gchar *invalid_name = test_data; + + g_test_summary ("Test that properties cannot be created with invalid names"); + + if (g_test_subprocess ()) + { + GParamSpec *p; + p = g_param_spec_int (invalid_name, "My Int", "Blurb", 0, 20, 10, G_PARAM_READWRITE); + g_param_spec_unref (p); + return; + } + + g_test_trap_subprocess (NULL, 0, 0); + g_test_trap_assert_failed (); + g_test_trap_assert_stderr ("*CRITICAL*is_valid_property_name (name)*"); +} + +static void test_param_convert (void) { GParamSpec *p; @@ -123,10 +143,10 @@ test_param_convert (void) g_value_init (&v2, G_TYPE_INT); g_value_set_int (&v2, -4); - g_assert (!g_param_value_convert (p, &v1, &v2, TRUE)); + g_assert_false (g_param_value_convert (p, &v1, &v2, TRUE)); g_assert_cmpint (g_value_get_int (&v2), ==, -4); - g_assert (g_param_value_convert (p, &v1, &v2, FALSE)); + g_assert_true (g_param_value_convert (p, &v1, &v2, FALSE)); g_assert_cmpint (g_value_get_int (&v2), ==, 20); g_param_spec_unref (p); @@ -139,11 +159,11 @@ test_value_transform (void) GValue dest = G_VALUE_INIT; #define CHECK_INT_CONVERSION(type, getter, value) \ - g_assert (g_value_type_transformable (G_TYPE_INT, type)); \ + g_assert_true (g_value_type_transformable (G_TYPE_INT, type)); \ g_value_init (&src, G_TYPE_INT); \ g_value_init (&dest, type); \ g_value_set_int (&src, value); \ - g_assert (g_value_transform (&src, &dest)); \ + g_assert_true (g_value_transform (&src, &dest)); \ g_assert_cmpint (g_value_get_##getter (&dest), ==, value); \ g_value_unset (&src); \ g_value_unset (&dest); @@ -171,11 +191,11 @@ test_value_transform (void) CHECK_INT_CONVERSION(G_TYPE_DOUBLE, double, 12345678) #define CHECK_UINT_CONVERSION(type, getter, value) \ - g_assert (g_value_type_transformable (G_TYPE_UINT, type)); \ + g_assert_true (g_value_type_transformable (G_TYPE_UINT, type)); \ g_value_init (&src, G_TYPE_UINT); \ g_value_init (&dest, type); \ g_value_set_uint (&src, value); \ - g_assert (g_value_transform (&src, &dest)); \ + g_assert_true (g_value_transform (&src, &dest)); \ g_assert_cmpuint (g_value_get_##getter (&dest), ==, value); \ g_value_unset (&src); \ g_value_unset (&dest); @@ -196,11 +216,11 @@ test_value_transform (void) CHECK_UINT_CONVERSION(G_TYPE_DOUBLE, double, 12345678) #define CHECK_LONG_CONVERSION(type, getter, value) \ - g_assert (g_value_type_transformable (G_TYPE_LONG, type)); \ + g_assert_true (g_value_type_transformable (G_TYPE_LONG, type)); \ g_value_init (&src, G_TYPE_LONG); \ g_value_init (&dest, type); \ g_value_set_long (&src, value); \ - g_assert (g_value_transform (&src, &dest)); \ + g_assert_true (g_value_transform (&src, &dest)); \ g_assert_cmpint (g_value_get_##getter (&dest), ==, value); \ g_value_unset (&src); \ g_value_unset (&dest); @@ -221,11 +241,11 @@ test_value_transform (void) CHECK_LONG_CONVERSION(G_TYPE_DOUBLE, double, 12345678) #define CHECK_ULONG_CONVERSION(type, getter, value) \ - g_assert (g_value_type_transformable (G_TYPE_ULONG, type)); \ + g_assert_true (g_value_type_transformable (G_TYPE_ULONG, type)); \ g_value_init (&src, G_TYPE_ULONG); \ g_value_init (&dest, type); \ g_value_set_ulong (&src, value); \ - g_assert (g_value_transform (&src, &dest)); \ + g_assert_true (g_value_transform (&src, &dest)); \ g_assert_cmpuint (g_value_get_##getter (&dest), ==, value); \ g_value_unset (&src); \ g_value_unset (&dest); @@ -246,11 +266,11 @@ test_value_transform (void) CHECK_ULONG_CONVERSION(G_TYPE_DOUBLE, double, 12345678) #define CHECK_INT64_CONVERSION(type, getter, value) \ - g_assert (g_value_type_transformable (G_TYPE_INT64, type)); \ + g_assert_true (g_value_type_transformable (G_TYPE_INT64, type)); \ g_value_init (&src, G_TYPE_INT64); \ g_value_init (&dest, type); \ g_value_set_int64 (&src, value); \ - g_assert (g_value_transform (&src, &dest)); \ + g_assert_true (g_value_transform (&src, &dest)); \ g_assert_cmpint (g_value_get_##getter (&dest), ==, value); \ g_value_unset (&src); \ g_value_unset (&dest); @@ -271,11 +291,11 @@ test_value_transform (void) CHECK_INT64_CONVERSION(G_TYPE_DOUBLE, double, 12345678) #define CHECK_UINT64_CONVERSION(type, getter, value) \ - g_assert (g_value_type_transformable (G_TYPE_UINT64, type)); \ + g_assert_true (g_value_type_transformable (G_TYPE_UINT64, type)); \ g_value_init (&src, G_TYPE_UINT64); \ g_value_init (&dest, type); \ g_value_set_uint64 (&src, value); \ - g_assert (g_value_transform (&src, &dest)); \ + g_assert_true (g_value_transform (&src, &dest)); \ g_assert_cmpuint (g_value_get_##getter (&dest), ==, value); \ g_value_unset (&src); \ g_value_unset (&dest); @@ -296,11 +316,11 @@ test_value_transform (void) CHECK_UINT64_CONVERSION(G_TYPE_DOUBLE, double, 12345678) #define CHECK_FLOAT_CONVERSION(type, getter, value) \ - g_assert (g_value_type_transformable (G_TYPE_FLOAT, type)); \ + g_assert_true (g_value_type_transformable (G_TYPE_FLOAT, type)); \ g_value_init (&src, G_TYPE_FLOAT); \ g_value_init (&dest, type); \ g_value_set_float (&src, value); \ - g_assert (g_value_transform (&src, &dest)); \ + g_assert_true (g_value_transform (&src, &dest)); \ g_assert_cmpfloat (g_value_get_##getter (&dest), ==, value); \ g_value_unset (&src); \ g_value_unset (&dest); @@ -321,11 +341,11 @@ test_value_transform (void) CHECK_FLOAT_CONVERSION(G_TYPE_DOUBLE, double, 12345678) #define CHECK_DOUBLE_CONVERSION(type, getter, value) \ - g_assert (g_value_type_transformable (G_TYPE_DOUBLE, type)); \ + g_assert_true (g_value_type_transformable (G_TYPE_DOUBLE, type)); \ g_value_init (&src, G_TYPE_DOUBLE); \ g_value_init (&dest, type); \ g_value_set_double (&src, value); \ - g_assert (g_value_transform (&src, &dest)); \ + g_assert_true (g_value_transform (&src, &dest)); \ g_assert_cmpfloat (g_value_get_##getter (&dest), ==, value); \ g_value_unset (&src); \ g_value_unset (&dest); @@ -346,14 +366,14 @@ test_value_transform (void) CHECK_DOUBLE_CONVERSION(G_TYPE_DOUBLE, double, 12345678) #define CHECK_BOOLEAN_CONVERSION(type, setter, value) \ - g_assert (g_value_type_transformable (type, G_TYPE_BOOLEAN)); \ + g_assert_true (g_value_type_transformable (type, G_TYPE_BOOLEAN)); \ g_value_init (&src, type); \ g_value_init (&dest, G_TYPE_BOOLEAN); \ g_value_set_##setter (&src, value); \ - g_assert (g_value_transform (&src, &dest)); \ + g_assert_true (g_value_transform (&src, &dest)); \ g_assert_cmpint (g_value_get_boolean (&dest), ==, TRUE); \ g_value_set_##setter (&src, 0); \ - g_assert (g_value_transform (&src, &dest)); \ + g_assert_true (g_value_transform (&src, &dest)); \ g_assert_cmpint (g_value_get_boolean (&dest), ==, FALSE); \ g_value_unset (&src); \ g_value_unset (&dest); @@ -366,11 +386,11 @@ test_value_transform (void) CHECK_BOOLEAN_CONVERSION(G_TYPE_UINT64, uint64, 12345678) #define CHECK_STRING_CONVERSION(int_type, setter, int_value) \ - g_assert (g_value_type_transformable (int_type, G_TYPE_STRING)); \ + g_assert_true (g_value_type_transformable (int_type, G_TYPE_STRING)); \ g_value_init (&src, int_type); \ g_value_init (&dest, G_TYPE_STRING); \ g_value_set_##setter (&src, int_value); \ - g_assert (g_value_transform (&src, &dest)); \ + g_assert_true (g_value_transform (&src, &dest)); \ g_assert_cmpstr (g_value_get_string (&dest), ==, #int_value); \ g_value_unset (&src); \ g_value_unset (&dest); @@ -384,12 +404,12 @@ test_value_transform (void) CHECK_STRING_CONVERSION(G_TYPE_FLOAT, float, 0.500000) CHECK_STRING_CONVERSION(G_TYPE_DOUBLE, double, -1.234567) - g_assert (!g_value_type_transformable (G_TYPE_STRING, G_TYPE_CHAR)); + g_assert_false (g_value_type_transformable (G_TYPE_STRING, G_TYPE_CHAR)); g_value_init (&src, G_TYPE_STRING); g_value_init (&dest, G_TYPE_CHAR); g_value_set_static_string (&src, "bla"); g_value_set_schar (&dest, 'c'); - g_assert (!g_value_transform (&src, &dest)); + g_assert_false (g_value_transform (&src, &dest)); g_assert_cmpint (g_value_get_schar (&dest), ==, 'c'); g_value_unset (&src); g_value_unset (&dest); @@ -757,7 +777,7 @@ test_param_implement (void) { case 0: /* make sure the other table agrees */ - g_assert (valid_impl_types[change_this_type * 16 + change_this_flag][use_this_type] == 0); + g_assert_cmpint (valid_impl_types[change_this_type * 16 + change_this_flag][use_this_type], ==, 0); g_test_trap_assert_failed (); g_test_trap_assert_stderr ("*Interface property does not exist*"); continue; @@ -820,7 +840,7 @@ test_param_default (void) param = g_param_spec_int ("my-int", "My Int", "Blurb", 0, 20, 10, G_PARAM_READWRITE); def = g_param_spec_get_default_value (param); - g_assert (G_VALUE_HOLDS (def, G_TYPE_INT)); + g_assert_true (G_VALUE_HOLDS (def, G_TYPE_INT)); g_assert_cmpint (g_value_get_int (def), ==, 10); g_param_spec_unref (param); @@ -836,6 +856,9 @@ main (int argc, char *argv[]) g_test_add_func ("/param/value", test_param_value); g_test_add_func ("/param/strings", test_param_strings); + g_test_add_data_func ("/param/invalid-name/colon", "my_int:hello", test_param_invalid_name); + g_test_add_data_func ("/param/invalid-name/first-char", "7zip", test_param_invalid_name); + g_test_add_data_func ("/param/invalid-name/empty", "", test_param_invalid_name); g_test_add_func ("/param/qdata", test_param_qdata); g_test_add_func ("/param/validate", test_param_validate); g_test_add_func ("/param/convert", test_param_convert); diff --git a/gobject/tests/reference.c b/gobject/tests/reference.c index 9508ee741..c6f4d5127 100644 --- a/gobject/tests/reference.c +++ b/gobject/tests/reference.c @@ -218,6 +218,35 @@ test_set_function (void) } static void +test_set_derived_type (void) +{ + GBinding *obj = NULL; + GObject *o = NULL; + GBinding *b = NULL; + + g_test_summary ("Check that g_set_object() doesn’t give strict aliasing " + "warnings when used on types derived from GObject"); + + g_assert_false (g_set_object (&o, NULL)); + g_assert_null (o); + + g_assert_false (g_set_object (&b, NULL)); + g_assert_null (b); + + obj = g_object_new (my_object_get_type (), NULL); + + g_assert_true (g_set_object (&o, G_OBJECT (obj))); + g_assert_true (o == G_OBJECT (obj)); + + g_assert_true (g_set_object (&b, obj)); + g_assert_true (b == obj); + + g_object_unref (obj); + g_clear_object (&b); + g_clear_object (&o); +} + +static void toggle_cb (gpointer data, GObject *obj, gboolean is_last) { gboolean *b = data; @@ -774,6 +803,7 @@ main (int argc, char **argv) g_test_add_func ("/object/clear-function", test_clear_function); g_test_add_func ("/object/set", test_set); g_test_add_func ("/object/set-function", test_set_function); + g_test_add_func ("/object/set/derived-type", test_set_derived_type); g_test_add_func ("/object/value", test_object_value); g_test_add_func ("/object/initially-unowned", test_initially_unowned); g_test_add_func ("/object/weak-pointer", test_weak_pointer); diff --git a/gobject/tests/signals.c b/gobject/tests/signals.c index 44e3f6217..ae8bd9dc2 100644 --- a/gobject/tests/signals.c +++ b/gobject/tests/signals.c @@ -180,7 +180,16 @@ test_class_init (TestClass *klass) NULL, G_TYPE_NONE, 0); - simple2_id = g_signal_new ("simple-2", + g_signal_new ("simple-detailed", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, + 0, + NULL, NULL, + NULL, + G_TYPE_NONE, + 0); + /* Deliberately install this one in non-canonical form to check that’s handled correctly: */ + simple2_id = g_signal_new ("simple_2", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE, 0, @@ -455,16 +464,16 @@ test_variant_signal (void) v = g_variant_new_boolean (TRUE); g_variant_ref (v); - g_assert (g_variant_is_floating (v)); + g_assert_true (g_variant_is_floating (v)); g_signal_emit_by_name (test, "variant-changed-no-slot", v); - g_assert (!g_variant_is_floating (v)); + g_assert_false (g_variant_is_floating (v)); g_variant_unref (v); v = g_variant_new_boolean (TRUE); g_variant_ref (v); - g_assert (g_variant_is_floating (v)); + g_assert_true (g_variant_is_floating (v)); g_signal_emit_by_name (test, "variant-changed", v); - g_assert (!g_variant_is_floating (v)); + g_assert_false (g_variant_is_floating (v)); g_variant_unref (v); g_object_unref (test); @@ -485,7 +494,7 @@ on_generic_marshaller_1 (Test *obj, g_assert_cmpint (v_uchar, ==, 43); g_assert_cmpint (v_int, ==, 4096); g_assert_cmpint (v_long, ==, 8192); - g_assert (v_pointer == NULL); + g_assert_null (v_pointer); g_assert_cmpfloat (v_double, >, 0.0); g_assert_cmpfloat (v_double, <, 1.0); g_assert_cmpfloat (v_float, >, 5.0); @@ -754,7 +763,7 @@ custom_marshaller_callback (Test *test, { GSignalInvocationHint *ihint; - g_assert (hint != &dont_use_this); + g_assert_true (hint != &dont_use_this); ihint = g_signal_get_invocation_hint (test); @@ -801,7 +810,7 @@ all_types_handler (Test *test, int i, gboolean b, char c, guchar uc, guint ui, g g_assert_cmpstr (str, ==, "Test"); g_assert_cmpstr (g_param_spec_get_nick (param), ==, "nick"); g_assert_cmpstr (g_bytes_get_data (bytes, NULL), ==, "Blah"); - g_assert (ptr == &enum_type); + g_assert_true (ptr == &enum_type); g_assert_cmpuint (g_variant_get_uint16 (var), == , 99); g_assert_cmpint (i64, ==, G_MAXINT64 - 1234); g_assert_cmpuint (ui64, ==, G_MAXUINT64 - 123456); @@ -810,7 +819,7 @@ all_types_handler (Test *test, int i, gboolean b, char c, guchar uc, guint ui, g static void all_types_handler_cb (Test *test, int i, gboolean b, char c, guchar uc, guint ui, glong l, gulong ul, MyEnum e, guint f, float fl, double db, char *str, GParamSpec *param, GBytes *bytes, gpointer ptr, Test *obj, GVariant *var, gint64 i64, guint64 ui64, gpointer user_data) { - g_assert (user_data == &flags_type); + g_assert_true (user_data == &flags_type); all_types_handler (test, i, b, c, uc, ui, l, ul, e, f, fl, db, str, param, bytes, ptr, obj, var, i64, ui64); } @@ -1064,6 +1073,7 @@ test_introspection (void) gint i; const gchar *names[] = { "simple", + "simple-detailed", "simple-2", "generic-marshaller-1", "generic-marshaller-2", @@ -1091,15 +1101,15 @@ test_introspection (void) for (i = 0; i < n_ids; i++) { name = g_signal_name (ids[i]); - g_assert (in_set (name, names)); + g_assert_true (in_set (name, names)); } g_signal_query (simple_id, &query); g_assert_cmpuint (query.signal_id, ==, simple_id); g_assert_cmpstr (query.signal_name, ==, "simple"); - g_assert (query.itype == test_get_type ()); - g_assert (query.signal_flags == G_SIGNAL_RUN_LAST); - g_assert (query.return_type == G_TYPE_NONE); + g_assert_true (query.itype == test_get_type ()); + g_assert_cmpint (query.signal_flags, ==, G_SIGNAL_RUN_LAST); + g_assert_cmpint (query.return_type, ==, G_TYPE_NONE); g_assert_cmpuint (query.n_params, ==, 0); g_free (ids); @@ -1129,7 +1139,7 @@ test_block_handler (void) handler = g_signal_handler_find (test1, G_SIGNAL_MATCH_ID, simple_id, 0, NULL, NULL, NULL); - g_assert (handler == handler1); + g_assert_true (handler == handler1); g_assert_cmpint (count1, ==, 0); g_assert_cmpint (count2, ==, 0); @@ -1238,7 +1248,7 @@ test_signal_disconnect_wrong_object (void) g_test_assert_expected_messages (); /* it's still connected */ - g_assert (g_signal_handler_is_connected (object, signal_id)); + g_assert_true (g_signal_handler_is_connected (object, signal_id)); g_object_unref (object); g_object_unref (object2); @@ -1276,6 +1286,172 @@ test_clear_signal_handler (void) g_object_unref (test_obj); } +static void +test_lookup (void) +{ + GTypeClass *test_class; + guint signal_id, saved_signal_id; + + g_test_summary ("Test that g_signal_lookup() works with a variety of inputs."); + + test_class = g_type_class_ref (test_get_type ()); + + signal_id = g_signal_lookup ("all-types", test_get_type ()); + g_assert_cmpint (signal_id, !=, 0); + + saved_signal_id = signal_id; + + /* Try with a non-canonical name. */ + signal_id = g_signal_lookup ("all_types", test_get_type ()); + g_assert_cmpint (signal_id, ==, saved_signal_id); + + /* Looking up a non-existent signal should return nothing. */ + g_assert_cmpint (g_signal_lookup ("nope", test_get_type ()), ==, 0); + + g_type_class_unref (test_class); +} + +static void +test_lookup_invalid (void) +{ + g_test_summary ("Test that g_signal_lookup() emits a warning if looking up an invalid signal name."); + + if (g_test_subprocess ()) + { + GTypeClass *test_class; + guint signal_id; + + test_class = g_type_class_ref (test_get_type ()); + + signal_id = g_signal_lookup ("", test_get_type ()); + g_assert_cmpint (signal_id, ==, 0); + + g_type_class_unref (test_class); + return; + } + + g_test_trap_subprocess (NULL, 0, 0); + g_test_trap_assert_failed (); + g_test_trap_assert_stderr ("*WARNING*unable to look up invalid signal name*"); +} + +static void +test_parse_name (void) +{ + GTypeClass *test_class; + guint signal_id, saved_signal_id; + gboolean retval; + GQuark detail, saved_detail; + + g_test_summary ("Test that g_signal_parse_name() works with a variety of inputs."); + + test_class = g_type_class_ref (test_get_type ()); + + /* Simple test. */ + retval = g_signal_parse_name ("simple-detailed", test_get_type (), &signal_id, &detail, TRUE); + g_assert_true (retval); + g_assert_cmpint (signal_id, !=, 0); + g_assert_cmpint (detail, ==, 0); + + saved_signal_id = signal_id; + + /* Simple test with detail. */ + retval = g_signal_parse_name ("simple-detailed::a-detail", test_get_type (), &signal_id, &detail, TRUE); + g_assert_true (retval); + g_assert_cmpint (signal_id, ==, saved_signal_id); + g_assert_cmpint (detail, !=, 0); + + saved_detail = detail; + + /* Simple test with the same detail again. */ + retval = g_signal_parse_name ("simple-detailed::a-detail", test_get_type (), &signal_id, &detail, FALSE); + g_assert_true (retval); + g_assert_cmpint (signal_id, ==, saved_signal_id); + g_assert_cmpint (detail, ==, saved_detail); + + /* Simple test with a new detail. */ + retval = g_signal_parse_name ("simple-detailed::another-detail", test_get_type (), &signal_id, &detail, FALSE); + g_assert_true (retval); + g_assert_cmpint (signal_id, ==, saved_signal_id); + g_assert_cmpint (detail, ==, 0); /* we didn’t force the quark */ + + /* Canonicalisation shouldn’t affect the results. */ + retval = g_signal_parse_name ("simple_detailed::a-detail", test_get_type (), &signal_id, &detail, FALSE); + g_assert_true (retval); + g_assert_cmpint (signal_id, ==, saved_signal_id); + g_assert_cmpint (detail, ==, saved_detail); + + /* Details don’t have to look like property names. */ + retval = g_signal_parse_name ("simple-detailed::hello::world", test_get_type (), &signal_id, &detail, TRUE); + g_assert_true (retval); + g_assert_cmpint (signal_id, ==, saved_signal_id); + g_assert_cmpint (detail, !=, 0); + + /* Trying to parse a detail for a signal which isn’t %G_SIGNAL_DETAILED should fail. */ + retval = g_signal_parse_name ("all-types::a-detail", test_get_type (), &signal_id, &detail, FALSE); + g_assert_false (retval); + + g_type_class_unref (test_class); +} + +static void +test_parse_name_invalid (void) +{ + GTypeClass *test_class; + gsize i; + guint signal_id; + GQuark detail; + const gchar *vectors[] = + { + "", + "7zip", + "invalid:signal", + "simple-detailed::", + "simple-detailed:", + ":", + "::", + ":valid-detail", + "::valid-detail", + }; + + g_test_summary ("Test that g_signal_parse_name() ignores a variety of invalid inputs."); + + test_class = g_type_class_ref (test_get_type ()); + + for (i = 0; i < G_N_ELEMENTS (vectors); i++) + { + g_test_message ("Parser input: %s", vectors[i]); + g_assert_false (g_signal_parse_name (vectors[i], test_get_type (), &signal_id, &detail, TRUE)); + } + + g_type_class_unref (test_class); +} + +static void +test_signals_invalid_name (gconstpointer test_data) +{ + const gchar *signal_name = test_data; + + g_test_summary ("Check that g_signal_new() rejects invalid signal names."); + + if (g_test_subprocess ()) + { + g_signal_new (signal_name, + test_get_type (), + G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE, + 0, + NULL, NULL, + NULL, + G_TYPE_NONE, + 0); + return; + } + + g_test_trap_subprocess (NULL, 0, 0); + g_test_trap_assert_failed (); + g_test_trap_assert_stderr ("*CRITICAL*is_valid_signal_name (signal_name)*"); +} + /* --- */ int @@ -1302,6 +1478,13 @@ main (int argc, g_test_add_func ("/gobject/signals/invocation-hint", test_invocation_hint); g_test_add_func ("/gobject/signals/test-disconnection-wrong-object", test_signal_disconnect_wrong_object); g_test_add_func ("/gobject/signals/clear-signal-handler", test_clear_signal_handler); + g_test_add_func ("/gobject/signals/lookup", test_lookup); + g_test_add_func ("/gobject/signals/lookup/invalid", test_lookup_invalid); + g_test_add_func ("/gobject/signals/parse-name", test_parse_name); + g_test_add_func ("/gobject/signals/parse-name/invalid", test_parse_name_invalid); + g_test_add_data_func ("/gobject/signals/invalid-name/colon", "my_int:hello", test_signals_invalid_name); + g_test_add_data_func ("/gobject/signals/invalid-name/first-char", "7zip", test_signals_invalid_name); + g_test_add_data_func ("/gobject/signals/invalid-name/empty", "", test_signals_invalid_name); return g_test_run (); } diff --git a/gobject/tests/testing.c b/gobject/tests/testing.c new file mode 100644 index 000000000..5c7e663bf --- /dev/null +++ b/gobject/tests/testing.c @@ -0,0 +1,71 @@ +/* GLib testing framework examples and tests + * + * Copyright © 2019 Endless Mobile, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + * Author: Philip Withnall <withnall@endlessm.com> + */ + +#include "config.h" + +/* We want to distinguish between messages originating from libglib + * and messages originating from this program. + */ +#undef G_LOG_DOMAIN +#define G_LOG_DOMAIN "testing" + +#include <glib.h> +#include <glib-object.h> +#include <locale.h> +#include <stdlib.h> + +static void +test_assert_finalize_object_subprocess_bad (void) +{ + GObject *obj = g_object_new (G_TYPE_OBJECT, NULL); + g_object_ref (obj); + + /* This should emit an assertion failure. */ + g_assert_finalize_object (obj); + + g_object_unref (obj); + + exit (0); +} + +static void +test_assert_finalize_object (void) +{ + GObject *obj = g_object_new (G_TYPE_OBJECT, NULL); + + g_assert_finalize_object (obj); + + g_test_trap_subprocess ("/assert/finalize_object/subprocess/bad", 0, 0); + g_test_trap_assert_failed (); + g_test_trap_assert_stderr ("*g_assert_finalize_object:*'weak_pointer' should be NULL*"); +} + +int +main (int argc, + char *argv[]) +{ + g_test_init (&argc, &argv, NULL); + + g_test_add_func ("/assert/finalize_object", test_assert_finalize_object); + g_test_add_func ("/assert/finalize_object/subprocess/bad", + test_assert_finalize_object_subprocess_bad); + + return g_test_run (); +} |