/*
 * This file was generated automatically by ExtUtils::ParseXS version 3.28 from the
 * contents of GObject.xs. Do not edit this file, edit GObject.xs instead.
 *
 *    ANY CHANGES MADE HERE WILL BE LOST!
 *
 */

#line 1 "GObject.xs"
/*
 * Copyright (C) 2003-2006, 2010, 2012-2013 by the gtk2-perl team (see the
 * file AUTHORS for the full list)
 *
 * This library is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Library 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 Library General Public
 * License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * $Id$
 */

/*
 * the POD directives in here will be stripped by xsubpp before compilation,
 * and are intended to be extracted by podselect when creating xs api
 * reference documentation.  pod must NOT appear within C comments, because
 * it gets replaced by a comment that says "embedded pod stripped".
 */

#if 0
  "Skipped embedded POD."
#endif
#line 53 "GObject.xs"

#include "gperl.h"
#include "gperl-private.h" /* for GPERL_SET_CONTEXT and
	                    * _gperl_sv_from_value_internal */

typedef struct _ClassInfo ClassInfo;
typedef struct _SinkFunc  SinkFunc;

struct _ClassInfo {
	GType   gtype;
	char  * package;
	gboolean initialized;
};

struct _SinkFunc {
	GType               gtype;
	GPerlObjectSinkFunc func;
};

static GHashTable * types_by_type    = NULL;
static GHashTable * types_by_package = NULL;

/* store outside of the class info maps any options we expect to be sparse;
 * this will save us a fair amount of space. */
static GHashTable * nowarn_by_type = NULL;
static GArray     * sink_funcs     = NULL;

static GQuark wrapper_quark; /* this quark stores the object's wrapper sv */

/* what should be done here */
#define GPERL_THREAD_SAFE !GPERL_DISABLE_THREADSAFE

#if GPERL_THREAD_SAFE
/* keep a list of all gobjects */
static gboolean     perl_gobject_tracking = FALSE;
static GHashTable * perl_gobjects = NULL;
G_LOCK_DEFINE_STATIC (perl_gobjects);
#endif

/* thread safety locks for the modifiables above */
G_LOCK_DEFINE_STATIC (types_by_type);
G_LOCK_DEFINE_STATIC (types_by_package);
G_LOCK_DEFINE_STATIC (nowarn_by_type);
G_LOCK_DEFINE_STATIC (sink_funcs);


static MGVTBL gperl_mg_vtbl;

/*
 * Attach a C<ptr> to the given C<sv>. It can be retrieved later using
 * C<_gperl_find_mg> and removed again using C<_gperl_remove_mg>.
 */

void
_gperl_attach_mg (SV * sv, void * ptr)
{
	sv_magicext (sv, NULL, PERL_MAGIC_ext, &gperl_mg_vtbl,
		     (const char *)ptr, 0);
}

/*
 * Retrieve the magic used to attach a pointer to the given C<sv> using
 * C<_gperl_attach_mg>. The C<mg_ptr> member of the returned struct will contain
 * the actual pointer attached to the scalar.
 */

MAGIC *
_gperl_find_mg (SV * sv)
{
	MAGIC *mg;

	if (SvTYPE (sv) < SVt_PVMG)
		return NULL;

	for (mg = SvMAGIC (sv); mg; mg = mg->mg_moremagic) {
		if (mg->mg_type == PERL_MAGIC_ext
		    && mg->mg_virtual == &gperl_mg_vtbl) {
			assert (mg->mg_ptr);
			return mg;
		}
	}

	return NULL;
}

/* copied from ppport.h, needed for older perls (< 5.8.8?) */
#ifndef SvMAGIC_set
#  define SvMAGIC_set(sv, val)           \
                STMT_START { assert(SvTYPE(sv) >= SVt_PVMG); \
                (((XPVMG*) SvANY(sv))->xmg_magic = (val)); } STMT_END
#endif

/*
 * Remove the association between a pointer attached to C<sv> using
 * C<_gperl_attach_mg> and the C<sv>.
 */

void
_gperl_remove_mg (SV * sv)
{
	MAGIC *mg, *prevmagic = NULL, *moremagic = NULL;

	if (SvTYPE (sv) < SVt_PVMG || !SvMAGIC (sv))
		return;

	for (mg = SvMAGIC (sv); mg; prevmagic = mg, mg = moremagic) {
		moremagic = mg->mg_moremagic;

		if (mg->mg_type == PERL_MAGIC_ext
		    && mg->mg_virtual == &gperl_mg_vtbl)
			break;
	}

	if (prevmagic) {
		prevmagic->mg_moremagic = moremagic;
	} else {
		SvMAGIC_set (sv, moremagic);
	}

	mg->mg_moremagic = NULL;
	Safefree (mg);
}

static ClassInfo *
class_info_new (GType gtype,
		const char * package)
{
	ClassInfo * class_info;

	class_info = g_new0 (ClassInfo, 1);
	class_info->gtype = gtype;
	class_info->package = g_strdup (package);
	class_info->initialized = FALSE;

	return class_info;
}

static void
class_info_destroy (ClassInfo * class_info)
{
	if (class_info) {
		g_free (class_info->package);
		g_free (class_info);
	}
}

static void
class_info_finish_loading (ClassInfo * class_info)
{
	char * child_isa_full;
	AV * isa;
	AV * new_isa;
	int i, items;

#ifdef NOISY
	static int depth = 0;
	char leader[50] = "";
	depth++;
	for (i = 0 ; i < depth ; i++)
		leader[i] = ' ';
	leader[i] = '\0';

	warn ("%s%s(0x%p) -> %s\n",
	      leader, __FUNCTION__, class_info, class_info->package);
#endif

	child_isa_full = g_strconcat (class_info->package, "::ISA", NULL);
	isa = get_av (child_isa_full, FALSE); /* supposed to exist already */
	if (!isa)
		croak ("internal inconsistency -- finishing lazy loading, "
		       "but %s::ISA does not exist", class_info->package);
	g_free (child_isa_full);

	/*
	 * Rather than just blowing away the old @ISA and replacing it with
	 * one of our own, we need to replace the _LazyLoader marker with
	 * the proper new info.  This is because some classes may need to
	 * have interfaces appear in @ISA *before* the parent class, in order
	 * to resolve name clashes -- think of Gtk2::TreeModel::get versus
	 * Glib::Object::get, for example.
	 *
	 * Thus, this will be a little roundabout.
	 */

	new_isa = newAV ();

	items = av_len (isa) + 1;
	for (i = 0 ; i < items ; i++) {
		/* We're shifting the entries off of the @ISA array here
		 * because just accessing them and later calling av_clear
		 * seems to break the caching magic associated with @ISA when
		 * running under perl 5.10.0. */
		SV * sv = av_shift (isa);
		if (!sv)
			continue;
		if (strEQ (SvPV_nolen (sv), "Glib::Object::_LazyLoader")) {
			/* omit _LazyLoader, fill with proper info */
			GType parent_type;
			GType *interfaces;
			guint n_interfaces;
			const char * package;
			int i;

			parent_type = g_type_parent (class_info->gtype);
			if (!parent_type)
				/* we just found GObject or GInterface.
				 * this is legal. */
				continue;

			if (parent_type == G_TYPE_INTERFACE)
				/* not interested in setting this up. */
				continue;

			/* possibly recurse, loading all the way down to
			 * GObject if necessary */
			package = gperl_object_package_from_type (parent_type);

			if (!package) {
				warn ("WHOA!  parent %s of %s is not an object"
				      " or interface!",
				      g_type_name (parent_type),
				      g_type_name (class_info->gtype));
				continue;
			}

			av_push (new_isa, newSVpv (package, 0));

			/* add in any interfaces we can find. */
			interfaces = g_type_interfaces (class_info->gtype,
							&n_interfaces);
			for (i = 0 ; interfaces[i] != 0 ; i++) {
				package = gperl_object_package_from_type
						(interfaces[i]);
				if (package)
					av_push (new_isa,
						 newSVpv (package, 0));
				else
					warn ("interface type %s(%"G_GSIZE_FORMAT") is not"
					      " registered",
					      g_type_name (interfaces[i]),
					      interfaces[i]);
			}
			if (interfaces)
				g_free (interfaces);

			/* this scalar is not needed anymore */
			sv_free (sv);
		} else {
			/* ownership of sv is transferred to new_isa */
			av_push (new_isa, sv);
		}
	}

	/* copy back to the now empty isa */
	items = av_len (new_isa) + 1;
	for (i = 0 ; i < items ; i++) {
		SV ** svp = av_fetch (new_isa, i, FALSE);
		if (svp && *svp)
			av_push (isa, SvREFCNT_inc (*svp));
		else
			warn ("bad pointer inside av\n");
	}

	av_clear (new_isa);
	av_undef (new_isa);

	class_info->initialized = TRUE;

#ifdef NOISY
	warn ("%sdone\n", leader);
	depth--;
#endif
}

