/* main-loop.c generated by valac 0.36.4, the Vala compiler
 * generated from main-loop.vala, do not modify */

/* This file is part of retro-gtk. License: GPLv3*/

#include <glib.h>
#include <glib-object.h>
#include <float.h>
#include <math.h>
#include <string.h>


#define RETRO_TYPE_MAIN_LOOP (retro_main_loop_get_type ())
#define RETRO_MAIN_LOOP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), RETRO_TYPE_MAIN_LOOP, RetroMainLoop))
#define RETRO_MAIN_LOOP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), RETRO_TYPE_MAIN_LOOP, RetroMainLoopClass))
#define RETRO_IS_MAIN_LOOP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), RETRO_TYPE_MAIN_LOOP))
#define RETRO_IS_MAIN_LOOP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), RETRO_TYPE_MAIN_LOOP))
#define RETRO_MAIN_LOOP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), RETRO_TYPE_MAIN_LOOP, RetroMainLoopClass))

typedef struct _RetroMainLoop RetroMainLoop;
typedef struct _RetroMainLoopClass RetroMainLoopClass;
typedef struct _RetroMainLoopPrivate RetroMainLoopPrivate;

#define RETRO_TYPE_CORE (retro_core_get_type ())
#define RETRO_CORE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), RETRO_TYPE_CORE, RetroCore))
#define RETRO_CORE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), RETRO_TYPE_CORE, RetroCoreClass))
#define RETRO_IS_CORE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), RETRO_TYPE_CORE))
#define RETRO_IS_CORE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), RETRO_TYPE_CORE))
#define RETRO_CORE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), RETRO_TYPE_CORE, RetroCoreClass))

typedef struct _RetroCore RetroCore;
typedef struct _RetroCoreClass RetroCoreClass;
#define _g_object_unref0(var) ((var == NULL) ? NULL : (var = (g_object_unref (var), NULL)))
#define _g_free0(var) ((var == NULL) ? NULL : (var = (g_free (var), NULL)))

struct _RetroMainLoop {
	GObject parent_instance;
	RetroMainLoopPrivate * priv;
};

struct _RetroMainLoopClass {
	GObjectClass parent_class;
};

struct _RetroMainLoopPrivate {
	RetroCore* _core;
	gdouble _speed_rate;
	guint* loop;
};


static gpointer retro_main_loop_parent_class = NULL;

GType retro_main_loop_get_type (void) G_GNUC_CONST;
GType retro_core_get_type (void) G_GNUC_CONST;
#define RETRO_MAIN_LOOP_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), RETRO_TYPE_MAIN_LOOP, RetroMainLoopPrivate))
enum  {
	RETRO_MAIN_LOOP_DUMMY_PROPERTY,
	RETRO_MAIN_LOOP_CORE,
	RETRO_MAIN_LOOP_SPEED_RATE
};
void retro_main_loop_stop (RetroMainLoop* self);
RetroMainLoop* retro_main_loop_new (RetroCore* core);
RetroMainLoop* retro_main_loop_construct (GType object_type, RetroCore* core);
void retro_main_loop_start (RetroMainLoop* self);
gdouble retro_main_loop_get_speed_rate (RetroMainLoop* self);
RetroCore* retro_main_loop_get_core (RetroMainLoop* self);
gdouble retro_core_get_frames_per_second (RetroCore* self);
static gboolean retro_main_loop_run (RetroMainLoop* self);
static gboolean _retro_main_loop_run_gsource_func (gpointer self);
static guint* _uint_dup (guint* self);
void retro_main_loop_reset (RetroMainLoop* self);
void retro_core_reset (RetroCore* self);
void retro_core_run (RetroCore* self);
static void retro_main_loop_on_frames_per_second_changed (RetroMainLoop* self);
void retro_main_loop_set_core (RetroMainLoop* self, RetroCore* value);
void retro_main_loop_set_speed_rate (RetroMainLoop* self, gdouble value);
static GObject * retro_main_loop_constructor (GType type, guint n_construct_properties, GObjectConstructParam * construct_properties);
static void _retro_main_loop___lambda13_ (RetroMainLoop* self, GObject* src, GParamSpec* param);
static void __retro_main_loop___lambda13__g_object_notify (GObject* _sender, GParamSpec* pspec, gpointer self);
static void _retro_main_loop_on_frames_per_second_changed_g_object_notify (GObject* _sender, GParamSpec* pspec, gpointer self);
static void retro_main_loop_finalize (GObject * obj);
static void _vala_retro_main_loop_get_property (GObject * object, guint property_id, GValue * value, GParamSpec * pspec);
static void _vala_retro_main_loop_set_property (GObject * object, guint property_id, const GValue * value, GParamSpec * pspec);


