From 200e815a8a93be423584dd4ef5d64e78453194e7 Mon Sep 17 00:00:00 2001
From: Ludovico de Nittis <ludovico.denittis@collabora.com>
Date: Tue, 31 Mar 2020 12:24:53 +0200
Subject: [PATCH] Create a new SrtSteam object

Having an SrtSteam object will be easier in the future, if needed, to
expand.

Signed-off-by: Ludovico de Nittis <ludovico.denittis@collabora.com>
---
 steam-runtime-tools/steam-internal.h |  32 +++-
 steam-runtime-tools/steam.c          | 267 ++++++++++++++++++++++++---
 steam-runtime-tools/steam.h          |  19 ++
 steam-runtime-tools/system-info.c    |  34 +---
 4 files changed, 294 insertions(+), 58 deletions(-)

diff --git a/steam-runtime-tools/steam-internal.h b/steam-runtime-tools/steam-internal.h
index a0d07465d..1845f2268 100644
--- a/steam-runtime-tools/steam-internal.h
+++ b/steam-runtime-tools/steam-internal.h
@@ -1,6 +1,6 @@
 /*<private_header>*/
 /*
- * Copyright © 2019 Collabora Ltd.
+ * Copyright © 2019-2020 Collabora Ltd.
  *
  * SPDX-License-Identifier: MIT
  *
@@ -31,8 +31,32 @@
 #include <glib.h>
 #include <glib-object.h>
 
+/*
+ * _srt_library_new:
+ *
+ * Returns: (transfer full): A new #SrtSteam
+ */
+static inline SrtSteam *_srt_steam_new (SrtSteamIssues issues,
+                                        const char *install_path,
+                                        const char *data_path,
+                                        const char *bin32_path);
+
+#ifndef __GTK_DOC_IGNORE__
+static inline SrtSteam *
+_srt_steam_new (SrtSteamIssues issues,
+                const char *install_path,
+                const char *data_path,
+                const char *bin32_path)
+{
+  return g_object_new (SRT_TYPE_STEAM,
+                       "issues", issues,
+                       "install-path", install_path,
+                       "data-path", data_path,
+                       "bin32-path", bin32_path,
+                       NULL);
+}
+#endif
+
 G_GNUC_INTERNAL
 SrtSteamIssues _srt_steam_check (const GStrv env,
-                                 gchar **install_path_out,
-                                 gchar **data_path_out,
-                                 gchar **bin32_out);
+                                 SrtSteam **more_details_out);
diff --git a/steam-runtime-tools/steam.c b/steam-runtime-tools/steam.c
index 5ed75376b..de86addf8 100644
--- a/steam-runtime-tools/steam.c
+++ b/steam-runtime-tools/steam.c
@@ -1,5 +1,5 @@
 /*
- * Copyright © 2019 Collabora Ltd.
+ * Copyright © 2019-2020 Collabora Ltd.
  *
  * SPDX-License-Identifier: MIT
  *
@@ -33,6 +33,7 @@
 
 #include <glib.h>
 
+#include "steam-runtime-tools/enums.h"
 #include "steam-runtime-tools/glib-compat.h"
 #include "steam-runtime-tools/utils.h"
 
@@ -46,23 +47,237 @@
  * installation.
  */
 