static ClassInfo *
find_registered_type_in_ancestry (const char *package)
{
	char *isa_name;
	AV *isa;

	isa_name = g_strconcat (package, "::ISA", NULL);
	isa = get_av (isa_name, FALSE); /* supposed to exist already */
	g_free (isa_name);

	if (isa) {
		int i, n_items = av_len (isa) + 1;
		for (i = 0; i < n_items; i++) {
			ClassInfo *class_info;
			SV **entry;

			entry = av_fetch (isa, i, 0);
			if (!entry || !gperl_sv_is_defined (*entry))
				continue;

			G_LOCK (types_by_package);
			class_info = (ClassInfo*)
				g_hash_table_lookup (types_by_package,
						     SvPV_nolen (*entry));
			G_UNLOCK (types_by_package);

			if (!class_info) {
				/* If this package is not registered, maybe one
				 * of its ancestors is?  So try to recurse into
				 * this package's @ISA. */
				class_info =
					find_registered_type_in_ancestry (
						SvPV_nolen (*entry));
			}

			if (class_info) {
				return class_info;
			}
		}
	}

	return NULL;
}


#if 0
  "Skipped embedded POD."
#endif
#line 382 "GObject.xs"

void
gperl_register_object (GType gtype,
                       const char * package)
{
	ClassInfo * class_info;

	G_LOCK (types_by_type);
	G_LOCK (types_by_package);

	if (!types_by_type) {
		/* we put the same data pointer into each hash table, so we
		 * must only associate the destructor with one of them.
		 * also, for the string-keyed hashes, the keys will be
		 * destroyed by the ClassInfo destructor, so we don't need
		 * a key_destroy_func. */
		types_by_type = g_hash_table_new_full (g_direct_hash,
						       g_direct_equal,
						       NULL,
						       (GDestroyNotify)
						          class_info_destroy);
		types_by_package = g_hash_table_new_full (g_str_hash,
							  g_str_equal,
							  NULL,
							  NULL);
	}
	class_info = class_info_new (gtype, package);

	/* We need to insert into types_by_package first because there might
	 * otherwise be trouble if we overwrite an entry: inserting into
	 * types_by_type frees the class_info of the overwritten entry, so
	 * that class_info->package is no longer valid at this point.
	 *
	 * Note also it's g_hash_table_replace() for types_by_package,
	 * because the old key string in the old class_info will be freed
	 * when types_by_type updates the value there.
	 */
	g_hash_table_replace (types_by_package, class_info->package, class_info);
	g_hash_table_insert (types_by_type,
	                     (gpointer) class_info->gtype, class_info);
	/* warn ("registered type %s to package %s\n", g_type_name (class_info->gtype), class_info->package); */

	/* defer the actual ISA setup to Glib::Object::_LazyLoader */
	gperl_set_isa (package, "Glib::Object::_LazyLoader");

	G_UNLOCK (types_by_type);
	G_UNLOCK (types_by_package);

	if (G_TYPE_IS_INTERFACE (gtype))
		/*
		 * Force GInterfaces to finish loading now.  In some cases,
		 * we won't cause a call to gperl_object_package_from_type()
		 * on the interface type to happen from perl code before
		 * somebody tries to do a lookup on an object type that
		 * implements that interface, which causes _LazyLoader to
		 * get upset.  Since GInterfaces are not deep-derivable, an
		 * alternative is simply to avoid setting up lazy loading
		 * for GInterfaces, but that can cause problems if the
		 * GInterface type is not registered.
		 *
		 * NOTE:  class_info_finish_loading() may call other
		 *        functions that grab locks, so we need to be
		 *        unlocked.
		 */
		class_info_finish_loading (class_info);
}

#if 0
  "Skipped embedded POD."
#endif
#line 462 "GObject.xs"

void
gperl_register_object_alias (GType gtype,
			     const char * package)
{
	ClassInfo *class_info;

	G_LOCK (types_by_type);
	class_info = (ClassInfo *)
		g_hash_table_lookup (types_by_type, (gpointer) gtype);
	G_UNLOCK (types_by_type);

	if (!class_info) {
		croak ("cannot register alias %s for the unregistered type %s",
		       package, g_type_name (gtype));
	}

	G_LOCK (types_by_package);
	/* associate package with the same class_info.  class_info is still
	   owned by types_by_type.  types_by_package doesn't have a
	   free-function installed, so that's ok. */
	g_hash_table_insert (types_by_package, (char *) package, class_info);
	G_UNLOCK (types_by_package);
}


#if 0
  "Skipped embedded POD."
#endif
#line 513 "GObject.xs"
/*
 * this stuff is directly inspired by pygtk.  i didn't actually copy
 * and paste the code, but it sure looks like i did, down to the names.
 * hey, they were the obvious names!
 *
 * for the record, i think this is a rather dodgy way to do sink funcs
 * --- it presumes that you'll find the right one first; i prepend new
 * registrees in the hopes that this will work out, but nothing guarantees
 * that this will work.  to do it right, the wrappers need to have
 * some form of inherited vtable or something...  but i've had enough
 * problems just getting the object caching working, so i can't really
 * mess with that right now.
 */
void
gperl_register_sink_func (GType gtype,
                          GPerlObjectSinkFunc func)
{
	SinkFunc sf;

	G_LOCK (sink_funcs);

	if (!sink_funcs)
		sink_funcs = g_array_new (FALSE, FALSE, sizeof (SinkFunc));
	sf.gtype = gtype;
	sf.func  = func;
	g_array_prepend_val (sink_funcs, sf);

	G_UNLOCK (sink_funcs);
}

/*
 * helper for gperl_new_object; do whatever you have to do to this
 * object to ensure that the calling code now owns the object.  assumes
 * the object has already been ref'd once.  to do this, we look up the
 * proper sink func; if none has been registered for this type, then
 * just call g_object_unref.
 */
static void
gperl_object_take_ownership (GObject * object)
{
	G_LOCK (sink_funcs);

	if (sink_funcs) {
		guint i;
		for (i = 0 ; i < sink_funcs->len ; i++)
			if (g_type_is_a (G_OBJECT_TYPE (object),
			                 g_array_index (sink_funcs,
			                                SinkFunc, i).gtype)) {
				g_array_index (sink_funcs,
				               SinkFunc, i).func (object);
				G_UNLOCK (sink_funcs);
				return;
			}
	}

	G_UNLOCK (sink_funcs);

	g_object_unref (object);
}