/**
 * Creates a MainLoop to run a {@link Core}.
 *
 * @param core the {@link Core} tu run
 */
RetroMainLoop* retro_main_loop_construct (GType object_type, RetroCore* core) {
	RetroMainLoop * self = NULL;
	RetroCore* _tmp0_;
	g_return_val_if_fail (core != NULL, NULL);
	_tmp0_ = core;
	self = (RetroMainLoop*) g_object_new (object_type, "core", _tmp0_, NULL);
	return self;
}


RetroMainLoop* retro_main_loop_new (RetroCore* core) {
	return retro_main_loop_construct (RETRO_TYPE_MAIN_LOOP, core);
}


/**
 * Starts running the {@link core}.
 */
static gboolean _retro_main_loop_run_gsource_func (gpointer self) {
	gboolean result;
	result = retro_main_loop_run ((RetroMainLoop*) self);
	return result;
}


static guint* _uint_dup (guint* self) {
	guint* dup;
	dup = g_new0 (guint, 1);
	memcpy (dup, self, sizeof (guint));
	return dup;
}


static gpointer __uint_dup0 (gpointer self) {
	return self ? _uint_dup (self) : NULL;
}


void retro_main_loop_start (RetroMainLoop* self) {
	gboolean _tmp0_ = FALSE;
	guint* _tmp1_;
	g_return_if_fail (self != NULL);
	_tmp1_ = self->priv->loop;
	if (_tmp1_ == NULL) {
		gdouble _tmp2_;
		_tmp2_ = self->priv->_speed_rate;
		_tmp0_ = _tmp2_ > ((gdouble) 0);
	} else {
		_tmp0_ = FALSE;
	}
	if (_tmp0_) {
		RetroCore* _tmp3_;
		gdouble _tmp4_;
		gdouble _tmp5_;
		gdouble _tmp6_;
		guint _tmp7_;
		guint* _tmp8_;
		_tmp3_ = self->priv->_core;
		_tmp4_ = retro_core_get_frames_per_second (_tmp3_);
		_tmp5_ = _tmp4_;
		_tmp6_ = self->priv->_speed_rate;
		_tmp7_ = g_timeout_add_full (G_PRIORITY_DEFAULT, (guint) (1000 / (_tmp5_ * _tmp6_)), _retro_main_loop_run_gsource_func, g_object_ref (self), g_object_unref);
		_tmp8_ = __uint_dup0 (&_tmp7_);
		_g_free0 (self->priv->loop);
		self->priv->loop = _tmp8_;
	}
}


/**
 * Resets the {@link core}.
 */
void retro_main_loop_reset (RetroMainLoop* self) {
	RetroCore* _tmp0_;
	g_return_if_fail (self != NULL);
	_tmp0_ = self->priv->_core;
	if (_tmp0_ != NULL) {
		RetroCore* _tmp1_;
		_tmp1_ = self->priv->_core;
		retro_core_reset (_tmp1_);
	}
}


/**
 * Stops running the {@link core}.
 */
void retro_main_loop_stop (RetroMainLoop* self) {
	guint* _tmp0_;
	g_return_if_fail (self != NULL);
	_tmp0_ = self->priv->loop;
	if (_tmp0_ != NULL) {
		guint* _tmp1_;
		_tmp1_ = self->priv->loop;
		g_source_remove (*_tmp1_);
		_g_free0 (self->priv->loop);
		self->priv->loop = NULL;
	}
}


static gboolean retro_main_loop_run (RetroMainLoop* self) {
	gboolean result = FALSE;
	gboolean _tmp0_ = FALSE;
	RetroCore* _tmp1_;
	g_return_val_if_fail (self != NULL, FALSE);
	_tmp1_ = self->priv->_core;
	if (_tmp1_ != NULL) {
		guint* _tmp2_;
		_tmp2_ = self->priv->loop;
		_tmp0_ = _tmp2_ != NULL;
	} else {
		_tmp0_ = FALSE;
	}
	if (_tmp0_) {
		RetroCore* _tmp3_;
		_tmp3_ = self->priv->_core;
		retro_core_run (_tmp3_);
		result = TRUE;
		return result;
	}
	result = FALSE;
	return result;
}


