diff --git a/docs/reference/gobject/glib-mkenums.xml b/docs/reference/gobject/glib-mkenums.xml index ce250a3ff..29709853c 100644 --- a/docs/reference/gobject/glib-mkenums.xml +++ b/docs/reference/gobject/glib-mkenums.xml @@ -44,6 +44,12 @@ input. The options specified control the text that generated, substituting vario keywords enclosed in @ characters in the templates. +Since version 2.74, GLib provides the G_DEFINE_ENUM_TYPE +and G_DEFINE_FLAGS_TYPE C pre-processor macros. These macros +can be used to define a GType for projects that have few, small enumeration +types without going through the complexities of generating code at build +time. + Production text substitutions Certain keywords enclosed in @ characters will be substituted in the diff --git a/docs/reference/gobject/gobject-sections.txt b/docs/reference/gobject/gobject-sections.txt index dc1c89e3e..4107f8356 100644 --- a/docs/reference/gobject/gobject-sections.txt +++ b/docs/reference/gobject/gobject-sections.txt @@ -129,6 +129,9 @@ G_DEFINE_BOXED_TYPE G_DEFINE_BOXED_TYPE_WITH_CODE G_DEFINE_POINTER_TYPE G_DEFINE_POINTER_TYPE_WITH_CODE +G_DEFINE_ENUM_VALUE +G_DEFINE_ENUM_TYPE +G_DEFINE_FLAGS_TYPE G_TYPE_FUNDAMENTAL_SHIFT diff --git a/gobject/genums.h b/gobject/genums.h index c66ce45c0..e54253c20 100644 --- a/gobject/genums.h +++ b/gobject/genums.h @@ -274,6 +274,106 @@ void g_flags_complete_type_info (GType g_flags_type, GTypeInfo *info, const GFlagsValue *const_values); +/* {{{ Macros */ + +/** + * G_DEFINE_ENUM_VALUE: + * @EnumValue: an enumeration value + * @EnumNick: a short string representing the enumeration value + * + * Defines an enumeration value, and maps it to a "nickname". + * + * This macro can only be used with G_DEFINE_ENUM_TYPE() and + * G_DEFINE_FLAGS_TYPE(). + * + * Since: 2.74 + */ +#define G_DEFINE_ENUM_VALUE(EnumValue, EnumNick) \ + { EnumValue, #EnumValue, EnumNick } \ + GLIB_AVAILABLE_MACRO_IN_2_74 + +/** + * G_DEFINE_ENUM_TYPE: + * @TypeName: the enumeration type, in `CamelCase` + * @type_name: the enumeration type prefixed, in `snake_case` + * @...: a list of enumeration values, defined using G_DEFINE_ENUM_VALUE() + * + * A convenience macro for defining enumeration types. + * + * This macro will generate a `*_get_type()` function for the + * given @TypeName, using @type_name as the function prefix. + * + * |[ + * G_DEFINE_ENUM_TYPE (GtkOrientation, gtk_orientation, + * G_DEFINE_ENUM_VALUE (GTK_ORIENTATION_HORIZONTAL, "horizontal"), + * G_DEFINE_ENUM_VALUE (GTK_ORIENTATION_VERTICAL, "vertical")) + * ]| + * + * For projects that have multiple enumeration types, or enumeration + * types with many values, you should consider using glib-mkenums to + * generate the type function. + * + * Since: 2.74 + */ +#define G_DEFINE_ENUM_TYPE(TypeName, type_name, ...) \ +GType \ +type_name ## _get_type (void) { \ + static gsize g_define_type__static = 0; \ + if (g_once_init_enter (&g_define_type__static)) { \ + static const GEnumValue enum_values[] = { \ + __VA_ARGS__ , \ + { 0, NULL, NULL }, \ + }; \ + GType g_define_type = g_enum_register_static (g_intern_static_string (#TypeName), enum_values); \ + g_once_init_leave (&g_define_type__static, g_define_type); \ + } \ + return g_define_type__static; \ +} \ + GLIB_AVAILABLE_MACRO_IN_2_74 + +/** + * G_DEFINE_FLAGS_TYPE: + * @TypeName: the enumeration type, in `CamelCase` + * @type_name: the enumeration type prefixed, in `snake_case` + * @...: a list of enumeration values, defined using G_DEFINE_ENUM_VALUE() + * + * A convenience macro for defining flag types. + * + * This macro will generate a `*_get_type()` function for the + * given @TypeName, using @type_name as the function prefix. + * + * |[ + * G_DEFINE_FLAGS_TYPE (GSettingsBindFlags, g_settings_bind_flags, + * G_DEFINE_ENUM_VALUE (G_SETTINGS_BIND_DEFAULT, "default"), + * G_DEFINE_ENUM_VALUE (G_SETTINGS_BIND_GET, "get"), + * G_DEFINE_ENUM_VALUE (G_SETTINGS_BIND_SET, "set"), + * G_DEFINE_ENUM_VALUE (G_SETTINGS_BIND_NO_SENSITIVITY, "no-sensitivity"), + * G_DEFINE_ENUM_VALUE (G_SETTINGS_BIND_GET_NO_CHANGES, "get-no-changes"), + * G_DEFINE_ENUM_VALUE (G_SETTINGS_BIND_INVERT_BOOLEAN, "invert-boolean")) + * ]| + * + * For projects that have multiple enumeration types, or enumeration + * types with many values, you should consider using glib-mkenums to + * generate the type function. + * + * Since: 2.74 + */ +#define G_DEFINE_FLAGS_TYPE(TypeName, type_name, ...) \ +GType \ +type_name ## _get_type (void) { \ + static gsize g_define_type__static = 0; \ + if (g_once_init_enter (&g_define_type__static)) { \ + static const GFlagsValue flags_values[] = { \ + __VA_ARGS__ , \ + { 0, NULL, NULL }, \ + }; \ + GType g_define_type = g_flags_register_static (g_intern_static_string (#TypeName), flags_values); \ + g_once_init_leave (&g_define_type__static, g_define_type); \ + } \ + return g_define_type__static; \ +} \ + GLIB_AVAILABLE_MACRO_IN_2_74 + G_END_DECLS #endif /* __G_ENUMS_H__ */ diff --git a/gobject/tests/enums.c b/gobject/tests/enums.c index 3b9641790..9ec1666d0 100644 --- a/gobject/tests/enums.c +++ b/gobject/tests/enums.c @@ -20,7 +20,7 @@ test_enum_basic (void) type = g_enum_register_static ("MyEnum", my_enum_values); g_value_init (&value, type); - g_assert (G_VALUE_HOLDS_ENUM (&value)); + g_assert_true (G_VALUE_HOLDS_ENUM (&value)); g_value_set_enum (&value, 2); g_assert_cmpint (g_value_get_enum (&value), ==, 2); @@ -33,22 +33,22 @@ test_enum_basic (void) g_assert_cmpint (class->n_values, ==, 3); val = g_enum_get_value (class, 2); - g_assert (val != NULL); + g_assert_nonnull (val); g_assert_cmpstr (val->value_name, ==, "the second value"); val = g_enum_get_value (class, 15); - g_assert (val == NULL); + g_assert_null (val); val = g_enum_get_value_by_name (class, "the third value"); - g_assert (val != NULL); + g_assert_nonnull (val); g_assert_cmpint (val->value, ==, 3); val = g_enum_get_value_by_name (class, "the color purple"); - g_assert (val == NULL); + g_assert_null (val); val = g_enum_get_value_by_nick (class, "one"); - g_assert (val != NULL); + g_assert_nonnull (val); g_assert_cmpint (val->value, ==, 1); val = g_enum_get_value_by_nick (class, "purple"); - g_assert (val == NULL); + g_assert_null (val); to_string = g_enum_to_string (type, 2); g_assert_cmpstr (to_string, ==, "the second value"); @@ -100,7 +100,7 @@ test_flags_basic (void) no_default_flag_values); g_value_init (&value, type); - g_assert (G_VALUE_HOLDS_FLAGS (&value)); + g_assert_true (G_VALUE_HOLDS_FLAGS (&value)); g_value_set_flags (&value, 2|8); g_assert_cmpint (g_value_get_flags (&value), ==, 2|8); @@ -111,22 +111,22 @@ test_flags_basic (void) g_assert_cmpint (class->n_values, ==, 4); val = g_flags_get_first_value (class, 2|8); - g_assert (val != NULL); + g_assert_nonnull (val); g_assert_cmpstr (val->value_name, ==, "the second flag"); val = g_flags_get_first_value (class, 16); - g_assert (val == NULL); + g_assert_null (val); val = g_flags_get_value_by_name (class, "the third flag"); - g_assert (val != NULL); + g_assert_nonnull (val); g_assert_cmpint (val->value, ==, 8); val = g_flags_get_value_by_name (class, "the color purple"); - g_assert (val == NULL); + g_assert_null (val); val = g_flags_get_value_by_nick (class, "one"); - g_assert (val != NULL); + g_assert_nonnull (val); g_assert_cmpint (val->value, ==, 1); val = g_flags_get_value_by_nick (class, "purple"); - g_assert (val == NULL); + g_assert_null (val); test_flags_transform_to_string (&value); g_value_unset (&value); @@ -158,13 +158,86 @@ test_flags_basic (void) g_type_class_unref (class); } +typedef enum { + TEST_ENUM_FIRST_VALUE, + TEST_ENUM_SECOND_VALUE, + TEST_ENUM_THIRD_VALUE +} TestEnum; + +GType test_enum_get_type (void); + +G_DEFINE_ENUM_TYPE (TestEnum, test_enum, + G_DEFINE_ENUM_VALUE (TEST_ENUM_FIRST_VALUE, "first-value"), + G_DEFINE_ENUM_VALUE (TEST_ENUM_SECOND_VALUE, "second-value"), + G_DEFINE_ENUM_VALUE (TEST_ENUM_THIRD_VALUE, "third-value")) + +static void +test_enum_define_type (void) +{ + GEnumClass *class = g_type_class_ref (test_enum_get_type ()); + GEnumValue *val; + + g_assert_cmpint (class->minimum, ==, 0); + g_assert_cmpint (class->maximum, ==, 2); + g_assert_cmpint (class->n_values, ==, 3); + + val = g_enum_get_value (class, 2); + g_assert_nonnull (val); + g_assert_cmpstr (val->value_nick, ==, "third-value"); + val = g_enum_get_value (class, 15); + g_assert_null (val); + + g_type_class_unref (class); +} + +typedef enum { + TEST_FLAGS_DEFAULT = 0, + TEST_FLAGS_FIRST = 1 << 0, + TEST_FLAGS_SECOND = 1 << 1, + TEST_FLAGS_THIRD = 1 << 2 +} TestFlags; + +GType test_flags_get_type (void); + +G_DEFINE_FLAGS_TYPE (TestFlags, test_flags, + G_DEFINE_ENUM_VALUE (TEST_FLAGS_DEFAULT, "default"), + G_DEFINE_ENUM_VALUE (TEST_FLAGS_FIRST, "first"), + G_DEFINE_ENUM_VALUE (TEST_FLAGS_SECOND, "second"), + G_DEFINE_ENUM_VALUE (TEST_FLAGS_THIRD, "third")) + +static void +test_flags_define_type (void) +{ + GFlagsClass *class = g_type_class_ref (test_flags_get_type ()); + GFlagsValue *val; + char *to_string; + + g_assert_cmpint (class->mask, ==, 1 | 2 | 4); + g_assert_cmpint (class->n_values, ==, 4); + + val = g_flags_get_first_value (class, 2|4); + g_assert_nonnull (val); + g_assert_cmpstr (val->value_nick, ==, "second"); + + val = g_flags_get_first_value (class, 8); + g_assert_null (val); + + to_string = g_flags_to_string (test_flags_get_type (), 0); + g_assert_cmpstr (to_string, ==, "TEST_FLAGS_DEFAULT"); + g_free (to_string); + + g_type_class_unref (class); +} + int main (int argc, char *argv[]) { g_test_init (&argc, &argv, NULL); g_test_add_func ("/enum/basic", test_enum_basic); + g_test_add_func ("/enum/define-type", test_enum_define_type); g_test_add_func ("/flags/basic", test_flags_basic); + g_test_add_func ("/flags/define-type", test_flags_define_type); return g_test_run (); }