[retro-gtk: 2/2] Port the variable interface to C



commit f9f780192e5c5def12b31d782b9038e29aaa4dd4
Author: Adrien Plazas <kekun plazas laposte net>
Date:   Thu May 18 16:33:22 2017 +0200

    Port the variable interface to C
    
    Also tweak the API to make it simpler and drop the useless Variables
    interface.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=782501

 retro-gtk/Makefile.am             |    8 +-
 retro-gtk/core.vala               |    2 -
 retro-gtk/retro-core.c            |    2 +-
 retro-gtk/retro-core.h            |    2 +
 retro-gtk/retro-environment.c     |   33 ++++--
 retro-gtk/retro-option.c          |  160 ++++++++++++++++++++++++++++
 retro-gtk/retro-option.h          |   27 +++++
 retro-gtk/retro-options.c         |  187 +++++++++++++++++++++++++++++++++
 retro-gtk/retro-options.h         |   35 ++++++
 retro-gtk/retro-variable.h        |   20 ++++
 retro-gtk/variable/options.vala   |  206 -------------------------------------
 retro-gtk/variable/variables.vala |   67 ------------
 12 files changed, 458 insertions(+), 291 deletions(-)
---
diff --git a/retro-gtk/Makefile.am b/retro-gtk/Makefile.am
index b506789..ad059da 100644
--- a/retro-gtk/Makefile.am
+++ b/retro-gtk/Makefile.am
@@ -38,9 +38,6 @@ libretro_gtk_la_SOURCES = \
        \
        loop/main-loop.vala \
        \
-       variable/options.vala \
-       variable/variables.vala \
-       \
        core.vala \
        core-error.vala \
        memory.vala \
@@ -55,6 +52,8 @@ libretro_gtk_la_SOURCES = \
        retro-module.c \
        retro-module-query.vala \
        retro-module-iterator.vala \
+       retro-option.c \
+       retro-options.c \
        rumble.vala \
        video.vala \
        retro-core.c \
@@ -107,6 +106,9 @@ libretro_gtk_la_LIBADD = $(RETRO_GTK_LIBS)
 retro_gtkincludedir = $(includedir)/retro-gtk-0.12
 retro_gtkinclude_HEADERS = \
        retro-gtk.h \
+       retro-option.h \
+       retro-options.h \
+       retro-variable.h \
        $(NULL)
 
 # Add unstable API guard