static void retro_main_loop_on_frames_per_second_changed (RetroMainLoop* self) {
	guint* _tmp0_;
	g_return_if_fail (self != NULL);
	_tmp0_ = self->priv->loop;
	if (_tmp0_ == NULL) {
		return;
	}
	retro_main_loop_stop (self);
	retro_main_loop_start (self);
}


RetroCore* retro_main_loop_get_core (RetroMainLoop* self) {
	RetroCore* result;
	RetroCore* _tmp0_;
	g_return_val_if_fail (self != NULL, NULL);
	_tmp0_ = self->priv->_core;
	result = _tmp0_;
	return result;
}


static gpointer _g_object_ref0 (gpointer self) {
	return self ? g_object_ref (self) : NULL;
}


void retro_main_loop_set_core (RetroMainLoop* self, RetroCore* value) {
	g_return_if_fail (self != NULL);
	if (retro_main_loop_get_core (self) != value) {
		RetroCore* _tmp0_;
		RetroCore* _tmp1_;
		_tmp0_ = value;
		_tmp1_ = _g_object_ref0 (_tmp0_);
		_g_object_unref0 (self->priv->_core);
		self->priv->_core = _tmp1_;
		g_object_notify ((GObject *) self, "core");
	}
}


gdouble retro_main_loop_get_speed_rate (RetroMainLoop* self) {
	gdouble result;
	gdouble _tmp0_;
	g_return_val_if_fail (self != NULL, 0.0);
	_tmp0_ = self->priv->_speed_rate;
	result = _tmp0_;
	return result;
}


void retro_main_loop_set_speed_rate (RetroMainLoop* self, gdouble value) {
	g_return_if_fail (self != NULL);
	if (retro_main_loop_get_speed_rate (self) != value) {
		gdouble _tmp0_;
		_tmp0_ = value;
		self->priv->_speed_rate = _tmp0_;
		g_object_notify ((GObject *) self, "speed-rate");
	}
}


static void _retro_main_loop___lambda13_ (RetroMainLoop* self, GObject* src, GParamSpec* param) {
	GParamSpec* _tmp0_;
	const gchar* _tmp1_;
	const gchar* _tmp2_;
	GQuark _tmp4_ = 0U;
	static GQuark _tmp3_label0 = 0;
	g_return_if_fail (src != NULL);
	g_return_if_fail (param != NULL);
	_tmp0_ = param;
	_tmp1_ = g_param_spec_get_name (_tmp0_);
	_tmp2_ = _tmp1_;
	_tmp4_ = (NULL == _tmp2_) ? 0 : g_quark_from_string (_tmp2_);
	if (_tmp4_ == ((0 != _tmp3_label0) ? _tmp3_label0 : (_tmp3_label0 = g_quark_from_static_string ("speed_rate")))) {
		switch (0) {
			default:
			{
				guint* _tmp5_;
				_tmp5_ = self->priv->loop;
				if (_tmp5_ != NULL) {
					retro_main_loop_stop (self);
					retro_main_loop_start (self);
				}
				break;
			}
		}
	}
}


static void __retro_main_loop___lambda13__g_object_notify (GObject* _sender, GParamSpec* pspec, gpointer self) {
	_retro_main_loop___lambda13_ ((RetroMainLoop*) self, _sender, pspec);
}


static void _retro_main_loop_on_frames_per_second_changed_g_object_notify (GObject* _sender, GParamSpec* pspec, gpointer self) {
	retro_main_loop_on_frames_per_second_changed ((RetroMainLoop*) self);
}


static GObject * retro_main_loop_constructor (GType type, guint n_construct_properties, GObjectConstructParam * construct_properties) {
	GObject * obj;
	GObjectClass * parent_class;
	RetroMainLoop * self;
	RetroCore* _tmp0_;
	parent_class = G_OBJECT_CLASS (retro_main_loop_parent_class);
	obj = parent_class->constructor (type, n_construct_properties, construct_properties);
	self = G_TYPE_CHECK_INSTANCE_CAST (obj, RETRO_TYPE_MAIN_LOOP, RetroMainLoop);
	_g_free0 (self->priv->loop);
	self->priv->loop = NULL;
	g_signal_connect_object ((GObject*) self, "notify", (GCallback) __retro_main_loop___lambda13__g_object_notify, self, 0);
	_tmp0_ = self->priv->_core;
	g_signal_connect_object ((GObject*) _tmp0_, "notify::frames-per-second", (GCallback) _retro_main_loop_on_frames_per_second_changed_g_object_notify, self, 0);
	return obj;
}


