[perl-Glib-Object-Introspection] Register unregistered enums
- From: Torsten Schönfeld <tsch src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [perl-Glib-Object-Introspection] Register unregistered enums
- Date: Mon, 2 Dec 2013 21:29:20 +0000 (UTC)
commit f463b9eeca4d6edb862e1ac3edb1b97e4a7bd80f
Author: Torsten Schönfeld <kaffeetisch gmx de>
Date: Mon Dec 2 22:21:41 2013 +0100
Register unregistered enums
Using the introspection information, create a custom GType for unregistered
enums/flags and register it with perl-Glib.
Relevant for, e.g., GSpawnFlags and VtePtyFlags.
GObjectIntrospection.xs | 20 ++++++++++++-
MANIFEST | 1 +
NEWS | 6 ++++
gperl-i11n-enums.c | 51 ++++++++++++++++++++++++++++++++++
gperl-i11n-info.c | 59 +++++++++++++++++++++++++++++-----------
gperl-i11n-marshal-interface.c | 16 +++++++++++
t/enums.t | 10 ++++++-
7 files changed, 144 insertions(+), 19 deletions(-)
---
diff --git a/GObjectIntrospection.xs b/GObjectIntrospection.xs
index 69f60f1..4ba39da 100644
--- a/GObjectIntrospection.xs
+++ b/GObjectIntrospection.xs
@@ -172,7 +172,11 @@ static GIFieldInfo * get_field_info (GIBaseInfo *info,
const gchar *field_name);
static GISignalInfo * get_signal_info (GIBaseInfo *container_info,
const gchar *signal_name);
+
+static gchar * sythesize_gtype_name (GIBaseInfo *info);
+static gchar * sythesize_prefixed_gtype_name (GIBaseInfo *info);
static GType get_gtype (GIRegisteredTypeInfo *info);
+
static const gchar * get_package_for_basename (const gchar *basename);
static gboolean is_forbidden_sub_name (const gchar *name);
@@ -231,6 +235,9 @@ static gsize size_of_type_tag (GITypeTag type_tag);
static gsize size_of_interface (GITypeInfo *type_info);
static gsize size_of_type_info (GITypeInfo *type_info);
+/* enums/flags */
+static GType register_unregistered_enum (GIEnumInfo *info);
+
/* fields */
static void store_fields (HV *fields, GIBaseInfo *info, GIInfoType info_type);
static SV * get_field (GIFieldInfo *field_info, gpointer mem, GITransfer transfer);
@@ -273,6 +280,7 @@ static void call_carp_carp (const char *msg);
#include "gperl-i11n-callback.c"
#include "gperl-i11n-croak.c"
+#include "gperl-i11n-enums.c"
#include "gperl-i11n-field.c"
#include "gperl-i11n-gvalue.c"
#include "gperl-i11n-info.c"
@@ -410,8 +418,16 @@ _register_types (class, namespace, package)
namespace, name);
}
if (type == G_TYPE_NONE) {
- g_base_info_unref ((GIBaseInfo *) info);
- continue;
+ /* Try registering unregistered enums/flags. */
+ if (info_type == GI_INFO_TYPE_ENUM || info_type == GI_INFO_TYPE_FLAGS) {
+ type = register_unregistered_enum (info);
+ }
+ /* If there is still no GType, stop this iteration and
+ * go to the next item. */
+ if (!type || type == G_TYPE_NONE) {
+ g_base_info_unref ((GIBaseInfo *) info);
+ continue;
+ }
}
full_package = g_strconcat (package, "::", name, NULL);
diff --git a/MANIFEST b/MANIFEST
index e3a7515..a21311f 100644
--- a/MANIFEST
+++ b/MANIFEST
@@ -1,6 +1,7 @@
GObjectIntrospection.xs
gperl-i11n-callback.c
gperl-i11n-croak.c
+gperl-i11n-enums.c
gperl-i11n-field.c
gperl-i11n-gvalue.c
gperl-i11n-info.c
diff --git a/NEWS b/NEWS
index ce1a142..2268c74 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,9 @@
+Overview of changes in Glib::Object::Introspection <next>
+========================================================
+
+* Register unregistered enums so that, e.g., GSpawnFlags and VtePtyFlags become
+ usable.
+
Overview of changes in Glib::Object::Introspection 0.016
========================================================
diff --git a/gperl-i11n-enums.c b/gperl-i11n-enums.c
new file mode 100644
index 0000000..0a471ef
--- /dev/null
+++ b/gperl-i11n-enums.c
@@ -0,0 +1,51 @@
+/* -*- mode: c; indent-tabs-mode: t; c-basic-offset: 8; -*- */
+
+#define FILL_VALUES(values) \
+ for (i = 0; i < n_values; i++) { \
+ GIValueInfo *value_info = g_enum_info_get_value (info, i); \
+ (values)[i].value = g_value_info_get_value (value_info); \
+ /* FIXME: Can we assume that the strings will stick around long enough? */ \
+ (values)[i].value_nick = g_base_info_get_name (value_info); \
+ (values)[i].value_name = g_base_info_get_attribute (value_info, "c:identifier"); \
+ if (!(values)[i].value_name) \
+ (values)[i].value_name = (values)[i].value_nick; \
+ g_base_info_unref (value_info); \
+ }
+
+static GType
+register_unregistered_enum (GIEnumInfo *info)
+{
+ GType gtype = G_TYPE_NONE;
+ gchar *full_name;
+ GIInfoType info_type;
+ void *values;
+
+ /* Abort if there already is a GType under this name. */
+ full_name = sythesize_prefixed_gtype_name (info);
+ if (g_type_from_name (full_name)) {
+ g_free (full_name);
+ return gtype;
+ }
+
+ /* We have to leak enum_values as g_enum_register_static and
+ * g_flags_register_static assume that what we pass in will be valid
+ * throughout the lifetime of the program. */
+ gint i, n_values = g_enum_info_get_n_values (info);
+ if (info_type == GI_INFO_TYPE_ENUM) {
+ values = g_new0 (GEnumValue, n_values+1); /* zero-terminated */
+ FILL_VALUES ((GEnumValue *) values);
+ } else {
+ values = g_new0 (GFlagsValue, n_values+1); /* zero-terminated */
+ FILL_VALUES ((GFlagsValue *) values);
+ }
+
+ info_type = g_base_info_get_type(info);
+ if (info_type == GI_INFO_TYPE_ENUM) {
+ gtype = g_enum_register_static (full_name, (GEnumValue *) values);
+ } else {
+ gtype = g_flags_register_static (full_name, (GFlagsValue *) values);
+ }
+
+ g_free (full_name);
+ return gtype;
+}
diff --git a/gperl-i11n-info.c b/gperl-i11n-info.c
index 2a4926a..922a8f4 100644
--- a/gperl-i11n-info.c
+++ b/gperl-i11n-info.c
@@ -164,31 +164,58 @@ get_signal_info (GIBaseInfo *container_info, const gchar *signal_name)
return NULL;
}
+/* Caller owns return value. */
+static gchar *
+sythesize_gtype_name (GIBaseInfo *info)
+{
+ const gchar *namespace = g_base_info_get_namespace (info);
+ const gchar *name = g_base_info_get_name (info);
+ if (0 == strncmp (namespace, "GObject", 8) ||
+ 0 == strncmp (namespace, "GLib", 4))
+ {
+ namespace = "G";
+ }
+ return g_strconcat (namespace, name, NULL);
+}
+
+/* Caller owns return value. */
+static gchar *
+sythesize_prefixed_gtype_name (GIBaseInfo *info)
+{
+ const gchar *namespace = g_base_info_get_namespace (info);
+ const gchar *name = g_base_info_get_name (info);
+ if (0 == strncmp (namespace, "GObject", 8) ||
+ 0 == strncmp (namespace, "GLib", 4))
+ {
+ namespace = "G";
+ }
+ return g_strconcat ("GPerlI11n", namespace, name, NULL);
+}
+
static GType
get_gtype (GIRegisteredTypeInfo *info)
{
GType gtype = g_registered_type_info_get_g_type (info);
- if (gtype == G_TYPE_NONE) {
- /* Fall back to the registered type name, and if that doesn't
- * work either, construct the full name and try that. */
+ /* Fall back to the registered type name, and if that doesn't work
+ * either, construct the full name and the prefixed full name and try
+ * them. */
+ if (!gtype || gtype == G_TYPE_NONE) {
const gchar *type_name = g_registered_type_info_get_type_name (info);
if (type_name) {
gtype = g_type_from_name (type_name);
- return gtype ? gtype : G_TYPE_NONE;
- } else {
- gchar *full_name;
- const gchar *namespace = g_base_info_get_namespace (info);
- const gchar *name = g_base_info_get_name (info);
- if (0 == strncmp (namespace, "GObject", 8)) {
- namespace = "G";
- }
- full_name = g_strconcat (namespace, name, NULL);
- gtype = g_type_from_name (full_name);
- g_free (full_name);
- return gtype ? gtype : G_TYPE_NONE;
}
}
- return gtype;
+ if (!gtype || gtype == G_TYPE_NONE) {
+ gchar *full_name = sythesize_gtype_name (info);
+ gtype = g_type_from_name (full_name);
+ g_free (full_name);
+ }
+ if (!gtype || gtype == G_TYPE_NONE) {
+ gchar *full_name = sythesize_prefixed_gtype_name (info);
+ gtype = g_type_from_name (full_name);
+ g_free (full_name);
+ }
+ return gtype ? gtype : G_TYPE_NONE;
}
static const gchar *
diff --git a/gperl-i11n-marshal-interface.c b/gperl-i11n-marshal-interface.c
index 517bfee..614841f 100644
--- a/gperl-i11n-marshal-interface.c
+++ b/gperl-i11n-marshal-interface.c
@@ -227,6 +227,10 @@ sv_to_interface (GIArgInfo * arg_info,
case GI_INFO_TYPE_ENUM:
{
GType type = get_gtype ((GIRegisteredTypeInfo *) interface);
+ if (G_TYPE_NONE == type) {
+ ccroak ("Could not handle unknown enum type %s",
+ g_base_info_get_name (interface));
+ }
/* FIXME: Check storage type? */
arg->v_long = gperl_convert_enum (type, sv);
break;
@@ -235,6 +239,10 @@ sv_to_interface (GIArgInfo * arg_info,
case GI_INFO_TYPE_FLAGS:
{
GType type = get_gtype ((GIRegisteredTypeInfo *) interface);
+ if (G_TYPE_NONE == type) {
+ ccroak ("Could not handle unknown flags type %s",
+ g_base_info_get_name (interface));
+ }
/* FIXME: Check storage type? */
arg->v_long = gperl_convert_flags (type, sv);
break;
@@ -305,6 +313,10 @@ interface_to_sv (GITypeInfo* info, GIArgument *arg, gboolean own, GPerlI11nInvoc
case GI_INFO_TYPE_ENUM:
{
GType type = get_gtype ((GIRegisteredTypeInfo *) interface);
+ if (G_TYPE_NONE == type) {
+ ccroak ("Could not handle unknown enum type %s",
+ g_base_info_get_name (interface));
+ }
/* FIXME: Is it right to just use v_long here? */
sv = gperl_convert_back_enum (type, arg->v_long);
break;
@@ -313,6 +325,10 @@ interface_to_sv (GITypeInfo* info, GIArgument *arg, gboolean own, GPerlI11nInvoc
case GI_INFO_TYPE_FLAGS:
{
GType type = get_gtype ((GIRegisteredTypeInfo *) interface);
+ if (G_TYPE_NONE == type) {
+ ccroak ("Could not handle unknown flags type %s",
+ g_base_info_get_name (interface));
+ }
/* FIXME: Is it right to just use v_long here? */
sv = gperl_convert_back_flags (type, arg->v_long);
break;
diff --git a/t/enums.t b/t/enums.t
index b412800..e5cecdd 100644
--- a/t/enums.t
+++ b/t/enums.t
@@ -5,8 +5,16 @@ BEGIN { require './t/inc/setup.pl' };
use strict;
use warnings;
-plan tests => 3;
+plan tests => 4;
is (Regress::test_enum_param ('value1'), 'value1');
is (Regress::test_unsigned_enum_param ('value2'), 'value2');
ok (Regress::global_get_flags_out () == ['flag1', 'flag3']);
+
+SKIP: {
+ skip 'non-GType flags tests', 1
+ unless (check_gi_version (0, 10, 3));
+
+ GI::no_type_flags_in ([qw/value2/]);
+ is (GI::no_type_flags_returnv (), [qw/value2/]);
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]