#if GLIB_CHECK_VERSION (2, 10, 0)
static void
sink_initially_unowned (GObject *object)
{
	/* FIXME: This is not correct when the object is not floating.  The
	 * sink function is supposed to effectively remove a reference, but
	 * when the object is not floating, ref_sink+unref == ref+unref == nop.
	 * Luckily, there do not seem to be functions of GInitiallyUnowned
	 * descendants out there that transfer ownership of a non-floating
	 * reference to the caller.  If we ever encounter one, this needs to be
	 * revisited.
	 *
	 * One peculiar corner case is Glib::Object::Introspection's handling
	 * of GtkWindow and its descendants.  G:O:I marks all constructors of
	 * GInitiallyUnowned descendants as transferring ownership (to override
	 * special-casing done by gobject-introspection).  This is thus
	 * inadvertedly also applied to GtkWindow and its descendants even
	 * though their constructors do not transfer ownership (because gtk+
	 * keeps an internal reference to each window).  But due to this
	 * incorrect code below, the ownership transfer is effectively ignored,
	 * resulting in correct behavior. */
	g_object_ref_sink (object);
	g_object_unref (object);
}
#endif


#if 0
  "Skipped embedded POD."
#endif
#line 625 "GObject.xs"
void
gperl_object_set_no_warn_unreg_subclass (GType gtype,
                                         gboolean nowarn)
{
	G_LOCK (nowarn_by_type);

	if (!nowarn_by_type) {
		if (!nowarn)
			return;
		nowarn_by_type = g_hash_table_new (g_direct_hash,
		                                   g_direct_equal);
	}
	g_hash_table_insert (nowarn_by_type,
	                     (gpointer) gtype,
	                     GINT_TO_POINTER (nowarn));

	G_UNLOCK (nowarn_by_type);
}

static gboolean
gperl_object_get_no_warn_unreg_subclass (GType gtype)
{
	gboolean result;

	G_LOCK (nowarn_by_type);

	if (!nowarn_by_type)
		result = FALSE;
	else
		result = GPOINTER_TO_INT
		              (g_hash_table_lookup (nowarn_by_type,
		                                    (gpointer) gtype));

	G_UNLOCK (nowarn_by_type);

	return result;
}


#if 0
  "Skipped embedded POD."
#endif
#line 672 "GObject.xs"
const char *
gperl_object_package_from_type (GType gtype)
{
	ClassInfo * class_info;

	if (!g_type_is_a (gtype, G_TYPE_OBJECT) &&
	    !g_type_is_a (gtype, G_TYPE_INTERFACE))
		return NULL;

	if (!types_by_type)
		croak ("internal problem: gperl_object_package_from_type "
		       "called before any classes were registered");

	G_LOCK (types_by_type);

	class_info = (ClassInfo *)
		g_hash_table_lookup (types_by_type, (gpointer) gtype);

	G_UNLOCK (types_by_type);

	if (!class_info) {
                /*
                 * Walk up the ancestry to see if we're the child of a type
                 * whose children are private.  In the old days, we called
                 * this "no-warn", to suppress warnings about unregistered
                 * types (e.g. Styles, GCs, etc).  Now we'll use it to
                 * map "private" GTypes to known parent classes.
                 */
                GType parent = gtype;
                while (0 != (parent = g_type_parent (parent))) {
                        if (gperl_object_get_no_warn_unreg_subclass (parent)) {
                                /* Use this class's ClassInfo instead. */
                                class_info = (ClassInfo *)
                                        g_hash_table_lookup (types_by_type,
                                                             (gpointer) parent);
                                break;
                        }
                }
        }

	if (!class_info) {
		gchar * package;

		package = g_strconcat ("Glib::Object::_Unregistered::",
				       g_type_name (gtype), NULL);
		/* XXX find a way to do this without locking twice */
		gperl_register_object (gtype, package);
		g_free (package);
		G_LOCK (types_by_type);
		class_info = (ClassInfo*)
			g_hash_table_lookup (types_by_type, (gpointer) gtype);
		G_UNLOCK (types_by_type);
	}

	g_assert (class_info);

	if (!class_info->initialized) {
		/* do a proper @ISA setup for this guy. */
		class_info_finish_loading (class_info);
	}

	return class_info->package;
}


#if 0
  "Skipped embedded POD."
#endif
#line 743 "GObject.xs"

HV *
gperl_object_stash_from_type (GType gtype)
{
	const char * package = gperl_object_package_from_type (gtype);
	if (package)
		return gv_stashpv (package, TRUE);
	else
		return NULL;
}


#if 0
  "Skipped embedded POD."
#endif
#line 761 "GObject.xs"

GType
gperl_object_type_from_package (const char * package)
{
	if (types_by_package) {
		ClassInfo * class_info;

		G_LOCK (types_by_package);

		class_info = (ClassInfo *)
			g_hash_table_lookup (types_by_package, package);

		G_UNLOCK (types_by_package);

		if (class_info) {
			/* class_info_finish_loading calls us, so even if
			 * !class_info->initialized, we should not call it to
			 * avoid recursion. */
			return class_info->gtype;
		} else {
			return 0;
		}
	} else
		croak ("internal problem: gperl_object_type_from_package "
		       "called before any classes were registered");
	return 0; /* not reached */
}

/*
 * Manipulate a pointer to indicate that an SV is undead.
 * Relies on SV pointers being word-aligned.
 */
#define IS_UNDEAD(x) (PTR2UV(x) & 1)
#define MAKE_UNDEAD(x) INT2PTR(void*, PTR2UV(x) | 1)
#define REVIVE_UNDEAD(x) INT2PTR(void*, PTR2UV(x) & ~1)

/*
 * this function is called whenever the gobject gets destroyed. this only
 * happens if the perl object is no longer referenced anywhere else, so
 * put it to final rest here.
 */
static void
gobject_destroy_wrapper (SV *obj)
{
	GPERL_SET_CONTEXT;

	/* As of perl 5.16, this function needs to run even during global
	 * destruction (i.e. when PL_in_clean_objs is true) since we might
	 * otherwise end up with undead HVs hanging on to garbage.  Prior to
	 * 5.16, this did not matter, but recent versions of perl will find
	 * these HVs and call DESTROY on them. */

#ifdef NOISY
        warn ("gobject_destroy_wrapper (%p)[%d]\n", obj,
              SvREFCNT ((SV*)REVIVE_UNDEAD(obj)));
#endif
        obj = REVIVE_UNDEAD(obj);
        _gperl_remove_mg (obj);

        /* we might want to optimize away the call to DESTROY here for non-perl classes. */
        SvREFCNT_dec (obj);
}

static void
update_wrapper (GObject *object, gpointer obj)
{
        /* printf("update_wrapper [%p] (%p)\n", object, obj); */
        g_object_steal_qdata (object, wrapper_quark);
        g_object_set_qdata_full (object,
                                 wrapper_quark,
                                 obj,
                                 (GDestroyNotify)gobject_destroy_wrapper);
}

#if 0
  "Skipped embedded POD."
#endif
#line 870 "GObject.xs"

