[retro-gtk/wip/aplazas/c-port: 7/19] Port MainLoop to C



commit e8e701e510051f02abe2fa07903f95a5ea0cb2a0
Author: Adrien Plazas <kekun plazas laposte net>
Date:   Fri Sep 8 13:03:49 2017 +0200

    Port MainLoop to C

 retro-gtk/Makefile.am         |    6 +-
 retro-gtk/loop/main-loop.vala |  104 ------------
 retro-gtk/retro-gtk.h         |    1 +
 retro-gtk/retro-main-loop.c   |  349 +++++++++++++++++++++++++++++++++++++++++
 retro-gtk/retro-main-loop.h   |   34 ++++
 5 files changed, 388 insertions(+), 106 deletions(-)
---
diff --git a/retro-gtk/Makefile.am b/retro-gtk/Makefile.am
index bd0edee..e510d90 100644
--- a/retro-gtk/Makefile.am
+++ b/retro-gtk/Makefile.am
@@ -40,6 +40,7 @@ retro_gtk_public_h_sources = \
        retro-joypad-id.h \
        retro-lightgun-id.h \
        retro-log.h \
+       retro-main-loop.h \
        retro-memory-type.h \
        retro-module-iterator.h \
        retro-module-query.h \
@@ -74,8 +75,6 @@ libretro_gtk_la_SOURCES = \
        input/input-device-manager.vala \
        input/retro-keyboard-key.c \
        \
-       loop/main-loop.vala \
-       \
        core.vala \
        core-error.vala \
        retro.vala \
@@ -92,6 +91,7 @@ libretro_gtk_la_SOURCES = \
        retro-joypad-id.c \
        retro-lightgun-id.c \
        retro-log.c \
+       retro-main-loop.c \
        retro-memory-type.c \
        retro-module.c \
        retro-module-iterator.c \
@@ -124,6 +124,8 @@ retro-environment.c: retro-gtk-internal.h libretro-environment.h
 
 retro-log.c: retro-gtk-internal.h
 
+retro-main-loop.c: retro-gtk-internal.h
+
 retro-module.c: retro-gtk-internal.h
 
 retro-module-iterator.c: retro-gtk-internal.h
diff --git a/retro-gtk/retro-gtk.h b/retro-gtk/retro-gtk.h
index 3cdcf2c..4f0affb 100644
--- a/retro-gtk/retro-gtk.h
+++ b/retro-gtk/retro-gtk.h
@@ -19,6 +19,7 @@
 #include "retro-joypad-id.h"
 #include "retro-lightgun-id.h"
 #include "retro-log.h"
+#include "retro-main-loop.h"
 #include "retro-memory-type.h"
 #include "retro-module-iterator.h"
 #include "retro-module-query.h"