-/*
+struct _SrtSteam
+{
+  /*< private >*/
+  GObject parent;
+  SrtSteamIssues issues;
+  gchar *install_path;
+  gchar *data_path;
+  gchar *bin32_path;
+};
+
+struct _SrtSteamClass
+{
+  /*< private >*/
+  GObjectClass parent_class;
+};
+
+enum {
+  PROP_0,
+  PROP_ISSUES,
+  PROP_INSTALL_PATH,
+  PROP_DATA_PATH,
+  PROP_BIN32_PATH,
+  N_PROPERTIES
+};
+
+G_DEFINE_TYPE (SrtSteam, srt_steam, G_TYPE_OBJECT)
+
+static void
+srt_steam_init (SrtSteam *self)
+{
+}
+
+static void
+srt_steam_get_property (GObject *object,
+                        guint prop_id,
+                        GValue *value,
+                        GParamSpec *pspec)
+{
+  SrtSteam *self = SRT_STEAM (object);
+
+  switch (prop_id)
+    {
+      case PROP_ISSUES:
+        g_value_set_flags (value, self->issues);
+        break;
+
+      case PROP_INSTALL_PATH:
+        g_value_set_string (value, self->install_path);
+        break;
+
+      case PROP_DATA_PATH:
+        g_value_set_string (value, self->data_path);
+        break;
+
+      case PROP_BIN32_PATH:
+        g_value_set_string (value, self->bin32_path);
+        break;
+
+      default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+srt_steam_set_property (GObject *object,
+                        guint prop_id,
+                        const GValue *value,
+                        GParamSpec *pspec)
+{
+  SrtSteam *self = SRT_STEAM (object);
+
+  switch (prop_id)
+    {
+      case PROP_ISSUES:
+        /* Construct-only */
+        g_return_if_fail (self->issues == 0);
+        self->issues = g_value_get_flags (value);
+        break;
+
+      case PROP_INSTALL_PATH:
+        /* Construct only */
+        g_return_if_fail (self->install_path == NULL);
+        self->install_path = g_value_dup_string (value);
+        break;
+
+      case PROP_DATA_PATH:
+        /* Construct only */
+        g_return_if_fail (self->data_path == NULL);
+        self->data_path = g_value_dup_string (value);
+        break;
+
+      case PROP_BIN32_PATH:
+        /* Construct only */
+        g_return_if_fail (self->bin32_path == NULL);
+        self->bin32_path = g_value_dup_string (value);
+        break;
+
+      default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+srt_steam_finalize (GObject *object)
+{
+  SrtSteam *self = SRT_STEAM (object);
+
+  g_free (self->install_path);
+  g_free (self->data_path);
+  g_free (self->bin32_path);
+
+  G_OBJECT_CLASS (srt_steam_parent_class)->finalize (object);
+}
+
+static GParamSpec *properties[N_PROPERTIES] = { NULL };
+
+static void
+srt_steam_class_init (SrtSteamClass *cls)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (cls);
+
+  object_class->get_property = srt_steam_get_property;
+  object_class->set_property = srt_steam_set_property;
+  object_class->finalize = srt_steam_finalize;
+
+  properties[PROP_ISSUES] =
+    g_param_spec_flags ("issues", "Issues", "Problems with the steam installation",
+                        SRT_TYPE_STEAM_ISSUES, SRT_STEAM_ISSUES_NONE,
+                        G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+                        G_PARAM_STATIC_STRINGS);
+
+  properties[PROP_INSTALL_PATH] =
+    g_param_spec_string ("install-path", "Install path",
+                         "Absolute path to the Steam installation",
+                         NULL,
+                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+                         G_PARAM_STATIC_STRINGS);
+
+  properties[PROP_DATA_PATH] =
+    g_param_spec_string ("data-path", "Data path",
+                         "Absolute path to the Steam data directory, which is usually "
+                         "the same as install-path, but may be different while "
+                         "testing a new Steam release",
+                         NULL,
+                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+                         G_PARAM_STATIC_STRINGS);
+
+  properties[PROP_BIN32_PATH] =
+    g_param_spec_string ("bin32-path", "Bin32 path",
+                         "Absolute path to `ubuntu12_32`",
+                         NULL,
+                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+                         G_PARAM_STATIC_STRINGS);
+
+  g_object_class_install_properties (object_class, N_PROPERTIES, properties);
+}
+
+/**
+ * srt_steam_get_issues:
+ * @self: The #SrtSteam object
+ *
+ * Return the problems found in @self.
+ *
+ * Returns: A bitfield containing problems, or %SRT_STEAM_ISSUES_NONE
+ *  if no problems were found
+ */
+SrtSteamIssues
+srt_steam_get_issues (SrtSteam *self)
+{
+  g_return_val_if_fail (SRT_IS_STEAM (self), SRT_STEAM_ISSUES_INTERNAL_ERROR);
+  return self->issues;
+}
+/**
+ * srt_steam_get_install_path:
+ * @self: The #SrtSteam object
+ *
+ * Returns: (nullable) (type filename): The absolute path to the Steam
+ *  installation, which is valid as long as @self is not destroyed.
+ */
+const char *
+srt_steam_get_install_path (SrtSteam *self)
+{
+  g_return_val_if_fail (SRT_IS_STEAM (self), NULL);
+  return self->install_path;
+}
+
+/**
+ * srt_steam_get_data_path:
+ * @self: The #SrtSteam object
+ *
+ * Used to return the absolute path to the Steam data directory, which
+ * is usually the same as `srt_steam_get_install_path`, but may be different
+ * while testing a new Steam release.
+ *
+ * Returns: (nullable) (type filename): The absolute path to the Steam data
+ *  directory, which is valid as long as @self is not destroyed.
+ */
+const char *
+srt_steam_get_data_path (SrtSteam *self)
+{
+  g_return_val_if_fail (SRT_IS_STEAM (self), NULL);
+  return self->data_path;
+}
+
+/**
+ * srt_steam_get_bin32_path:
+ * @self: The #SrtSteam object
+ *
+ * Returns: (nullable) (type filename): The absolute path to `ubuntu12_32`,
+ *  which is valid as long as @self is not destroyed.
+ */
+const char *
+srt_steam_get_bin32_path (SrtSteam *self)
+{
+  g_return_val_if_fail (SRT_IS_STEAM (self), NULL);
+  return self->bin32_path;
+}
+
+/**
  * _srt_steam_check:
- * @environ: (nullable): The list of environment variables to use.
- * @install_path_out: (out) (optional) (nullable) (type filename):
- *  Used to return the absolute path to the Steam installation
- * @data_path_out: (out) (optional) (nullable) (type filename):
- *  Used to return the absolute path to the Steam data directory,
- *  which is usually the same as @install_path_out, but may be different
- *  while testing a new Steam release
- * @bin32_out: (out) (optional) (nullable) (type filename):
- *  Used to return the absolute path to `ubuntu12_32`
+ * @my_environ: (nullable): The list of environment variables to use.
+ * @more_details_out: (out) (optional) (transfer full): Used to return an
+ *  #SrtSteam object representing information about the current Steam
+ *  installation. Free with `g_object_unref()`.
+ *
+ * Returns: A bitfield containing problems, or %SRT_STEAM_ISSUES_NONE
+ *  if no problems were found
  */
 SrtSteamIssues
-_srt_steam_check (const GStrv environ,
-                  gchar **install_path_out,
-                  gchar **data_path_out,
-                  gchar **bin32_out)
+_srt_steam_check (const GStrv my_environ,
+                  SrtSteam **more_details_out)
 {
   SrtSteamIssues issues = SRT_STEAM_ISSUES_NONE;
   gchar *dot_steam_bin32 = NULL;
@@ -78,14 +293,10 @@ _srt_steam_check (const GStrv environ,
 
   g_return_val_if_fail (_srt_check_not_setuid (),
                         SRT_STEAM_ISSUES_INTERNAL_ERROR);
-  g_return_val_if_fail (install_path_out == NULL || *install_path_out == NULL,
-                        SRT_STEAM_ISSUES_INTERNAL_ERROR);
-  g_return_val_if_fail (data_path_out == NULL || *data_path_out == NULL,
-                        SRT_STEAM_ISSUES_INTERNAL_ERROR);
-  g_return_val_if_fail (bin32_out == NULL || *bin32_out == NULL,
+  g_return_val_if_fail (more_details_out == NULL || *more_details_out == NULL,
                         SRT_STEAM_ISSUES_INTERNAL_ERROR);
 
-  env = (environ == NULL) ? g_get_environ () : g_strdupv (environ);
+  env = (my_environ == NULL) ? g_get_environ () : g_strdupv (my_environ);
 
   home = g_environ_getenv (env, "HOME");
   user_data = g_environ_getenv (env, "XDG_DATA_HOME");
@@ -256,17 +467,13 @@ _srt_steam_check (const GStrv environ,
       g_debug ("Found Steam data at %s", data_path);
     }
 
-  /* We can't just transfer ownership here, because in the older GLib
-   * that we're targeting, g_free() and free() are not guaranteed to be
-   * associated with the same memory pool. */
-  if (install_path_out != NULL)
-    *install_path_out = g_strdup (install_path);
 
-  if (data_path_out != NULL)
-    *data_path_out = g_strdup (data_path);
 
-  if (bin32_out != NULL)
-    *bin32_out = g_strdup (bin32);
+  if (more_details_out != NULL)
+    *more_details_out = _srt_steam_new (issues,
+                                        install_path,
+                                        data_path,
+                                        bin32);
 
   free (install_path);
   free (data_path);
diff --git a/steam-runtime-tools/steam.h b/steam-runtime-tools/steam.h
index b19b1197e..a0597ce01 100644
--- a/steam-runtime-tools/steam.h
+++ b/steam-runtime-tools/steam.h
@@ -29,6 +29,20 @@
 #error "Do not include directly, use <steam-runtime-tools/steam-runtime-tools.h>"
 #endif
 
+#include <glib.h>
+#include <glib-object.h>
+
+typedef struct _SrtSteam SrtSteam;
+typedef struct _SrtSteamClass SrtSteamClass;
+
+#define SRT_TYPE_STEAM srt_steam_get_type ()
+#define SRT_STEAM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SRT_TYPE_STEAM, SrtSteam))
+#define SRT_STEAM_CLASS(cls) (G_TYPE_CHECK_CLASS_CAST ((cls), SRT_TYPE_STEAM, SrtSteamClass))
+#define SRT_IS_STEAM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SRT_TYPE_STEAM))
+#define SRT_IS_STEAM_CLASS(cls) (G_TYPE_CHECK_CLASS_TYPE ((cls), SRT_TYPE_STEAM))
+#define SRT_STEAM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), SRT_TYPE_STEAM, SrtSteamClass)
+GType srt_steam_get_type (void);
+
 /**
  * SrtSteamIssues:
  * @SRT_STEAM_ISSUES_NONE: There are no problems
@@ -74,3 +88,8 @@ typedef enum
   SRT_STEAM_ISSUES_DOT_STEAM_ROOT_NOT_DIRECTORY = (1 << 6),
   SRT_STEAM_ISSUES_NONE = 0
 } SrtSteamIssues;
+
+SrtSteamIssues srt_steam_get_issues (SrtSteam *self);
+const char *srt_steam_get_install_path (SrtSteam *self);
+const char *srt_steam_get_data_path (SrtSteam *self);
+const char *srt_steam_get_bin32_path (SrtSteam *self);
diff --git a/steam-runtime-tools/system-info.c b/steam-runtime-tools/system-info.c
index 625838230..180f44831 100644
--- a/steam-runtime-tools/system-info.c
+++ b/steam-runtime-tools/system-info.c
@@ -104,6 +104,7 @@ struct _SrtSystemInfo
    * shouldn't matter, or %NULL to use the compiled-in default */
   GQuark primary_multiarch_tuple;
   GHashTable *cached_hidden_deps;
+  SrtSteam *steam_data;
   struct
   {
     /* GQuark => MaybeLocale */
@@ -112,15 +113,6 @@ struct _SrtSystemInfo
     gboolean have_issues;
   } locales;
   struct
-  {
-    /* install_path != NULL or issues != NONE indicates we have already
-     * checked the Steam installation */
-    gchar *install_path;
-    gchar *data_path;
-    gchar *bin32;
-    SrtSteamIssues issues;
-  } steam;
-  struct
   {
     /* path != NULL or issues != NONE indicates we have already checked
      * the Steam Runtime */
@@ -401,10 +393,9 @@ static void
 forget_steam (SrtSystemInfo *self)
 {
   forget_runtime (self);
-  self->steam.issues = SRT_STEAM_ISSUES_NONE;
-  g_clear_pointer (&self->steam.install_path, g_free);
-  g_clear_pointer (&self->steam.data_path, g_free);
-  g_clear_pointer (&self->steam.bin32, g_free);
+  if (self->steam_data != NULL)
+    g_object_unref (self->steam_data);
+  self->steam_data = NULL;
 }
 
 /*
@@ -1626,13 +1617,8 @@ srt_system_info_set_sysroot (SrtSystemInfo *self,
 static void
 ensure_steam_cached (SrtSystemInfo *self)
 {
-  if (self->steam.issues == SRT_STEAM_ISSUES_NONE &&
-      self->steam.install_path == NULL &&
-      self->steam.data_path == NULL)
-    self->steam.issues = _srt_steam_check (self->env,
-                                           &self->steam.install_path,
-                                           &self->steam.data_path,
-                                           &self->steam.bin32);
+  if (self->steam_data == NULL)
+    _srt_steam_check (self->env, &self->steam_data);
 }
 
 /**
@@ -1651,7 +1637,7 @@ srt_system_info_get_steam_issues (SrtSystemInfo *self)
                         SRT_STEAM_ISSUES_INTERNAL_ERROR);
 
   ensure_steam_cached (self);
-  return self->steam.issues;
+  return srt_steam_get_issues (self->steam_data);
 }
 
 /**
@@ -1693,7 +1679,7 @@ srt_system_info_dup_steam_installation_path (SrtSystemInfo *self)
   g_return_val_if_fail (SRT_IS_SYSTEM_INFO (self), NULL);
 
   ensure_steam_cached (self);
-  return g_strdup (self->steam.install_path);
+  return g_strdup (srt_steam_get_install_path (self->steam_data));
 }
 
 /**
@@ -1735,7 +1721,7 @@ srt_system_info_dup_steam_data_path (SrtSystemInfo *self)
   g_return_val_if_fail (SRT_IS_SYSTEM_INFO (self), NULL);
 
   ensure_steam_cached (self);
-  return g_strdup (self->steam.data_path);
+  return g_strdup (srt_steam_get_data_path (self->steam_data));
 }
 
 static void
@@ -2083,7 +2069,7 @@ ensure_runtime_cached (SrtSystemInfo *self)
         }
       else
         {
-          self->runtime.issues = _srt_runtime_check (self->steam.bin32,
+          self->runtime.issues = _srt_runtime_check (srt_steam_get_bin32_path (self->steam_data),
                                                      self->runtime.expected_version,
                                                      self->env,
                                                      &self->runtime.version,
-- 
GitLab