SV *
gperl_new_object (GObject * object,
                  gboolean own)
{
	SV *obj;
	SV *sv;

	/* take the easy way out if we can */
	if (!object) {
#ifdef NOISY
		warn ("gperl_new_object (NULL) => undef\n");
#endif
		return &PL_sv_undef;
	}

	if (!G_IS_OBJECT (object))
		croak ("object %p is not really a GObject", object);

        /* fetch existing wrapper_data */
        obj = (SV *)g_object_get_qdata (object, wrapper_quark);

        if (!obj) {
                /* create the perl object */
                GType gtype = G_OBJECT_TYPE (object);

                HV *stash = gperl_object_stash_from_type (gtype);

                /* We should only get NULL for the stash here if gtype is
                 * neither a GObject nor GInterface.  We filtered out all
                 * non-GObject types a few lines back. */
                g_assert (stash != NULL);

                /*
                 * Create the "object", a hash.
                 *
                 * This does not need to be a HV, the only problem is finding
                 * out what to use, and HV is certainly the way to go for any
                 * built-in objects.
                 */

                /* this increases the combined object's refcount. */
                obj = (SV *)newHV ();
                /* attach magic */
                _gperl_attach_mg (obj, object);

                /* The SV has a ref to the C object.  If we are to own this
                 * object, then any other references will be taken care of
                 * below in take_ownership */
                g_object_ref (object);

                /* create the wrapper to return, the _noinc decreases the
                 * combined refcount by one. */
                sv = newRV_noinc (obj);

                /* bless into the package */
                sv_bless (sv, stash);

                /* attach it to the gobject */
                update_wrapper (object, obj);
                /* printf("creating new wrapper for [%p] (%p)\n", object, obj); */

                /* the noinc is so that the SV (initially) exists only as long
                 * as the perl code needs it.  When the DESTROY gets called, we
                 * check and see if the SV is the only referer to the C object,
                 * and if so remove both.  Otherwise, the SV will become
                 * "undead," to be either revived or destroyed with the C
                 * object */

#ifdef NOISY
		warn ("gperl_new_object%d %s(%p)[%d] => %s (%p) (NEW)\n", own,
		      G_OBJECT_TYPE_NAME (object), object, object->ref_count,
		      gperl_object_package_from_type (G_OBJECT_TYPE (object)),
		      SvRV (sv));
#endif
        } else {
                /* create the wrapper to return, increases the combined
                 * refcount by one. */

                /* if the SV is undead, revive it */
                if (IS_UNDEAD(obj)) {
                    g_object_ref (object);
                    obj = REVIVE_UNDEAD(obj);
                    update_wrapper (object, obj);
                    sv = newRV_noinc (obj);
                    /* printf("reviving undead wrapper for [%p] (%p)\n", object, obj); */
                } else {
                    /* printf("reusing previous wrapper for %p\n", obj); */
                    sv = newRV_inc (obj);
                }
        }

#ifdef NOISY
	warn ("gperl_new_object%d %s(%p)[%d] => %s (%p)[%d] (PRE-OWN)\n", own,
	      G_OBJECT_TYPE_NAME (object), object, object->ref_count,
	      gperl_object_package_from_type (G_OBJECT_TYPE (object)),
	      SvRV (sv), SvREFCNT (SvRV (sv)));
#endif

	if (own)
		gperl_object_take_ownership (object);

#if GPERL_THREAD_SAFE
	if(perl_gobject_tracking)
	{
		G_LOCK (perl_gobjects);
/*g_printerr ("adding object: 0x%p - %d\n", object, object->ref_count);*/
		if (!perl_gobjects)
			perl_gobjects = g_hash_table_new (g_direct_hash, g_direct_equal);
		g_hash_table_insert (perl_gobjects, (gpointer)object, (gpointer)1);
		G_UNLOCK (perl_gobjects);
	}
#endif

	return sv;
}



#if 0
  "Skipped embedded POD."
#endif
#line 998 "GObject.xs"

GObject *
gperl_get_object (SV * sv)
{
	MAGIC *mg;

	if (!gperl_sv_is_ref (sv) || !(mg = _gperl_find_mg (SvRV (sv))))
		return NULL;

	return (GObject *) mg->mg_ptr;
}


#if 0
  "Skipped embedded POD."
#endif
#line 1018 "GObject.xs"

GObject *
gperl_get_object_check (SV * sv,
			GType gtype)
{
	MAGIC *mg;
	const char * package;
	package = gperl_object_package_from_type (gtype);
	if (!package)
		croak ("INTERNAL: GType %s (%d) is not registered with GPerl!",
		       g_type_name (gtype), gtype);
	if (!gperl_sv_is_ref (sv) || !sv_derived_from (sv, package))
		croak ("%s is not of type %s",
		       gperl_format_variable_for_output (sv),
		       package);
	if (!(mg = _gperl_find_mg (SvRV (sv))))
		croak ("%s is not a proper Glib::Object "
		       "(it doesn't contain the right magic)",
		       gperl_format_variable_for_output (sv));

	return (GObject *) mg->mg_ptr;
}


#if 0
  "Skipped embedded POD."
#endif
#line 1049 "GObject.xs"

SV *
gperl_object_check_type (SV * sv,
                         GType gtype)
{
	gperl_get_object_check (sv, gtype);
	return sv;
}



/* helper for g_object_[gs]et_parameter */
static void
init_property_value (GObject * object,
		     const char * name,
		     GValue * value)
{
	GParamSpec * pspec;
	pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (object),
	                                      name);
	if (!pspec) {
		const char * classname =
			gperl_object_package_from_type (G_OBJECT_TYPE (object));
		if (!classname)
			classname = G_OBJECT_TYPE_NAME (object);
		croak ("type %s does not support property '%s'",
		       classname, name);
	}
	g_value_init (value, G_PARAM_SPEC_VALUE_TYPE (pspec));
}


#if 0
  "Skipped embedded POD."
#endif
#line 1097 "GObject.xs"

/*
 * $sv = $object->{name}
 *
 * if the key doesn't exist with name, convert - to _ and try again.
 * that is, support both "funny-name" and "funny_name".
 *
 * if create is true, autovivify the key (and always return a value).
 * if create is false, returns NULL is there is no such key.
 */
SV *
_gperl_fetch_wrapper_key (GObject * object,
                          const char * name,
                          gboolean create)
{
	SV ** svp;
	SV * svname;
	HV * wrapper_hash;
	wrapper_hash = g_object_get_qdata (object, wrapper_quark);

	/* we don't care whether the wrapper is alive or undead.  forcibly
	 * remove the undead bit, or the pointer will be unusable. */
	wrapper_hash = REVIVE_UNDEAD (wrapper_hash);

	svname = newSVpv (name, strlen (name));
	svp = hv_fetch (wrapper_hash, SvPV_nolen (svname), SvCUR (svname),
	                FALSE); /* never create on the first try; prefer
	                         * prefer to create the second version. */
	if (!svp) {
		/* the key doesn't exist with that name.  do s/-/_/g and
		 * try again. */
		register char * c;
		for (c = SvPV_nolen (svname); c <= SvEND (svname) ; c++)
			if (*c == '-')
				*c = '_';
		svp = hv_fetch (wrapper_hash,
		                SvPV_nolen (svname), SvCUR (svname),
		                create);
	}
	SvREFCNT_dec (svname);

	return (svp ? *svp : NULL);
}

#if GPERL_THREAD_SAFE
static void
_inc_ref_and_count (GObject * key, gint value, gpointer user_data)
{
	PERL_UNUSED_VAR (user_data);
	g_object_ref (key);
	value += 1;
	g_hash_table_replace (perl_gobjects, key, GINT_TO_POINTER (value));
}
#endif


#line 1024 "GObject.c"
#ifndef PERL_UNUSED_VAR
#  define PERL_UNUSED_VAR(var) if (0) var = var
#endif

#ifndef dVAR
#  define dVAR		dNOOP
#endif


