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 ();
}