static void retro_main_loop_class_init (RetroMainLoopClass * klass) {
	retro_main_loop_parent_class = g_type_class_peek_parent (klass);
	g_type_class_add_private (klass, sizeof (RetroMainLoopPrivate));
	G_OBJECT_CLASS (klass)->get_property = _vala_retro_main_loop_get_property;
	G_OBJECT_CLASS (klass)->set_property = _vala_retro_main_loop_set_property;
	G_OBJECT_CLASS (klass)->constructor = retro_main_loop_constructor;
	G_OBJECT_CLASS (klass)->finalize = retro_main_loop_finalize;
	/**
	 * The core to run.
	 */
	g_object_class_install_property (G_OBJECT_CLASS (klass), RETRO_MAIN_LOOP_CORE, g_param_spec_object ("core", "core", "core", RETRO_TYPE_CORE, G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT));
	/**
	 * The speed factor at which the {@link core} should run.
	 */
	g_object_class_install_property (G_OBJECT_CLASS (klass), RETRO_MAIN_LOOP_SPEED_RATE, g_param_spec_double ("speed-rate", "speed-rate", "speed-rate", -G_MAXDOUBLE, G_MAXDOUBLE, (gdouble) 1, G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT));
}


static void retro_main_loop_instance_init (RetroMainLoop * self) {
	self->priv = RETRO_MAIN_LOOP_GET_PRIVATE (self);
	self->priv->_speed_rate = (gdouble) 1;
}


static void retro_main_loop_finalize (GObject * obj) {
	RetroMainLoop * self;
	self = G_TYPE_CHECK_INSTANCE_CAST (obj, RETRO_TYPE_MAIN_LOOP, RetroMainLoop);
	retro_main_loop_stop (self);
	_g_object_unref0 (self->priv->_core);
	_g_free0 (self->priv->loop);
	G_OBJECT_CLASS (retro_main_loop_parent_class)->finalize (obj);
}


/**
 * Runs a {@link Core} in a GLib or Gtk main loop.
 *
 * It may cause problems if the core takes more time than expected to run a
 * frame.
 */
GType retro_main_loop_get_type (void) {
	static volatile gsize retro_main_loop_type_id__volatile = 0;
	if (g_once_init_enter (&retro_main_loop_type_id__volatile)) {
		static const GTypeInfo g_define_type_info = { sizeof (RetroMainLoopClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) retro_main_loop_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (RetroMainLoop), 0, (GInstanceInitFunc) retro_main_loop_instance_init, NULL };
		GType retro_main_loop_type_id;
		retro_main_loop_type_id = g_type_register_static (G_TYPE_OBJECT, "RetroMainLoop", &g_define_type_info, 0);
		g_once_init_leave (&retro_main_loop_type_id__volatile, retro_main_loop_type_id);
	}
	return retro_main_loop_type_id__volatile;
}


static void _vala_retro_main_loop_get_property (GObject * object, guint property_id, GValue * value, GParamSpec * pspec) {
	RetroMainLoop * self;
	self = G_TYPE_CHECK_INSTANCE_CAST (object, RETRO_TYPE_MAIN_LOOP, RetroMainLoop);
	switch (property_id) {
		case RETRO_MAIN_LOOP_CORE:
		g_value_set_object (value, retro_main_loop_get_core (self));
		break;
		case RETRO_MAIN_LOOP_SPEED_RATE:
		g_value_set_double (value, retro_main_loop_get_speed_rate (self));
		break;
		default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
		break;
	}
}


static void _vala_retro_main_loop_set_property (GObject * object, guint property_id, const GValue * value, GParamSpec * pspec) {
	RetroMainLoop * self;
	self = G_TYPE_CHECK_INSTANCE_CAST (object, RETRO_TYPE_MAIN_LOOP, RetroMainLoop);
	switch (property_id) {
		case RETRO_MAIN_LOOP_CORE:
		retro_main_loop_set_core (self, g_value_get_object (value));
		break;
		case RETRO_MAIN_LOOP_SPEED_RATE:
		retro_main_loop_set_speed_rate (self, g_value_get_double (value));
		break;
		default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
		break;
	}
}