/* This stuff is not part of the API! You have been warned. */
#ifndef PERL_VERSION_DECIMAL
#  define PERL_VERSION_DECIMAL(r,v,s) (r*1000000 + v*1000 + s)
#endif
#ifndef PERL_DECIMAL_VERSION
#  define PERL_DECIMAL_VERSION \
	  PERL_VERSION_DECIMAL(PERL_REVISION,PERL_VERSION,PERL_SUBVERSION)
#endif
#ifndef PERL_VERSION_GE
#  define PERL_VERSION_GE(r,v,s) \
	  (PERL_DECIMAL_VERSION >= PERL_VERSION_DECIMAL(r,v,s))
#endif
#ifndef PERL_VERSION_LE
#  define PERL_VERSION_LE(r,v,s) \
	  (PERL_DECIMAL_VERSION <= PERL_VERSION_DECIMAL(r,v,s))
#endif

/* XS_INTERNAL is the explicit static-linkage variant of the default
 * XS macro.
 *
 * XS_EXTERNAL is the same as XS_INTERNAL except it does not include
 * "STATIC", ie. it exports XSUB symbols. You probably don't want that
 * for anything but the BOOT XSUB.
 *
 * See XSUB.h in core!
 */


/* TODO: This might be compatible further back than 5.10.0. */
#if PERL_VERSION_GE(5, 10, 0) && PERL_VERSION_LE(5, 15, 1)
#  undef XS_EXTERNAL
#  undef XS_INTERNAL
#  if defined(__CYGWIN__) && defined(USE_DYNAMIC_LOADING)
#    define XS_EXTERNAL(name) __declspec(dllexport) XSPROTO(name)
#    define XS_INTERNAL(name) STATIC XSPROTO(name)
#  endif
#  if defined(__SYMBIAN32__)
#    define XS_EXTERNAL(name) EXPORT_C XSPROTO(name)
#    define XS_INTERNAL(name) EXPORT_C STATIC XSPROTO(name)
#  endif
#  ifndef XS_EXTERNAL
#    if defined(HASATTRIBUTE_UNUSED) && !defined(__cplusplus)
#      define XS_EXTERNAL(name) void name(pTHX_ CV* cv __attribute__unused__)
#      define XS_INTERNAL(name) STATIC void name(pTHX_ CV* cv __attribute__unused__)
#    else
#      ifdef __cplusplus
#        define XS_EXTERNAL(name) extern "C" XSPROTO(name)
#        define XS_INTERNAL(name) static XSPROTO(name)
#      else
#        define XS_EXTERNAL(name) XSPROTO(name)
#        define XS_INTERNAL(name) STATIC XSPROTO(name)
#      endif
#    endif
#  endif
#endif

/* perl >= 5.10.0 && perl <= 5.15.1 */


/* The XS_EXTERNAL macro is used for functions that must not be static
 * like the boot XSUB of a module. If perl didn't have an XS_EXTERNAL
 * macro defined, the best we can do is assume XS is the same.
 * Dito for XS_INTERNAL.
 */
#ifndef XS_EXTERNAL
#  define XS_EXTERNAL(name) XS(name)
#endif
#ifndef XS_INTERNAL
#  define XS_INTERNAL(name) XS(name)
#endif

/* Now, finally, after all this mess, we want an ExtUtils::ParseXS
 * internal macro that we're free to redefine for varying linkage due
 * to the EXPORT_XSUB_SYMBOLS XS keyword. This is internal, use
 * XS_EXTERNAL(name) or XS_INTERNAL(name) in your code if you need to!
 */

#undef XS_EUPXS
#if defined(PERL_EUPXS_ALWAYS_EXPORT)
#  define XS_EUPXS(name) XS_EXTERNAL(name)
#else
   /* default to internal */
#  define XS_EUPXS(name) XS_INTERNAL(name)
#endif

#ifndef PERL_ARGS_ASSERT_CROAK_XS_USAGE
#define PERL_ARGS_ASSERT_CROAK_XS_USAGE assert(cv); assert(params)

/* prototype to pass -Wmissing-prototypes */
STATIC void
S_croak_xs_usage(const CV *const cv, const char *const params);

STATIC void
S_croak_xs_usage(const CV *const cv, const char *const params)
{
    const GV *const gv = CvGV(cv);

    PERL_ARGS_ASSERT_CROAK_XS_USAGE;

    if (gv) {
        const char *const gvname = GvNAME(gv);
        const HV *const stash = GvSTASH(gv);
        const char *const hvname = stash ? HvNAME(stash) : NULL;

        if (hvname)
	    Perl_croak_nocontext("Usage: %s::%s(%s)", hvname, gvname, params);
        else
	    Perl_croak_nocontext("Usage: %s(%s)", gvname, params);
    } else {
        /* Pants. I don't think that it should be possible to get here. */
	Perl_croak_nocontext("Usage: CODE(0x%"UVxf")(%s)", PTR2UV(cv), params);
    }
}
#undef  PERL_ARGS_ASSERT_CROAK_XS_USAGE

#define croak_xs_usage        S_croak_xs_usage

#endif

/* NOTE: the prototype of newXSproto() is different in versions of perls,
 * so we define a portable version of newXSproto()
 */
#ifdef newXS_flags
#define newXSproto_portable(name, c_impl, file, proto) newXS_flags(name, c_impl, file, proto, 0)
#else
#define newXSproto_portable(name, c_impl, file, proto) (PL_Sv=(SV*)newXS(name, c_impl, file), sv_setpv(PL_Sv, proto), (CV*)PL_Sv)
#endif /* !defined(newXS_flags) */

#if PERL_VERSION_LE(5, 21, 5)
#  define newXS_deffile(a,b) Perl_newXS(aTHX_ a,b,file)
#else
#  define newXS_deffile(a,b) Perl_newXS_deffile(aTHX_ a,b)
#endif

#line 1168 "GObject.c"
#if GPERL_THREAD_SAFE
#define XSubPPtmpAAAA 1


XS_EUPXS(XS_Glib__Object_CLONE); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_Glib__Object_CLONE)
{
    dVAR; dXSARGS;
    if (items != 1)
       croak_xs_usage(cv,  "class");
    {
	gchar *	class;

	/* same as SvGChar(), but not in a function */
	sv_utf8_upgrade (ST(0));
	class = (gchar *)SvPV_nolen (ST(0))
;
#line 1170 "GObject.xs"
	/* !perl_gobjects can happen when no object has been created yet. */
    	if (perl_gobject_tracking && perl_gobjects &&
	    strcmp (class, "Glib::Object") == 0)
	{
		G_LOCK (perl_gobjects);
/*g_printerr ("we're in clone: %s\n", class);*/
		g_hash_table_foreach (perl_gobjects,
				      (GHFunc)_inc_ref_and_count, NULL);
		G_UNLOCK (perl_gobjects);
	}
#line 1197 "GObject.c"
    }
    XSRETURN_EMPTY;
}

#endif

XS_EUPXS(XS_Glib__Object_set_threadsafe); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_Glib__Object_set_threadsafe)
{
    dVAR; dXSARGS;
    if (items != 2)
       croak_xs_usage(cv,  "class, threadsafe");
    {
	gboolean	RETVAL;
	gboolean	threadsafe = (bool)SvTRUE(ST(1))
;
#line 1190 "GObject.xs"
#if GPERL_THREAD_SAFE
	RETVAL = perl_gobject_tracking = threadsafe;
#else
	PERL_UNUSED_VAR (threadsafe);
	RETVAL = FALSE;
#endif
#line 1221 "GObject.c"
	ST(0) = boolSV(RETVAL);
    }
    XSRETURN(1);
}