diff --git a/retro-gtk/retro-main-loop.c b/retro-gtk/retro-main-loop.c
new file mode 100644
index 0000000..99bfd54
--- /dev/null
+++ b/retro-gtk/retro-main-loop.c
@@ -0,0 +1,349 @@
+// This file is part of retro-gtk. License: GPL-3.0+.
+
+#include "retro-main-loop.h"
+
+#include "retro-gtk-internal.h"
+
+struct _RetroMainLoop
+{
+  GObject parent_instance;
+  RetroCore *core;
+  gdouble speed_rate;
+  glong loop;
+  gulong core_fps_id;
+};
+
+G_DEFINE_TYPE (RetroMainLoop, retro_main_loop, G_TYPE_OBJECT)
+
+enum  {
+  PROP_CORE = 1,
+  PROP_SPEED_RATE,
+  N_PROPS,
+};
+
+static GParamSpec *properties [N_PROPS];
+
+/* Private */
+
+static void
+retro_main_loop_finalize (GObject *object)
+{
+  RetroMainLoop *self = RETRO_MAIN_LOOP (object);
+
+  retro_main_loop_stop (self);
+  g_clear_object (&self->core);
+
+  G_OBJECT_CLASS (retro_main_loop_parent_class)->finalize (object);
+}
+
+static void
+retro_main_loop_get_property (GObject    *object,
+                              guint       prop_id,
+                              GValue     *value,
+                              GParamSpec *pspec)
+{
+  RetroMainLoop *self = RETRO_MAIN_LOOP (object);
+
+  switch (prop_id) {
+  case PROP_CORE:
+    g_value_set_object (value, retro_main_loop_get_core (self));
+
+    break;
+  case PROP_SPEED_RATE:
+    g_value_set_double (value, retro_main_loop_get_speed_rate (self));
+
+    break;
+  default:
+    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+
+    break;
+  }
+}
+
+static void
+retro_main_loop_set_property (GObject      *object,
+                              guint         prop_id,
+                              const GValue *value,
+                              GParamSpec   *pspec)
+{
+  RetroMainLoop *self = RETRO_MAIN_LOOP (object);
+
+  switch (prop_id) {
+  case PROP_CORE:
+    retro_main_loop_set_core (self, g_value_get_object (value));
+
+    break;
+  case PROP_SPEED_RATE:
+    retro_main_loop_set_speed_rate (self, g_value_get_double (value));
+
+    break;
+  default:
+    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+
+    break;
+  }
+}
+
+static void
+retro_main_loop_class_init (RetroMainLoopClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->finalize = retro_main_loop_finalize;
+  object_class->get_property = retro_main_loop_get_property;
+  object_class->set_property = retro_main_loop_set_property;
+
+  properties[PROP_CORE] =
+    g_param_spec_object ("core",
+                         "Core",
+                         "The core",
+                         RETRO_TYPE_CORE,
+                         G_PARAM_READWRITE |
+                         G_PARAM_STATIC_NAME |
+                         G_PARAM_STATIC_NICK |
+                         G_PARAM_STATIC_BLURB |
+                         G_PARAM_CONSTRUCT);
+  g_object_class_install_property (G_OBJECT_CLASS (klass),
+                                   PROP_CORE,
+                                   properties[PROP_CORE]);
+
+  properties[PROP_SPEED_RATE] =
+    g_param_spec_double ("speed-rate",
+                         "Speed rate",
+                         "The speed ratio at wich the core will run",
+                         -G_MAXDOUBLE, G_MAXDOUBLE, 1.0,
+                         G_PARAM_READWRITE |
+                         G_PARAM_STATIC_NAME |
+                         G_PARAM_STATIC_NICK |
+                         G_PARAM_STATIC_BLURB |
+                         G_PARAM_CONSTRUCT);
+  g_object_class_install_property (G_OBJECT_CLASS (klass),
+                                   PROP_SPEED_RATE,
+                                   properties[PROP_SPEED_RATE]);
+}
+
+static void
+retro_main_loop_on_notification (GObject    *src,
+                                 GParamSpec *param,
+                                 gpointer    user_data)
+{
+  RetroMainLoop *self = RETRO_MAIN_LOOP (user_data);
+  const gchar *param_name;
+
+  g_return_if_fail (self != NULL);
+  g_return_if_fail (src != NULL);
+  g_return_if_fail (param != NULL);
+
+  if (self->loop < 0)
+    return;
+
+  param_name = g_param_spec_get_name (param);
+  if (g_strcmp0 (param_name, "speed-rate") != 0)
+    return;
+
+  retro_main_loop_stop (self);
+  retro_main_loop_start (self);
+}
+
+static void
+retro_main_loop_on_frames_per_second_changed (GObject    *sender,
+                                              GParamSpec *pspec,
+                                              gpointer    user_data)
+{
+  RetroMainLoop *self = RETRO_MAIN_LOOP (user_data);
+
+  g_return_if_fail (self != NULL);
+
+  if (self->loop < 0)
+    return;
+
+  retro_main_loop_stop (self);
+  retro_main_loop_start (self);
+}
+
+static void
+retro_main_loop_init (RetroMainLoop *self)
+{
+  self->loop = -1;
+
+  g_signal_connect_object (G_OBJECT (self),
+                           "notify",
+                           (GCallback) retro_main_loop_on_notification,
+                           self,
+                           0);
+}
+
+static gboolean
+retro_main_loop_run (RetroMainLoop *self)
+{
+  g_return_val_if_fail (self != NULL, FALSE);
+
+  if (self->core == NULL || self->loop < 0)
+    return FALSE;
+
+  retro_core_run (self->core);
+
+  return TRUE;
+}
+
+/* Public */
+
+/**
+ * retro_main_loop_get_speed_rate:
+ * @self: a #RetroMainLoop
+ *
+ * Gets the speed rate at which to run the core.
+ *
+ * Returns: the speed rate
+ */
+gdouble
+retro_main_loop_get_speed_rate (RetroMainLoop *self)
+{
+  g_return_val_if_fail (self != NULL, 1.0);
+
+  return self->speed_rate;
+}
+
+/**
+ * retro_main_loop_get_core:
+ * @self: a #RetroMainLoop
+ *
+ * Gets the core handled by @self.
+ *
+ * Returns: (transfer none): a #RetroCore
+ */
+RetroCore *
+retro_main_loop_get_core (RetroMainLoop *self)
+{
+  g_return_val_if_fail (self != NULL, NULL);
+
+  return self->core;
+}
+
+/**
+ * retro_main_loop_set_core:
+ * @self: a #RetroMainLoop
+ * @core: (nullable): a #RetroCore, or %NULL
+ *
+ * Sets @core as the #RetroCore handled by @self.
+ */
+void
+retro_main_loop_set_core (RetroMainLoop *self,
+                          RetroCore     *core)
+{
+  g_return_if_fail (self != NULL);
+
+  if (self->core == core)
+    return;
+
+  retro_main_loop_stop (self);
+
+  if (self->core != NULL) {
+    g_signal_handler_disconnect (G_OBJECT (self->core), self->core_fps_id);
+    g_clear_object (&self->core);
+  }
+
+  if (core != NULL) {
+    self->core = g_object_ref (core);
+    self->core_fps_id =
+      g_signal_connect_object (G_OBJECT (self->core),
+                               "notify::frames-per-second",
+                               (GCallback) retro_main_loop_on_frames_per_second_changed,
+                               self,
+                               0);
+  }
+
+  g_object_notify_by_pspec ((GObject *) self, properties[PROP_CORE]);
+}
+
+/**
+ * retro_main_loop_set_speed_rate:
+ * @self: a #RetroMainLoop
+ * @speed_rate: a speed rate
+ *
+ * Sets the speed rate at which to run the core.
+ */
+void
+retro_main_loop_set_speed_rate (RetroMainLoop *self,
+                                gdouble        speed_rate)
+{
+  g_return_if_fail (self != NULL);
+
+  if (self->speed_rate == speed_rate)
+    return;
+
+  self->speed_rate = speed_rate;
+  g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SPEED_RATE]);
+}
+
+/**
+ * retro_main_loop_start:
+ * @self: a #RetroMainLoop
+ *
+ * Starts runing the core. If the core was stopped, it will restart from this moment.
+ */
+void
+retro_main_loop_start (RetroMainLoop *self)
+{
+  gdouble fps;
+
+  g_return_if_fail (self != NULL);
+  g_return_if_fail (self->core != NULL);
+
+  if (self->loop >= 0 || self->speed_rate <= 0)
+    return;
+
+  // TODO What if fps <= 0?
+  fps = retro_core_get_frames_per_second (self->core);
+  self->loop = g_timeout_add_full (G_PRIORITY_DEFAULT,
+                                   (guint) (1000 / (fps * self->speed_rate)),
+                                   (GSourceFunc) retro_main_loop_run,
+                                   g_object_ref (self),
+                                   g_object_unref);
+}
+
+/**
+ * retro_main_loop_reset:
+ * @self: a #RetroMainLoop
+ *
+ * Resets the core. Results depend on the core's implementation.
+ */
+void
+retro_main_loop_reset (RetroMainLoop *self)
+{
+  g_return_if_fail (self != NULL);
+  g_return_if_fail (self->core != NULL);
+
+  retro_core_reset (self->core);
+}
+
+/**
+ * retro_main_loop_stop:
+ * @self: a #RetroMainLoop
+ *
+ * Stops runing the core.
+ */
+void
+retro_main_loop_stop (RetroMainLoop *self)
+{
+  g_return_if_fail (self != NULL);
+
+  if (self->loop < 0)
+    return;
+
+  g_source_remove (self->loop);
+  self->loop = -1;
+}
+
+/**
+ * retro_main_loop_new:
+ *
+ * Creates a new #RetroMainLoop.
+ *
+ * Returns: (transfer full): a new #RetroMainLoop
+ */
+RetroMainLoop *
+retro_main_loop_new (RetroCore *core)
+{
+  return g_object_new (RETRO_TYPE_MAIN_LOOP, "core", core, NULL);
+}
diff --git a/retro-gtk/retro-main-loop.h b/retro-gtk/retro-main-loop.h
new file mode 100644
index 0000000..a105d4f
--- /dev/null
+++ b/retro-gtk/retro-main-loop.h
@@ -0,0 +1,34 @@
+// This file is part of retro-gtk. License: GPL-3.0+.
+
+#ifndef RETRO_MAIN_LOOP_H
+#define RETRO_MAIN_LOOP_H
+
+#if !defined(__RETRO_GTK_INSIDE__) && !defined(RETRO_GTK_COMPILATION)
+# error "Only <retro-gtk.h> can be included directly."
+#endif
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+// FIXME Remove as soon as possible.
+typedef struct _RetroCore RetroCore;
+
+#define RETRO_TYPE_MAIN_LOOP (retro_main_loop_get_type())
+
+G_DECLARE_FINAL_TYPE (RetroMainLoop, retro_main_loop, RETRO, MAIN_LOOP, GObject)
+
+RetroMainLoop *retro_main_loop_new (RetroCore *core);
+RetroCore *retro_main_loop_get_core (RetroMainLoop *self);
+void retro_main_loop_set_core (RetroMainLoop *self,
+                               RetroCore     *core);
+void retro_main_loop_start (RetroMainLoop *self);
+void retro_main_loop_reset (RetroMainLoop *self);
+void retro_main_loop_stop (RetroMainLoop *self);
+gdouble retro_main_loop_get_speed_rate (RetroMainLoop *self);
+void retro_main_loop_set_speed_rate (RetroMainLoop *self,
+                                     gdouble        speed_rate);
+
+G_END_DECLS
+
+#endif /* RETRO_MAIN_LOOP_H */


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]