diff --git a/retro-gtk/core.vala b/retro-gtk/core.vala
index e898f2f..3778337 100644
--- a/retro-gtk/core.vala
+++ b/retro-gtk/core.vala
@@ -138,8 +138,6 @@ public class Core : Object {
         */
        public signal bool message (string message, uint frames);
 
-       internal Variables variables_interface;
-
        internal void *environment_internal;
 
        /**
diff --git a/retro-gtk/retro-core.c b/retro-gtk/retro-core.c
index d925c85..5ff2763 100644
--- a/retro-gtk/retro-core.c
+++ b/retro-gtk/retro-core.c
@@ -668,7 +668,7 @@ retro_core_constructor (RetroCore   *self,
   g_free (libretro_path);
 
   retro_core_set_callbacks (self);
-  self->variables_interface = RETRO_VARIABLES (retro_options_new ());
+  internal->options = retro_options_new ();
 }
 
 // FIXME Make static as soon as possible.
diff --git a/retro-gtk/retro-core.h b/retro-gtk/retro-core.h
index d651c05..b5c9369 100644
--- a/retro-gtk/retro-core.h
+++ b/retro-gtk/retro-core.h
@@ -6,6 +6,7 @@
 #include "retro-disk-control-callback.h"
 #include "retro-gtk-internal.h"
 #include "retro-module.h"
+#include "retro-options.h"
 #include "retro-rotation.h"
 
 G_BEGIN_DECLS
@@ -30,6 +31,7 @@ struct _RetroCoreEnvironmentInternal {
   gdouble sample_rate;
 
   RetroKeyboardCallback keyboard_callback;
+  RetroOptions *options;
 };
 
 gchar *retro_core_get_name (RetroCore *self);
diff --git a/retro-gtk/retro-environment.c b/retro-gtk/retro-environment.c
index b401556..afef623 100644
--- a/retro-gtk/retro-environment.c
+++ b/retro-gtk/retro-environment.c
@@ -195,20 +195,29 @@ static gboolean
 get_variable (RetroCore     *self,
               RetroVariable *variable)
 {
-  gchar *result;
+  RetroCoreEnvironmentInternal *internal;
+  const gchar *value;
+
+  internal = RETRO_CORE_ENVIRONMENT_INTERNAL (self);
 
-  result = retro_variables_get_variable (self->variables_interface,
-                                         variable->key);
-  variable->value = result ? result : "";
+  if (!retro_options_contains (internal->options, variable->key))
+    return FALSE;
 
-  return !!result;
+  value = retro_options_get_option_value (internal->options, variable->key);
+  variable->value = g_strdup (value); // FIXME Is that a memory leak?
+
+  return TRUE;
 }
 
 static gboolean
 get_variable_update (RetroCore *self,
                      gboolean  *update)
 {
-  *update = retro_variables_get_variable_update (self->variables_interface);
+  RetroCoreEnvironmentInternal *internal;
+
+  internal = RETRO_CORE_ENVIRONMENT_INTERNAL (self);
+
+  *update = retro_options_get_variable_update (internal->options);
 
   return TRUE;
 }
@@ -299,13 +308,13 @@ static gboolean
 set_variables (RetroCore     *self,
                RetroVariable *variable_array)
 {
-  int length;
+  RetroCoreEnvironmentInternal *internal;
+  int i;
+
+  internal = RETRO_CORE_ENVIRONMENT_INTERNAL (self);
 
-  for (length = 0 ;
-       variable_array[length].key && variable_array[length].value ;
-       length++);
-  retro_variables_set_variable (self->variables_interface,
-                                variable_array, length);
+  for (i = 0 ; variable_array[i].key && variable_array[i].value ; i++)
+    retro_options_insert_variable (internal->options, &variable_array[i]);
 
   return TRUE;
 }
diff --git a/retro-gtk/retro-option.c b/retro-gtk/retro-option.c
new file mode 100644
index 0000000..2368293
--- /dev/null
+++ b/retro-gtk/retro-option.c
@@ -0,0 +1,160 @@
+// This file is part of retro-gtk. License: GPL-3.0+.
+
+#include "retro-option.h"
+
+struct _RetroOption
+{
+  GObject parent_instance;
+  gchar *key;
+  gchar *description;
+  gchar **values;
+  gchar *current;
+};
+
+G_DEFINE_TYPE (RetroOption, retro_option, G_TYPE_OBJECT)
+
+#define RETRO_OPTION_ERROR (retro_option_error_quark ())
+
+enum {
+  RETRO_OPTION_ERROR_NO_DESCRIPTION_SEPARATOR,
+  RETRO_OPTION_ERROR_NO_VALUES,
+  RETRO_OPTION_ERROR_INVALID_VALUE,
+};
+
+/* Private */
+
+static GQuark
+retro_option_error_quark (void)
+{
+  return g_quark_from_static_string ("retro-option-error-quark");
+}
+
+static void
+retro_option_finalize (GObject *object)
+{
+  RetroOption *self = (RetroOption *)object;
+
+  g_free (self->key);
+  g_free (self->description);
+  g_strfreev (self->values);
+  g_free (self->current);
+
+  G_OBJECT_CLASS (retro_option_parent_class)->finalize (object);
+}
+
+static void
+retro_option_class_init (RetroOptionClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->finalize = retro_option_finalize;
+}
+
+static void
+retro_option_init (RetroOption *self)
+{
+}
+
+/* Public */
+
+const gchar *
+retro_option_get_key (RetroOption *self)
+{
+  g_return_val_if_fail (RETRO_IS_OPTION (self), NULL);
+
+  return self->key;
+}
+
+const gchar *
+retro_option_get_description (RetroOption *self)
+{
+  g_return_val_if_fail (RETRO_IS_OPTION (self), NULL);
+
+  return self->description;
+}
+
+const gchar **
+retro_option_get_values (RetroOption *self)
+{
+  g_return_val_if_fail (RETRO_IS_OPTION (self), NULL);
+
+  return self->values;
+}
+
+const gchar *
+retro_option_get_current (RetroOption *self)
+{
+  g_return_val_if_fail (RETRO_IS_OPTION (self), NULL);
+
+  return self->current;
+}
+
+void
+retro_option_set_current (RetroOption  *self,
+                          const gchar  *current,
+                          GError      **error)
+{
+  g_return_if_fail (RETRO_IS_OPTION (self));
+  g_return_if_fail (current != NULL);
+
+  g_message ("%s, %s", self->current, current);
+  if (g_strcmp0 (self->current, current) == 0)
+    return;
+
+  if (G_UNLIKELY (g_strv_contains ((const gchar *const *) self->values, current))) {
+    g_set_error_literal (error,
+                         RETRO_OPTION_ERROR,
+                         RETRO_OPTION_ERROR_INVALID_VALUE,
+                         "Unexpected option value: option %s doesn’t have value %s.");
+
+    return;
+  }
+
+  g_free (self->current);
+  self->current = g_strdup (current);
+}
+
+RetroOption *
+retro_option_new (const RetroVariable  *variable,
+                  GError              **error)
+{
+  RetroOption *self;
+  gchar *description_separator;
+  gchar **values;
+
+  g_return_val_if_fail (variable != NULL, NULL);
+  g_return_val_if_fail (variable->key != NULL, NULL);
+  g_return_val_if_fail (variable->value != NULL, NULL);
+
+  description_separator = g_strstr_len (variable->value, -1, "; ");
+  if (G_UNLIKELY (description_separator == NULL)) {
+    g_set_error_literal (error,
+                         RETRO_OPTION_ERROR,
+                         RETRO_OPTION_ERROR_NO_DESCRIPTION_SEPARATOR,
+                         "Unexpected variable format: no description separator found.");
+
+    return NULL;
+  }
+
+  values = g_strsplit (description_separator + 2, "|", 0);
+  if (G_UNLIKELY (*values == NULL)) {
+    g_strfreev (values);
+
+    g_set_error_literal (error,
+                         RETRO_OPTION_ERROR,
+                         RETRO_OPTION_ERROR_NO_VALUES,
+                         "Unexpected variable format: no values.");
+
+    return NULL;
+  }
+
+  self = g_object_new (RETRO_TYPE_OPTION, NULL);
+
+  self->key = g_strdup (variable->key);
+  self->description = g_strndup (variable->value,
+                                 description_separator - variable->value);
+  self->values = values;
+  self->current = g_strdup (values[0]);
+
+  return self;
+}
diff --git a/retro-gtk/retro-option.h b/retro-gtk/retro-option.h
new file mode 100644
index 0000000..b49ca09
--- /dev/null
+++ b/retro-gtk/retro-option.h
@@ -0,0 +1,27 @@
+// This file is part of retro-gtk. License: GPL-3.0+.
+
+#ifndef RETRO_OPTION_H
+#define RETRO_OPTION_H
+
+#include <glib-object.h>
+#include "retro-variable.h"
+
+G_BEGIN_DECLS
+
+#define RETRO_TYPE_OPTION (retro_option_get_type())
+
+G_DECLARE_FINAL_TYPE (RetroOption, retro_option, RETRO, OPTION, GObject)
+
+RetroOption *retro_option_new (const RetroVariable  *variable,
+                               GError              **error);
+const gchar *retro_option_get_key (RetroOption *self);
+const gchar *retro_option_get_description (RetroOption *self);
+const gchar **retro_option_get_values (RetroOption *self);
+const gchar *retro_option_get_current (RetroOption *self);
+void retro_option_set_current (RetroOption  *self,
+                               const gchar  *current,
+                               GError      **error);
+
+G_END_DECLS
+
+#endif /* RETRO_OPTION_H */
diff --git a/retro-gtk/retro-options.c b/retro-gtk/retro-options.c
new file mode 100644
index 0000000..059b53d
--- /dev/null
+++ b/retro-gtk/retro-options.c
@@ -0,0 +1,187 @@
+// This file is part of retro-gtk. License: GPL-3.0+.
+
+#include "retro-options.h"
+
+#include "retro-option.h"
+
+struct _RetroOptions
+{
+  GObject parent_instance;
+  GHashTable *options;
+  gboolean updated;
+};
+
+G_DEFINE_TYPE (RetroOptions, retro_options, G_TYPE_OBJECT)
+
+enum {
+  SIG_VALUE_CHANGED,
+  N_SIGNALS,
+};
+
+static guint signals[N_SIGNALS];
+
+RetroOptions *
+retro_options_new (void)
+{
+  return g_object_new (RETRO_TYPE_OPTIONS, NULL);
+}
+
+static void
+retro_options_finalize (GObject *object)
+{
+  RetroOptions *self = (RetroOptions *)object;
+
+  g_hash_table_unref (self->options);
+
+  G_OBJECT_CLASS (retro_options_parent_class)->finalize (object);
+}
+
+static void
+retro_options_class_init (RetroOptionsClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->finalize = retro_options_finalize;
+
+  signals[SIG_VALUE_CHANGED] =
+    g_signal_new ("value-changed", RETRO_TYPE_OPTIONS, G_SIGNAL_RUN_LAST,
+                  0, NULL, NULL,
+                  g_cclosure_marshal_VOID__STRING,
+                  G_TYPE_NONE,
+                  1,
+                  G_TYPE_STRING);
+}
+
+static void
+retro_options_init (RetroOptions *self)
+{
+  self->options = g_hash_table_new_full (g_str_hash, g_str_equal,
+                                         g_free, g_object_unref);
+}
+
+/* Public */
+
+gboolean
+retro_options_contains (RetroOptions *self,
+                        const gchar  *key)
+{
+  g_return_val_if_fail (RETRO_IS_OPTIONS (self), FALSE);
+  g_return_val_if_fail (key != NULL, FALSE);
+
+  return g_hash_table_contains (self->options, key);
+}
+
+const gchar *
+retro_options_get_option_value (RetroOptions *self,
+                                const gchar  *key)
+{
+  RetroOption *option;
+
+  g_return_val_if_fail (RETRO_IS_OPTIONS (self), FALSE);
+  g_return_val_if_fail (key != NULL, FALSE);
+
+  option = RETRO_OPTION (g_hash_table_lookup (self->options, key));
+
+  return retro_option_get_current (option);
+}
+
+void
+retro_options_set_option_value (RetroOptions *self,
+                                const gchar  *key,
+                                const gchar  *value)
+{
+  RetroOption *option;
+  GError *tmp_error = NULL;
+
+  g_return_if_fail (RETRO_IS_OPTIONS (self));
+  g_return_if_fail (key != NULL);
+  g_return_if_fail (value != NULL);
+
+  option = RETRO_OPTION (g_hash_table_lookup (self->options, key));
+
+  retro_option_set_current (option, value, &tmp_error);
+  if (G_UNLIKELY (tmp_error != NULL)) {
+    g_clear_error (&tmp_error);
+
+    return;
+  }
+
+  g_signal_emit (self, signals[SIG_VALUE_CHANGED], 0, key);
+  self->updated = TRUE;
+}
+
+const gchar *
+retro_options_get_option_description (RetroOptions *self,
+                                      const gchar  *key)
+{
+  RetroOption *option;
+
+  g_return_val_if_fail (RETRO_IS_OPTIONS (self), FALSE);
+  g_return_val_if_fail (key != NULL, FALSE);
+
+  option = RETRO_OPTION (g_hash_table_lookup (self->options, key));
+
+  return retro_option_get_description (option);
+}
+
+const gchar **
+retro_options_get_option_values (RetroOptions *self,
+                                 const gchar  *key)
+{
+  RetroOption *option;
+
+  g_return_val_if_fail (RETRO_IS_OPTIONS (self), FALSE);
+  g_return_val_if_fail (key != NULL, FALSE);
+
+  option = RETRO_OPTION (g_hash_table_lookup (self->options, key));
+
+  return retro_option_get_values (option);
+}
+
+GList *
+retro_options_get_keys (RetroOptions *self)
+{
+  g_return_val_if_fail (RETRO_IS_OPTIONS (self), NULL);
+
+  return g_hash_table_get_keys (self->options);
+}
+
+void
+retro_options_insert_variable (RetroOptions        *self,
+                               const RetroVariable *variable)
+{
+  RetroOption *option;
+  const gchar *key;
+  GError *tmp_error = NULL;
+
+  g_return_if_fail (RETRO_IS_OPTIONS (self));
+  g_return_if_fail (variable != NULL);
+
+  option = retro_option_new (variable, &tmp_error);
+  if (G_UNLIKELY (tmp_error != NULL)) {
+    g_debug ("%s", tmp_error->message);
+    g_clear_error (&tmp_error);
+
+    return;
+  }
+
+  key = retro_option_get_key (option);
+
+  g_hash_table_insert (self->options, g_strdup (key), option);
+  g_signal_emit (self, signals[SIG_VALUE_CHANGED], 0, key);
+
+  self->updated = TRUE;
+}
+
+gboolean
+retro_options_get_variable_update (RetroOptions *self)
+{
+  g_return_val_if_fail (RETRO_IS_OPTIONS (self), FALSE);
+
+  if (!self->updated)
+    return FALSE;
+
+  self->updated = FALSE;
+
+  return TRUE;
+}
diff --git a/retro-gtk/retro-options.h b/retro-gtk/retro-options.h
new file mode 100644
index 0000000..e4c1d2e
--- /dev/null
+++ b/retro-gtk/retro-options.h
@@ -0,0 +1,35 @@
+// This file is part of retro-gtk. License: GPL-3.0+.
+
+#ifndef RETRO_OPTIONS_H
+#define RETRO_OPTIONS_H
+
+#include <glib-object.h>
+#include "retro-variable.h"
+
+G_BEGIN_DECLS
+
+#define RETRO_TYPE_OPTIONS (retro_options_get_type())
+
+G_DECLARE_FINAL_TYPE (RetroOptions, retro_options, RETRO, OPTIONS, GObject)
+
+RetroOptions *retro_options_new (void);
+
+gboolean retro_options_contains (RetroOptions *self,
+                                 const gchar  *key);
+const gchar *retro_options_get_option_value (RetroOptions *self,
+                                             const gchar  *key);
+void retro_options_set_option_value (RetroOptions *self,
+                                     const gchar  *key,
+                                     const gchar  *value);
+const gchar *retro_options_get_option_description (RetroOptions *self,
+                                                   const gchar  *key);
+const gchar **retro_options_get_option_values (RetroOptions *self,
+                                               const gchar  *key);
+GList *retro_options_get_keys (RetroOptions *self);
+void retro_options_insert_variable (RetroOptions        *self,
+                                    const RetroVariable *variable);
+gboolean retro_options_get_variable_update (RetroOptions *self);
+
+G_END_DECLS
+
+#endif /* RETRO_OPTIONS_H */
diff --git a/retro-gtk/retro-variable.h b/retro-gtk/retro-variable.h
new file mode 100644
index 0000000..bd569de
--- /dev/null
+++ b/retro-gtk/retro-variable.h
@@ -0,0 +1,20 @@
+// This file is part of retro-gtk. License: GPL-3.0+.
+
+#ifndef RETRO_VARIABLE_H
+#define RETRO_VARIABLE_H
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef struct _RetroVariable RetroVariable;
+
+struct _RetroVariable
+{
+  const gchar *key;
+  const gchar *value;
+};
+
+G_END_DECLS
+
+#endif /* RETRO_VARIABLE_H */


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