XS_EUPXS(XS_Glib__Object_DESTROY); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_Glib__Object_DESTROY)
{
    dVAR; dXSARGS;
    if (items != 1)
       croak_xs_usage(cv,  "sv");
    {
#line 1242 "GObject.xs"
        GObject *object;
        gboolean was_undead;
#line 1238 "GObject.c"
	SV *	sv = ST(0)
;
#line 1245 "GObject.xs"
        object = gperl_get_object (sv);
        if (!object) /* Happens on GObject destruction. */
                return;
#ifdef NOISY
        warn ("DESTROY< (%p)[%d] => %s (%p)[%d]\n",
              object, object->ref_count,
              gperl_object_package_from_type (G_OBJECT_TYPE (object)),
              sv, SvREFCNT (SvRV(sv)));
#endif
        was_undead = IS_UNDEAD (g_object_get_qdata (object, wrapper_quark));
        /* gobject object still exists, so take back the refcount we lend it. */
        /* this operation does NOT change the refcount of the combined object. */
	if (PL_in_clean_objs) {
                /* be careful during global destruction. basically,
                 * don't bother, since refcounting is no longer meaningful. */
                _gperl_remove_mg (SvRV (sv));
                g_object_steal_qdata (object, wrapper_quark);
        } else {
                SvREFCNT_inc (SvRV (sv));
                if (object->ref_count > 1) {
                    /* become undead */
                    SV *obj = SvRV(sv);
                    update_wrapper (object, MAKE_UNDEAD(obj));
                    /* printf("zombies! [%p] (%p)\n", object, obj);*/
                }
        }
#if GPERL_THREAD_SAFE
	if(perl_gobject_tracking)
	{
		gint count;
		G_LOCK (perl_gobjects);
		count = GPOINTER_TO_INT (g_hash_table_lookup (perl_gobjects, object));
		count--;
		if (count > 0)
		{
/*g_printerr ("decing: %p - %d\n", object, count);*/
			g_hash_table_replace (perl_gobjects, object,
					      GINT_TO_POINTER (count));
		}
		else
		{
/*g_printerr ("removing: %p\n", object);*/
			g_hash_table_remove (perl_gobjects, object);
		}
		G_UNLOCK (perl_gobjects);
	}
#endif
        /* As of perl 5.16, even HVs that are not referenced by any SV will get
         * their DESTROY called during global destruction.  Such HVs can occur
         * when the GObject outlives the HV, as for GtkWindow or GdkScreen.
         * Here in DESTROY such an HV will be in the "undead" state and will
         * not own a reference to the GObject anymore.  Thus we need to avoid
         * calling unref in this case.  See
         * <https://rt.perl.org/rt3//Public/Bug/Display.html?id=36347> for the
         * perl change. */
        if (!was_undead) {
                g_object_unref (object);
        }
#ifdef NOISY
	warn ("DESTROY> (%p) done\n", object);
	/*
        warn ("DESTROY> (%p)[%d] => %s (%p)[%d]",
              object, object->ref_count,
              gperl_object_package_from_type (G_OBJECT_TYPE (object)),
              sv, SvREFCNT (SvRV(sv)));
	*/
#endif
#line 1309 "GObject.c"
    }
    XSRETURN_EMPTY;
}


XS_EUPXS(XS_Glib__Object_new); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_Glib__Object_new)
{
    dVAR; dXSARGS;
    if (items < 1)
       croak_xs_usage(cv,  "class, ...");
    {
	const char *	class = (const char *)SvPV_nolen(ST(0))
;
#line 1330 "GObject.xs"
	int n_params = 0;
	GParameter * params = NULL;
	GType object_type;
	GObject * object;
	GObjectClass *oclass = NULL;
#line 1330 "GObject.c"
	SV *	RETVAL;
#line 1336 "GObject.xs"
#define FIRST_ARG	1
	object_type = gperl_object_type_from_package (class);
	if (!object_type)
		croak ("%s is not registered with gperl as an object type",
		       class);
	if (G_TYPE_IS_ABSTRACT (object_type))
		croak ("cannot create instance of abstract (non-instantiatable)"
		       " type `%s'", g_type_name (object_type));
	if (0 != ((items - 1) % 2))
		croak ("new method expects name => value pairs "
		       "(odd number of arguments detected)");
	if (items > FIRST_ARG) {
		int i;
		if (NULL == (oclass = g_type_class_ref (object_type)))
			croak ("could not get a reference to type class");
		n_params = (items - FIRST_ARG) / 2;
		params = g_new0 (GParameter, n_params);
		for (i = 0 ; i < n_params ; i++) {
			const char * key = SvPV_nolen (ST (FIRST_ARG+i*2+0));
			GParamSpec * pspec;
			pspec = g_object_class_find_property (oclass, key);
			if (!pspec) {
				/* clean up... */
				int j;
				for (j = 0 ; j < i ; j++)
					g_value_unset (&params[j].value);
				g_free (params);
				/* and bail out. */
				croak ("type %s does not support property '%s'",
				       class, key);
			}
			g_value_init (&params[i].value,
			              G_PARAM_SPEC_VALUE_TYPE (pspec));
			/* note: this croaks if there is a problem.  this is
			 * usually the right thing to do, because if it
			 * doesn't know how to convert the value, then there's
			 * something seriously wrong; however, it means that
			 * if there is a problem, all non-trivial values we've
			 * converted will be leaked. */
			gperl_value_from_sv (&params[i].value,
			                     ST (FIRST_ARG+i*2+1));
			params[i].name = key; /* will be valid until this
			                       * xsub is finished */
		}
	}
#undef FIRST_ARG

	object = g_object_newv (object_type, n_params, params);

	/* this wrapper *must* own this object!
	 * because we've been through initialization, the perl object
	 * will already exist at this point --- but this still causes
	 * gperl_object_take_ownership to be called. */
	RETVAL = gperl_new_object (object, TRUE);

	if (n_params) {
		int i;
		for (i = 0 ; i < n_params ; i++)
			g_value_unset (&params[i].value);
		g_free (params);
	}
	if (oclass)
		g_type_class_unref (oclass);
#line 1396 "GObject.c"
	RETVAL = sv_2mortal(RETVAL);
	ST(0) = RETVAL;
    }
    XSRETURN(1);
}


XS_EUPXS(XS_Glib__Object_get); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_Glib__Object_get)
{
    dVAR; dXSARGS;
    dXSI32;
    if (items < 1)
       croak_xs_usage(cv,  "object, ...");
    {
	GObject *	object = SvGObject (ST(0))
;
#line 1424 "GObject.xs"
	GValue value = {0,};
	int i;
#line 1417 "GObject.c"
#line 1427 "GObject.xs"
	/* Use CODE: instead of PPCODE: so we can handle the stack ourselves in
	 * order to avoid that xsubs called by g_object_get_property or
	 * _gperl_sv_from_value_internal overwrite what we put on the stack. */
	PERL_UNUSED_VAR (ix);
	for (i = 1; i < items; i++) {
		char *name = SvPV_nolen (ST (i));
		init_property_value (object, name, &value);
		g_object_get_property (object, name, &value);
		ST (i - 1) =
			sv_2mortal (
				_gperl_sv_from_value_internal (&value, TRUE));
		g_value_unset (&value);
	}
	XSRETURN (items - 1);
#line 1433 "GObject.c"
    }
    XSRETURN(1);
}


XS_EUPXS(XS_Glib__Object_set); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_Glib__Object_set)
{
    dVAR; dXSARGS;
    dXSI32;
    if (items < 1)
       croak_xs_usage(cv,  "object, ...");
    {
	GObject *	object = SvGObject (ST(0))
;
#line 1466 "GObject.xs"
	GValue value = {0,};
	int i;
#line 1452 "GObject.c"
#line 1469 "GObject.xs"
	PERL_UNUSED_VAR (ix);
	if (0 != ((items - 1) % 2))
		croak ("set method expects name => value pairs "
		       "(odd number of arguments detected)");

	for (i = 1; i < items; i += 2) {
		char *name = SvPV_nolen (ST (i));
		SV *newval = ST (i + 1);

		init_property_value (object, name, &value);
		gperl_value_from_sv (&value, newval);
		g_object_set_property (object, name, &value);
		g_value_unset (&value);
	}
#line 1468 "GObject.c"
    }
    XSRETURN_EMPTY;
}


XS_EUPXS(XS_Glib__Object_notify); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_Glib__Object_notify)
{
    dVAR; dXSARGS;
    if (items != 2)
       croak_xs_usage(cv,  "object, property_name");
    {
	GObject *	object = SvGObject (ST(0))
;
	const gchar *	property_name;

	/* same as SvGChar(), but not in a function */
	sv_utf8_upgrade (ST(1));
	property_name = (const gchar *)SvPV_nolen (ST(1))
;

	g_object_notify(object, property_name);
    }
    XSRETURN_EMPTY;
}


XS_EUPXS(XS_Glib__Object_freeze_notify); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_Glib__Object_freeze_notify)
{
    dVAR; dXSARGS;
    if (items != 1)
       croak_xs_usage(cv,  "object");
    {
	GObject *	object = SvGObject (ST(0))
;

	g_object_freeze_notify(object);
    }
    XSRETURN_EMPTY;
}


XS_EUPXS(XS_Glib__Object_thaw_notify); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_Glib__Object_thaw_notify)
{
    dVAR; dXSARGS;
    if (items != 1)
       croak_xs_usage(cv,  "object");
    {
	GObject *	object = SvGObject (ST(0))
;

	g_object_thaw_notify(object);
    }
    XSRETURN_EMPTY;
}


XS_EUPXS(XS_Glib__Object_find_property); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_Glib__Object_find_property)
{
    dVAR; dXSARGS;
    dXSI32;
    if (items < 1)
       croak_xs_usage(cv,  "object_or_class_name, ...");
    PERL_UNUSED_VAR(ax); /* -Wall */
    SP -= items;
    {
	SV *	object_or_class_name = ST(0)
;
#line 1554 "GObject.xs"
	GType type = G_TYPE_INVALID;
	gchar *name = NULL;
#line 1543 "GObject.c"
#line 1557 "GObject.xs"
	if (gperl_sv_is_ref (object_or_class_name)) {
		GObject * object = SvGObject (object_or_class_name);
		if (!object)
			croak ("wha?  NULL object in list_properties");
		type = G_OBJECT_TYPE (object);
	} else {
		type = gperl_object_type_from_package
		                          (SvPV_nolen (object_or_class_name));
		if (!type)
			croak ("package %s is not registered with GPerl",
			       SvPV_nolen (object_or_class_name));
	}

	if (ix == 0 && items == 2) {
		name = SvGChar (ST (1));
#ifdef NOISY
		warn ("Glib::Object::find_property ('%s', '%s')\n",
		      g_type_name (type),
		      name);
#endif
	}
	else if (ix == 0 && items != 2)
		croak ("Usage: Glib::Object::find_property (class, name)");
	else if (ix == 1 && items != 1)
		croak ("Usage: Glib::Object::list_properties (class)");

	if (G_TYPE_IS_OBJECT (type))
	{
		/* classes registered by perl are kept alive by the bindings.
		 * those coming straight from C are not.  if we had an actual
		 * object, the class will be alive, but if we just had a
		 * package, the class may not exist yet.  thus, we'll have to
		 * do an honest ref here, rather than a peek.
		 */
		GObjectClass *object_class = g_type_class_ref (type);

		if (ix == 0) {
			GParamSpec *pspec;

			pspec = g_object_class_find_property (object_class, name);
			if (pspec)
				XPUSHs (sv_2mortal (newSVGParamSpec (pspec)));
			else
				XPUSHs (newSVsv (&PL_sv_undef));
		}
		else if (ix == 1) {
			GParamSpec **props;
			guint n_props, i;

			props = g_object_class_list_properties (object_class, &n_props);
#ifdef NOISY
			warn ("list_properties: %d properties\n", n_props);
#endif
			if (n_props) {
				EXTEND (SP, n_props);

				for (i = 0; i < n_props; i++)
					PUSHs (sv_2mortal (newSVGParamSpec (props[i])));

			}
			g_free (props); /* must free even when n_props==0 */
		}

		g_type_class_unref (object_class);
	}
#if GLIB_CHECK_VERSION(2,4,0)
	else if (G_TYPE_IS_INTERFACE (type))
	{
		gpointer iface = g_type_default_interface_ref (type);

		if (ix == 0) {
			GParamSpec *pspec;

			pspec = g_object_interface_find_property (iface, name);
			if (pspec)
				XPUSHs (sv_2mortal (newSVGParamSpec (pspec)));
			else
				XPUSHs (newSVsv (&PL_sv_undef));
		}
		else if (ix == 1) {
			GParamSpec **props;
			guint n_props, i;

			props = g_object_interface_list_properties (iface, &n_props);
#ifdef NOISY
			warn ("list_properties: %d properties\n", n_props);
#endif
			if (n_props) {
				EXTEND (SP, n_props);

				for (i = 0; i < n_props; i++)
					PUSHs (sv_2mortal (newSVGParamSpec (props[i])));

			}
			g_free (props); /* must free even when n_props==0 */
		}

		g_type_default_interface_unref (iface);
	}
#endif
	else {
		XSRETURN_EMPTY;
	}
#line 1648 "GObject.c"
	PUTBACK;
	return;
    }
}


XS_EUPXS(XS_Glib__Object_set_data); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_Glib__Object_set_data)
{
    dVAR; dXSARGS;
    if (items != 3)
       croak_xs_usage(cv,  "object, key, data");
    {
	GObject *	object = SvGObject (ST(0))
;
	gchar *	key;
	SV *	data = ST(2)
;

	/* same as SvGChar(), but not in a function */
	sv_utf8_upgrade (ST(1));
	key = (gchar *)SvPV_nolen (ST(1))
;
#line 1677 "GObject.xs"
	if (SvROK (data) || !SvIOK (data))
		croak ("set_data only sets unsigned integers, use"
		       " a key in the object hash for anything else");
	g_object_set_data (object, key, INT2PTR (gpointer, SvUV (data)));
#line 1677 "GObject.c"
    }
    XSRETURN_EMPTY;
}


XS_EUPXS(XS_Glib__Object_get_data); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_Glib__Object_get_data)
{
    dVAR; dXSARGS;
    if (items != 2)
       croak_xs_usage(cv,  "object, key");
    {
	GObject *	object = SvGObject (ST(0))
;
	gchar *	key;
	UV	RETVAL;
	dXSTARG;

	/* same as SvGChar(), but not in a function */
	sv_utf8_upgrade (ST(1));
	key = (gchar *)SvPV_nolen (ST(1))
;
#line 1694 "GObject.xs"
        RETVAL = PTR2UV (g_object_get_data (object, key));
#line 1702 "GObject.c"
	XSprePUSH; PUSHu((UV)RETVAL);
    }
    XSRETURN(1);
}


XS_EUPXS(XS_Glib__Object_new_from_pointer); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_Glib__Object_new_from_pointer)
{
    dVAR; dXSARGS;
    if (items < 2 || items > 3)
       croak_xs_usage(cv,  "class, pointer, noinc=FALSE");
    {
	gpointer	pointer = INT2PTR(gpointer,SvIV(ST(1)))
;
	gboolean	noinc;
	SV *	RETVAL;

	if (items < 3)
	    noinc = FALSE;
	else {
	    noinc = (bool)SvTRUE(ST(2))
;
	}
#line 1723 "GObject.xs"
	RETVAL = gperl_new_object (G_OBJECT (pointer), noinc);
#line 1729 "GObject.c"
	RETVAL = sv_2mortal(RETVAL);
	ST(0) = RETVAL;
    }
    XSRETURN(1);
}


XS_EUPXS(XS_Glib__Object_get_pointer); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_Glib__Object_get_pointer)
{
    dVAR; dXSARGS;
    if (items != 1)
       croak_xs_usage(cv,  "object");
    {
	GObject *	object = SvGObject (ST(0))
;
	gpointer	RETVAL;
	dXSTARG;
#line 1737 "GObject.xs"
	RETVAL = object;
#line 1750 "GObject.c"
	XSprePUSH; PUSHi(PTR2IV(RETVAL));
    }
    XSRETURN(1);
}

#if 0
#define XSubPPtmpAAAB 1


XS_EUPXS(XS_Glib__Object_tie_properties); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_Glib__Object_tie_properties)
{
    dVAR; dXSARGS;
    if (items < 1 || items > 2)
       croak_xs_usage(cv,  "object, all=FALSE");
    {
	GObject *	object = SvGObject (ST(0))
;
	gboolean	all;

	if (items < 2)
	    all = FALSE;
	else {
	    all = (bool)SvTRUE(ST(1))
;
	}

	tie_properties(object, all);
    }
    XSRETURN_EMPTY;
}

#endif

XS_EUPXS(XS_Glib__Object___LazyLoader__load); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_Glib__Object___LazyLoader__load)
{
    dVAR; dXSARGS;
    if (items != 1)
       croak_xs_usage(cv,  "package");
    {
#line 1775 "GObject.xs"
	ClassInfo * class_info;
#line 1794 "GObject.c"
	const char *	package = (const char *)SvPV_nolen(ST(0))
;
#line 1777 "GObject.xs"
#ifdef NOISY
	warn ("_load (%s)\n", package);
#endif
	G_LOCK (types_by_package);
	class_info = (ClassInfo*)
		g_hash_table_lookup (types_by_package,
				     package);
	G_UNLOCK (types_by_package);

	/* This can happen when we get called on a package that is not
	 * registered with the type system but is instead manually set up to
	 * inherit from a package that is registered with the type system. For
	 * example:
	 *
	 *   Glib::Object::_LazyLoader
	 *   +----Gtk2::Gdk::Pixmap
	 *        +----Gtk2::Gdk::Bitmap
	 *
	 * When someone tries to call a method on Gtk2::Gdk::Bitmap before
	 * Gtk2::Gdk::Pixmap has been set up, we get in here and class_info ==
	 * NULL.
	 *
	 * So we walk the package's @ISA and look for a package that is
	 * registered.  This is supposed to succeed -- how did we get in here
	 * at all if there is no registered package in the ancestry?
	 */
	if (!class_info)
		class_info = find_registered_type_in_ancestry (package);

	if (!class_info)
		croak ("asked to lazy-load %s, but that package is not "
		       "registered and has no registered packages in its "
		       "ancestry", package);

	class_info_finish_loading (class_info);
#line 1833 "GObject.c"
    }
    XSRETURN_EMPTY;
}

#ifdef __cplusplus
extern "C"
#endif
XS_EXTERNAL(boot_Glib__Object); /* prototype to pass -Wmissing-prototypes */
XS_EXTERNAL(boot_Glib__Object)
{
#if PERL_VERSION_LE(5, 21, 5)
    dVAR; dXSARGS;
#else
    dVAR; dXSBOOTARGSXSAPIVERCHK;
#endif
#if (PERL_REVISION == 5 && PERL_VERSION < 9)
    char* file = __FILE__;
#else
    const char* file = __FILE__;
#endif

    PERL_UNUSED_VAR(file);

    PERL_UNUSED_VAR(cv); /* -W */
    PERL_UNUSED_VAR(items); /* -W */
#if PERL_VERSION_LE(5, 21, 5)
    XS_VERSION_BOOTCHECK;
#  ifdef XS_APIVERSION_BOOTCHECK
    XS_APIVERSION_BOOTCHECK;
#  endif
#endif

#if XSubPPtmpAAAA
        newXS_deffile("Glib::Object::CLONE", XS_Glib__Object_CLONE);
#endif
        newXS_deffile("Glib::Object::set_threadsafe", XS_Glib__Object_set_threadsafe);
        newXS_deffile("Glib::Object::DESTROY", XS_Glib__Object_DESTROY);
        newXS_deffile("Glib::Object::new", XS_Glib__Object_new);
        cv = newXS_deffile("Glib::Object::get", XS_Glib__Object_get);
        XSANY.any_i32 = 0;
        cv = newXS_deffile("Glib::Object::get_property", XS_Glib__Object_get);
        XSANY.any_i32 = 1;
        cv = newXS_deffile("Glib::Object::set", XS_Glib__Object_set);
        XSANY.any_i32 = 0;
        cv = newXS_deffile("Glib::Object::set_property", XS_Glib__Object_set);
        XSANY.any_i32 = 1;
        newXS_deffile("Glib::Object::notify", XS_Glib__Object_notify);
        newXS_deffile("Glib::Object::freeze_notify", XS_Glib__Object_freeze_notify);
        newXS_deffile("Glib::Object::thaw_notify", XS_Glib__Object_thaw_notify);
        cv = newXS_deffile("Glib::Object::find_property", XS_Glib__Object_find_property);
        XSANY.any_i32 = 0;
        cv = newXS_deffile("Glib::Object::list_properties", XS_Glib__Object_find_property);
        XSANY.any_i32 = 1;
        newXS_deffile("Glib::Object::set_data", XS_Glib__Object_set_data);
        newXS_deffile("Glib::Object::get_data", XS_Glib__Object_get_data);
        newXS_deffile("Glib::Object::new_from_pointer", XS_Glib__Object_new_from_pointer);
        newXS_deffile("Glib::Object::get_pointer", XS_Glib__Object_get_pointer);
#if XSubPPtmpAAAB
        newXS_deffile("Glib::Object::tie_properties", XS_Glib__Object_tie_properties);
#endif
        newXS_deffile("Glib::Object::_LazyLoader::_load", XS_Glib__Object___LazyLoader__load);

    /* Initialisation Section */

#if XSubPPtmpAAAA
#endif
#line 1230 "GObject.xs"
	gperl_register_object (G_TYPE_INTERFACE, "Glib::Interface");
	gperl_register_object (G_TYPE_OBJECT, "Glib::Object");
#if GLIB_CHECK_VERSION (2, 10, 0)
	gperl_register_object (G_TYPE_INITIALLY_UNOWNED, "Glib::InitiallyUnowned");
	gperl_register_sink_func (G_TYPE_INITIALLY_UNOWNED, sink_initially_unowned);
#endif
	wrapper_quark = g_quark_from_static_string ("Perl-wrapper-object");

#if XSubPPtmpAAAB
#endif
#line 1911 "GObject.c"

    /* End of Initialisation Section */

#if PERL_VERSION_LE(5, 21, 5)
#  if PERL_VERSION_GE(5, 9, 0)
    if (PL_unitcheckav)
        call_list(PL_scopestack_ix, PL_unitcheckav);
#  endif
    XSRETURN_YES;
#else
    Perl_xs_boot_epilog(aTHX_ ax);
#endif
}

