diff --git a/bin/system-info.c b/bin/system-info.c
index 8ba71a5bf87d0a0980c2201d67b0c2304b577102..2f58661c87e00cab51cee1637460e7b2d249ac3f 100644
--- a/bin/system-info.c
+++ b/bin/system-info.c
@@ -759,6 +759,7 @@ main (int argc,
   int opt;
   static const char * const multiarch_tuples[] = { SRT_ABI_I386, SRT_ABI_X86_64, NULL };
   GList *icds;
+  GList *desktop_entries;
   const GList *icd_iter;
   SrtDriverFlags extra_driver_flags = SRT_DRIVER_FLAGS_INCLUDE_ALL;
 
@@ -1175,6 +1176,43 @@ main (int argc,
   json_builder_end_array (builder);   // vulkan.icds
   json_builder_end_object (builder);  // vulkan
 
+  json_builder_set_member_name (builder, "desktop-entries");
+  json_builder_begin_array (builder);
+    {
+      desktop_entries = srt_system_info_list_desktop_entries (info);
+      for (GList *iter = desktop_entries; iter != NULL; iter = iter->next)
+        {
+          json_builder_begin_object (builder);
+          if (srt_desktop_entry_get_id (iter->data) != NULL)
+            {
+              json_builder_set_member_name (builder, "id");
+              json_builder_add_string_value (builder, srt_desktop_entry_get_id (iter->data));
+            }
+
+          if (srt_desktop_entry_get_commandline (iter->data) != NULL)
+            {
+              json_builder_set_member_name (builder, "commandline");
+              json_builder_add_string_value (builder, srt_desktop_entry_get_commandline (iter->data));
+            }
+
+          if (srt_desktop_entry_get_filename (iter->data) != NULL)
+            {
+              json_builder_set_member_name (builder, "filename");
+              json_builder_add_string_value (builder, srt_desktop_entry_get_filename (iter->data));
+            }
+
+          json_builder_set_member_name (builder, "default_steam_uri_handler");
+          json_builder_add_boolean_value (builder, srt_desktop_entry_is_default_handler (iter->data));
+
+          json_builder_set_member_name (builder, "steam_uri_handler");
+          json_builder_add_boolean_value (builder, srt_desktop_entry_is_steam_handler (iter->data));
+
+          json_builder_end_object (builder);
+        }
+      g_list_free_full (desktop_entries, g_object_unref);
+    }
+  json_builder_end_array (builder);
+
   json_builder_end_object (builder); // End global object
 
   JsonNode *root = json_builder_get_root (builder);
diff --git a/bin/system-info.md b/bin/system-info.md
index ef244578cbf00a76c6cc07b85fdc807a91d49dac..498e5fec96089473ebb310b79aabd4d70ef50f48 100644
--- a/bin/system-info.md
+++ b/bin/system-info.md
@@ -630,6 +630,28 @@ keys:
     :   Vulkan API version implemented by this ICD as a dotted-decimal
         string, for example **1.1.90**
 
+**desktop-entries**
+:   An array of objects describing the Steam related desktop entries
+    that have been found.
+    Every object can have the following keys:
+
+    **id**
+    :   A string with the ID of the application entry, such as `steam.desktop`.
+
+    **commandline**
+    :   A string with which the application will be started, such as
+        `/usr/bin/steam %U`.
+
+    **filename**
+    :   Absolute path to the desktop entry file.
+
+    **default_steam_uri_handler**
+    :   A boolean value indicating whether this entry is the default used
+        to open `steam:` URIs.
+
+    **steam_uri_handler**
+    :   A boolean value indicating whether this entry can open `steam:` URIs.
+
 # EXIT STATUS
 
 0
diff --git a/meson.build b/meson.build
index 385916853ac0830c3cdbcec3330b18c3032c419a..3e90ff89bc2b640d6dbb1e27f31199589746a707 100644
--- a/meson.build
+++ b/meson.build
@@ -181,6 +181,10 @@ gio = dependency(
   'gio-2.0',
   version : '>= 2.32',
 )
+gio_unix = dependency(
+  'gio-unix-2.0',
+  version : '>= 2.32',
+)
 json_glib = dependency(
   'json-glib-1.0',
   version : '>= 1.0',
diff --git a/steam-runtime-tools/desktop-entry-internal.h b/steam-runtime-tools/desktop-entry-internal.h
new file mode 100644
index 0000000000000000000000000000000000000000..ffa49466c926c21c3c44515f7a3a5280fb8b3d4a
--- /dev/null
+++ b/steam-runtime-tools/desktop-entry-internal.h
@@ -0,0 +1,70 @@
+/*< internal_header >*/
+/*
+ * Copyright © 2020 Collabora Ltd.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#pragma once
+
+#include "steam-runtime-tools/steam-runtime-tools.h"
+#include "steam-runtime-tools/utils-internal.h"
+
+/*
+ * _srt_desktop_entry_new:
+ * @id: (nullable)
+ * @commandline: (nullable)
+ * @filename: (nullable)
+ *
+ * Inline convenience function to create a new SrtDesktopEntry.
+ * This is not part of the public API.
+ *
+ * Returns: (transfer full): A new #SrtDesktopEntry
+ */
+static inline SrtDesktopEntry *_srt_desktop_entry_new (const gchar *id,
+                                                       const gchar *commandline,
+                                                       const gchar *filename,
+                                                       gboolean is_default_handler,
+                                                       gboolean is_steam_handler);
+
+#ifndef __GTK_DOC_IGNORE__
+
+static inline SrtDesktopEntry *
+_srt_desktop_entry_new (const gchar *id,
+                        const gchar *commandline,
+                        const gchar *filename,
+                        gboolean is_default_handler,
+                        gboolean is_steam_handler)
+{
+  return g_object_new (SRT_TYPE_DESKTOP_ENTRY,
+                       "id", id,
+                       "commandline", commandline,
+                       "filename", filename,
+                       "is-default-handler", is_default_handler,
+                       "is-steam-handler", is_steam_handler,
+                       NULL);
+}
+
+#endif
+
+G_GNUC_INTERNAL
+GList *_srt_list_steam_desktop_entries (void);
diff --git a/steam-runtime-tools/desktop-entry.c b/steam-runtime-tools/desktop-entry.c
new file mode 100644
index 0000000000000000000000000000000000000000..433494e7697cdd8c6898c53192332df360a3c6e4
--- /dev/null
+++ b/steam-runtime-tools/desktop-entry.c
@@ -0,0 +1,392 @@
+/*
+ * Copyright © 2020 Collabora Ltd.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "steam-runtime-tools/desktop-entry.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <glib.h>
+#include <gio/gio.h>
+#include <gio/gdesktopappinfo.h>
+
+#include "steam-runtime-tools/desktop-entry-internal.h"
+#include "steam-runtime-tools/enums.h"
+#include "steam-runtime-tools/glib-compat.h"
+#include "steam-runtime-tools/utils.h"
+
+/**
+ * SECTION:desktop-entry
+ * @title: Desktop entry
+ * @short_description: Information about the Steam desktop entries
+ * @include: steam-runtime-tools/steam-runtime-tools.h
+ */
+
+struct _SrtDesktopEntry
+{
+  /*< private >*/
+  GObject parent;
+  gchar *id;
+  gchar *commandline;
+  gchar *filename;
+  gboolean is_default_handler;
+  gboolean is_steam_handler;
+};
+
+struct _SrtDesktopEntryClass
+{
+  /*< private >*/
+  GObjectClass parent_class;
+};
+
+enum {
+  PROP_0,
+  PROP_ID,
+  PROP_COMMANDLINE,
+  PROP_FILENAME,
+  PROP_IS_DEFAULT_HANDLER,
+  PROP_IS_STEAM_HANDLER,
+  N_PROPERTIES
+};
+
+G_DEFINE_TYPE (SrtDesktopEntry, srt_desktop_entry, G_TYPE_OBJECT)
+
+static void
+srt_desktop_entry_init (SrtDesktopEntry *self)
+{
+}
+
+static void
+srt_desktop_entry_get_property (GObject *object,
+                                guint prop_id,
+                                GValue *value,
+                                GParamSpec *pspec)
+{
+  SrtDesktopEntry *self = SRT_DESKTOP_ENTRY (object);
+
+  switch (prop_id)
+    {
+      case PROP_ID:
+        g_value_set_string (value, self->id);
+        break;
+
+      case PROP_COMMANDLINE:
+        g_value_set_string (value, self->commandline);
+        break;
+
+      case PROP_FILENAME:
+        g_value_set_string (value, self->filename);
+        break;
+
+      case PROP_IS_DEFAULT_HANDLER:
+        g_value_set_boolean (value, self->is_default_handler);
+        break;
+
+      case PROP_IS_STEAM_HANDLER:
+        g_value_set_boolean (value, self->is_steam_handler);
+        break;
+
+      default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+srt_desktop_entry_set_property (GObject *object,
+                                guint prop_id,
+                                const GValue *value,
+                                GParamSpec *pspec)
+{
+  SrtDesktopEntry *self = SRT_DESKTOP_ENTRY (object);
+
+  switch (prop_id)
+    {
+      case PROP_ID:
+        /* Construct-only */
+        g_return_if_fail (self->id == NULL);
+        self->id = g_value_dup_string (value);
+        break;
+
+      case PROP_COMMANDLINE:
+        /* Construct only */
+        g_return_if_fail (self->commandline == NULL);
+        self->commandline = g_value_dup_string (value);
+        break;
+
+      case PROP_FILENAME:
+        /* Construct only */
+        g_return_if_fail (self->filename == NULL);
+        self->filename = g_value_dup_string (value);
+        break;
+
+      case PROP_IS_DEFAULT_HANDLER:
+        /* Construct only */
+        self->is_default_handler = g_value_get_boolean (value);
+        break;
+
+      case PROP_IS_STEAM_HANDLER:
+        /* Construct only */
+        self->is_steam_handler = g_value_get_boolean (value);
+        break;
+
+      default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+srt_desktop_entry_finalize (GObject *object)
+{
+  SrtDesktopEntry *self = SRT_DESKTOP_ENTRY (object);
+
+  g_free (self->id);
+  g_free (self->commandline);
+  g_free (self->filename);
+
+  G_OBJECT_CLASS (srt_desktop_entry_parent_class)->finalize (object);
+}
+
+static GParamSpec *properties[N_PROPERTIES] = { NULL };
+
+static void
+srt_desktop_entry_class_init (SrtDesktopEntryClass *cls)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (cls);
+
+  object_class->get_property = srt_desktop_entry_get_property;
+  object_class->set_property = srt_desktop_entry_set_property;
+  object_class->finalize = srt_desktop_entry_finalize;
+
+  properties[PROP_ID] =
+    g_param_spec_string ("id", "ID", "Desktop entry ID",
+                         NULL,
+                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+                         G_PARAM_STATIC_STRINGS);
+
+  properties[PROP_COMMANDLINE] =
+    g_param_spec_string ("commandline", "Commandline",
+                         "Commandline with which the application will be started",
+                         NULL,
+                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+                         G_PARAM_STATIC_STRINGS);
+
+  properties[PROP_FILENAME] =
+    g_param_spec_string ("filename", "Filename",
+                         "Full path to the desktop entry file",
+                         NULL,
+                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+                         G_PARAM_STATIC_STRINGS);
+
+  properties[PROP_IS_DEFAULT_HANDLER] =
+    g_param_spec_boolean ("is-default-handler", "Is default handler?",
+                          "TRUE if the entry is the default that handles the URI scheme \"steam\"",
+                          FALSE,
+                          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+                          G_PARAM_STATIC_STRINGS);
+
+  properties[PROP_IS_STEAM_HANDLER] =
+    g_param_spec_boolean ("is-steam-handler", "Is Steam handler?",
+                          "TRUE if the entry is of the type \"x-scheme-handler/steam\"",
+                          FALSE,
+                          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+                          G_PARAM_STATIC_STRINGS);
+
+  g_object_class_install_properties (object_class, N_PROPERTIES, properties);
+}
+
+/**
+ * srt_desktop_entry_get_id:
+ * @self: The #SrtDesktopEntry object
+ *
+ * Return the ID of @self.
+ *
+ * Returns: (nullable): A string like `steam.desktop`, which is valid as long
+ *  as @self is not destroyed.
+ */
+const char *
+srt_desktop_entry_get_id (SrtDesktopEntry *self)
+{
+  g_return_val_if_fail (SRT_IS_DESKTOP_ENTRY (self), NULL);
+  return self->id;
+}
+
+/**
+ * srt_desktop_entry_get_commandline:
+ * @self: The #SrtDesktopEntry object
+ *
+ * Return the commandline with which the application @self will be started.
+ *
+ * Returns: (nullable): A string like `/usr/bin/steam %U`, which is valid as
+ *  long as @self is not destroyed.
+ */
+const char *
+srt_desktop_entry_get_commandline (SrtDesktopEntry *self)
+{
+  g_return_val_if_fail (SRT_IS_DESKTOP_ENTRY (self), NULL);
+  return self->commandline;
+}
+
+/**
+ * srt_desktop_entry_get_filename:
+ * @self: The #SrtDesktopEntry object
+ *
+ * Return the full path to the @self file.
+ *
+ * Returns: (type filename) (nullable): A string like
+ *  `/usr/share/applications/steam.desktop`, which is valid as long as @self
+ *  is not destroyed.
+ */
+const char *
+srt_desktop_entry_get_filename (SrtDesktopEntry *self)
+{
+  g_return_val_if_fail (SRT_IS_DESKTOP_ENTRY (self), NULL);
+  return self->filename;
+}
+
+/**
+ * srt_desktop_entry_is_default_handler:
+ * @self: The #SrtDesktopEntry object
+ *
+ * Returns: %TRUE if @self is the default handler for `steam:` URIs
+ */
+gboolean
+srt_desktop_entry_is_default_handler (SrtDesktopEntry *self)
+{
+  g_return_val_if_fail (SRT_IS_DESKTOP_ENTRY (self), FALSE);
+  return self->is_default_handler;
+}
+
+/**
+ * srt_desktop_entry_is_default_handler:
+ * @self: The #SrtDesktopEntry object
+ *
+ * Returns: %TRUE if @self can handle `steam:` URIs
+ */
+gboolean
+srt_desktop_entry_is_steam_handler (SrtDesktopEntry *self)
+{
+  g_return_val_if_fail (SRT_IS_DESKTOP_ENTRY (self), FALSE);
+  return self->is_steam_handler;
+}
+
+/**
+ * _srt_list_steam_desktop_entries:
+ *
+ * Implementation of srt_system_info_list_desktop_entries().
+ *
+ * Returns: (transfer full) (element-type SrtDesktopEntry) (nullable): A list of
+ *  opaque #SrtDesktopEntry objects or %NULL if nothing was found. Free with
+ *  `g_list_free_full (entries, g_object_unref)`.
+ */
+GList *
+_srt_list_steam_desktop_entries (void)
+{
+  GList *ret = NULL;
+  GList *app_list = NULL;
+  GHashTable *found_handlers = NULL;
+  GHashTable *known_ids = NULL;
+  GAppInfo *default_handler = NULL;
+  const char *default_handler_id = NULL;
+  const GList *this_app;
+
+  default_handler = g_app_info_get_default_for_uri_scheme ("steam");
+  if (default_handler != NULL)
+    {
+      default_handler_id = g_app_info_get_id (default_handler);
+      g_debug ("Found the default `steam:` handler: %s", default_handler_id);
+    }
+
+  app_list = g_app_info_get_all_for_type ("x-scheme-handler/steam");
+
+  found_handlers = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+  known_ids = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+  /* The official Steam package or Debian */
+  g_hash_table_add (known_ids, g_strdup ("steam.desktop"));
+  /* Flathub */
+  g_hash_table_add (known_ids, g_strdup ("com.valvesoftware.Steam.desktop"));
+  /* Arch Linux Steam native */
+  g_hash_table_add (known_ids, g_strdup ("steam-native.desktop"));
+
+  for (this_app = app_list; this_app != NULL; this_app = this_app->next)
+    {
+      const char *id = NULL;
+      const char *commandline = NULL;
+      const char *filename = NULL;
+      gboolean is_default_handler = FALSE;
+      gboolean is_steam_handler = TRUE;
+      SrtDesktopEntry *entry = NULL;
+
+      id = g_app_info_get_id (this_app->data);
+      commandline = g_app_info_get_commandline (this_app->data);
+      if (G_IS_DESKTOP_APP_INFO (this_app->data))
+        filename = g_desktop_app_info_get_filename (this_app->data);
+
+      if (id != NULL)
+        {
+          g_hash_table_add (found_handlers, g_strdup (id));
+          is_default_handler = (g_strcmp0 (id, default_handler_id) == 0);
+        }
+
+      entry = _srt_desktop_entry_new (id, commandline, filename, is_default_handler, is_steam_handler);
+      ret = g_list_prepend (ret, entry);
+    }
+
+  g_list_free_full (app_list, g_object_unref);
+
+  /* Get a list of all the desktop apps and filter them if they have a well known ID */
+  app_list = g_app_info_get_all ();
+  for (this_app = app_list; this_app != NULL; this_app = this_app->next)
+    {
+      const char *id = NULL;
+      const char *commandline = NULL;
+      const char *filename = NULL;
+      gboolean is_default_handler = FALSE;
+      gboolean is_steam_handler = FALSE;
+      SrtDesktopEntry *entry = NULL;
+
+      id = g_app_info_get_id (this_app->data);
+      if (id == NULL || !g_hash_table_contains (known_ids, id) || g_hash_table_contains (found_handlers, id))
+        continue;
+
+      commandline = g_app_info_get_commandline (this_app->data);
+      if (G_IS_DESKTOP_APP_INFO (this_app->data))
+        filename = g_desktop_app_info_get_filename (this_app->data);
+
+      is_default_handler = (id == default_handler_id);
+
+      entry = _srt_desktop_entry_new (id, commandline, filename, is_default_handler, is_steam_handler);
+      ret = g_list_prepend (ret, entry);
+    }
+  
+  g_hash_table_unref (found_handlers);
+  g_hash_table_unref (known_ids);
+  g_list_free_full (app_list, g_object_unref);
+  if (default_handler != NULL)
+    g_object_unref (default_handler);
+
+  return g_list_reverse (ret);
+}
diff --git a/steam-runtime-tools/desktop-entry.h b/steam-runtime-tools/desktop-entry.h
new file mode 100644
index 0000000000000000000000000000000000000000..795f7b7d7ee4bc6330862f790d4500a836bf1de1
--- /dev/null
+++ b/steam-runtime-tools/desktop-entry.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright © 2020 Collabora Ltd.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#pragma once
+
+#if !defined(_SRT_IN_SINGLE_HEADER) && !defined(_SRT_COMPILATION)
+#error "Do not include directly, use <steam-runtime-tools/steam-runtime-tools.h>"
+#endif
+
+#include <glib.h>
+#include <glib-object.h>
+
+typedef struct _SrtDesktopEntry SrtDesktopEntry;
+typedef struct _SrtDesktopEntryClass SrtDesktopEntryClass;
+
+#define SRT_TYPE_DESKTOP_ENTRY srt_desktop_entry_get_type ()
+#define SRT_DESKTOP_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SRT_TYPE_DESKTOP_ENTRY, SrtDesktopEntry))
+#define SRT_DESKTOP_ENTRY_CLASS(cls) (G_TYPE_CHECK_CLASS_CAST ((cls), SRT_TYPE_DESKTOP_ENTRY, SrtDesktopEntryClass))
+#define SRT_IS_DESKTOP_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SRT_TYPE_DESKTOP_ENTRY))
+#define SRT_IS_DESKTOP_ENTRY_CLASS(cls) (G_TYPE_CHECK_CLASS_TYPE ((cls), SRT_TYPE_DESKTOP_ENTRY))
+#define SRT_DESKTOP_ENTRY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), SRT_TYPE_DESKTOP_ENTRY, SrtDesktopEntryClass)
+GType srt_desktop_entry_get_type (void);
+
+const char *srt_desktop_entry_get_id (SrtDesktopEntry *self);
+const char *srt_desktop_entry_get_commandline (SrtDesktopEntry *self);
+const char *srt_desktop_entry_get_filename (SrtDesktopEntry *self);
+gboolean srt_desktop_entry_is_default_handler (SrtDesktopEntry *self);
+gboolean srt_desktop_entry_is_steam_handler (SrtDesktopEntry *self);
diff --git a/steam-runtime-tools/meson.build b/steam-runtime-tools/meson.build
index 7f372c4f8225e21e3092953cb029a49fa455044a..4a3b4f3383175ed10350fd5b8e385c74277036cc 100644
--- a/steam-runtime-tools/meson.build
+++ b/steam-runtime-tools/meson.build
@@ -24,6 +24,8 @@
 libsteamrt_sources = [
     'architecture-internal.h',
     'architecture.c',
+    'desktop-entry-internal.h',
+    'desktop-entry.c',
     'graphics-internal.h',
     'graphics.c',
     'library-internal.h',
@@ -43,6 +45,7 @@ libsteamrt_sources = [
 
 libsteamrt_public_headers = [
     'architecture.h',
+    'desktop-entry.h',
     'graphics.h',
     'library.h',
     'locale.h',
@@ -76,7 +79,7 @@ libsteamrt = library(
     '-D_SRT_API_MAJOR="' + api_major + '"',
   ],
   include_directories : project_include_dirs,
-  dependencies : [libdl, threads, libelf, glib, gobject, json_glib],
+  dependencies : [libdl, threads, libelf, gio_unix, glib, gobject, json_glib],
   soversion : abi_major,
   version : abi_major + '.' + abi_minor,
   install : true,
diff --git a/steam-runtime-tools/steam-runtime-tools.h b/steam-runtime-tools/steam-runtime-tools.h
index 694c40a5f70a960995052aecb9381c6b0a6ad315..a2afe659f3f52ca47ccb88a785282bddad28c043 100644
--- a/steam-runtime-tools/steam-runtime-tools.h
+++ b/steam-runtime-tools/steam-runtime-tools.h
@@ -28,6 +28,7 @@
 #define _SRT_IN_SINGLE_HEADER
 
 #include <steam-runtime-tools/architecture.h>
+#include <steam-runtime-tools/desktop-entry.h>
 #include <steam-runtime-tools/enums.h>
 #include <steam-runtime-tools/graphics.h>
 #include <steam-runtime-tools/library.h>
diff --git a/steam-runtime-tools/steam.c b/steam-runtime-tools/steam.c
index de86addf8eec806d0619eb73bf0f4650c252c2f3..861e973c6f2d46757a798730897f3e7653dd789c 100644
--- a/steam-runtime-tools/steam.c
+++ b/steam-runtime-tools/steam.c
@@ -32,6 +32,7 @@
 #include <string.h>
 
 #include <glib.h>
+#include <gio/gio.h>
 
 #include "steam-runtime-tools/enums.h"
 #include "steam-runtime-tools/glib-compat.h"
@@ -272,6 +273,9 @@ srt_steam_get_bin32_path (SrtSteam *self)
  *  #SrtSteam object representing information about the current Steam
  *  installation. Free with `g_object_unref()`.
  *
+ * Please note that @my_environ can't be used when checking the default
+ * desktop entry that handles `steam:` URIs.
+ *
  * Returns: A bitfield containing problems, or %SRT_STEAM_ISSUES_NONE
  *  if no problems were found
  */
@@ -284,12 +288,18 @@ _srt_steam_check (const GStrv my_environ,
   gchar *dot_steam_steam = NULL;
   gchar *dot_steam_root = NULL;
   gchar *default_steam_path = NULL;
+  GAppInfo *default_app = NULL;
   char *install_path = NULL;
   char *data_path = NULL;
   char *bin32 = NULL;
   const char *home = NULL;
   const char *user_data = NULL;
+  const char *steam_script = NULL;
+  const char *commandline = NULL;
+  const char *executable = NULL;
+  const char *app_id = NULL;
   GStrv env = NULL;
+  GError *error = NULL;
 
   g_return_val_if_fail (_srt_check_not_setuid (),
                         SRT_STEAM_ISSUES_INTERNAL_ERROR);
@@ -467,7 +477,82 @@ _srt_steam_check (const GStrv my_environ,
       g_debug ("Found Steam data at %s", data_path);
     }
 
+  default_app = g_app_info_get_default_for_uri_scheme ("steam");
+
+  if (default_app == NULL)
+    {
+      g_debug ("There isn't a default app that can handle `steam:` URLs");
+      issues |= SRT_STEAM_ISSUES_MISSING_STEAM_URI_HANDLER;
+    }
+  else
+    {
+      executable = g_app_info_get_executable (default_app);
+      commandline = g_app_info_get_commandline (default_app);
+      app_id = g_app_info_get_id (default_app);
+      gboolean found_expected_steam_uri_handler = FALSE;
+
+      if (commandline != NULL)
+        {
+          gchar **argvp;
+          if (g_shell_parse_argv (commandline, NULL, &argvp, &error))
+            {
+              const char *const expectations[] = { executable, "%U", NULL };
+              gsize i;
+              for (i = 0; argvp[i] != NULL && expectations[i] != NULL; i++)
+                {
+                  if (g_strcmp0 (argvp[i], expectations[i]) != 0)
+                    break;
+                }
+
+              if (argvp[i] == NULL && expectations[i] == NULL)
+                found_expected_steam_uri_handler = TRUE;
+
+              g_strfreev (argvp);
+            }
+          else
+            {
+              g_debug ("Cannot parse \"Exec=%s\" like a shell would: %s", commandline, error->message);
+              g_clear_error (&error);
+            }
+        }
+
+      /* Exclude the special case `/usr/bin/env steam %U` that we use in our unit tests */
+      if (!found_expected_steam_uri_handler && (g_strcmp0 (commandline, "/usr/bin/env steam %U") != 0))
+        issues |= SRT_STEAM_ISSUES_UNEXPECTED_STEAM_URI_HANDLER;
 
+      if (g_strcmp0 (app_id, "steam.desktop") != 0 && g_strcmp0 (app_id, "com.valvesoftware.Steam.desktop") != 0)
+        {
+          g_debug ("The default Steam app handler id is not what we expected: %s", app_id ? app_id : "NULL");
+          issues |= SRT_STEAM_ISSUES_UNEXPECTED_STEAM_DESKTOP_ID;
+        }
+    }
+
+  steam_script = g_environ_getenv (env, "STEAMSCRIPT");
+  if (steam_script == NULL)
+    {
+      g_debug ("\"STEAMSCRIPT\" environment variable is missing");
+      issues |= SRT_STEAM_ISSUES_STEAMSCRIPT_NOT_IN_ENVIRONMENT;
+
+      if (executable != NULL &&
+          g_strcmp0 (executable, "/usr/bin/steam") != 0 &&
+          /* Arch Linux steam.desktop */
+          g_strcmp0 (executable, "/usr/bin/steam-runtime") != 0 &&
+          /* Debian steam.desktop */
+          g_strcmp0 (executable, "/usr/games/steam"))
+        {
+          g_debug ("The default Steam app executable is not what we expected: %s", executable);
+          issues |= SRT_STEAM_ISSUES_UNEXPECTED_STEAM_URI_HANDLER;
+        }
+    }
+  else
+    {
+      if (g_strcmp0 (executable, steam_script) != 0)
+        {
+          g_debug ("Unexpectedly \"STEAMSCRIPT\" environment variable and the default Steam app "
+                   "executable point to different paths: \"%s\" and \"%s\"", steam_script, executable);
+          issues |= SRT_STEAM_ISSUES_UNEXPECTED_STEAM_URI_HANDLER;
+        }
+    }
 
   if (more_details_out != NULL)
     *more_details_out = _srt_steam_new (issues,
diff --git a/steam-runtime-tools/steam.h b/steam-runtime-tools/steam.h
index a0597ce018087e00d0642473067831b210f9cb41..1037209edba8710c35ef40c03761d629a1f0958f 100644
--- a/steam-runtime-tools/steam.h
+++ b/steam-runtime-tools/steam.h
@@ -70,6 +70,16 @@ GType srt_steam_get_type (void);
  *  neither a directory nor a symbolic link to a directory.
  *  Steam is unlikely to work in this situation.
  *  See srt_system_info_dup_steam_installation_path().
+ * @SRT_STEAM_ISSUES_STEAMSCRIPT_NOT_IN_ENVIRONMENT: The environment
+ *  `STEAMSCRIPT` is not set. Probably it's safe to be considered a minor
+ *  issue.
+ * @SRT_STEAM_ISSUES_MISSING_STEAM_URI_HANDLER: There isn't a default desktop
+ *  application that can handle `steam:` URIs.
+ * @SRT_STEAM_ISSUES_UNEXPECTED_STEAM_URI_HANDLER: The default Steam URI
+ *  handler executable is either not what we expected or is different from the
+ *  one `STEAMSCRIPT` points to.
+ * @SRT_STEAM_ISSUES_UNEXPECTED_STEAM_DESKTOP_ID: The default Steam desktop
+ *  application ID is not what we expected.
  *
  * A bitfield with flags representing problems with the Steam
  * installation, or %SRT_STEAM_ISSUES_NONE (which is numerically zero)
@@ -86,6 +96,10 @@ typedef enum
   SRT_STEAM_ISSUES_DOT_STEAM_STEAM_NOT_DIRECTORY = (1 << 4),
   SRT_STEAM_ISSUES_DOT_STEAM_ROOT_NOT_SYMLINK = (1 << 5),
   SRT_STEAM_ISSUES_DOT_STEAM_ROOT_NOT_DIRECTORY = (1 << 6),
+  SRT_STEAM_ISSUES_STEAMSCRIPT_NOT_IN_ENVIRONMENT = (1 << 7),
+  SRT_STEAM_ISSUES_MISSING_STEAM_URI_HANDLER = (1 << 8),
+  SRT_STEAM_ISSUES_UNEXPECTED_STEAM_URI_HANDLER = (1 << 9),
+  SRT_STEAM_ISSUES_UNEXPECTED_STEAM_DESKTOP_ID = (1 << 10),
   SRT_STEAM_ISSUES_NONE = 0
 } SrtSteamIssues;
 
diff --git a/steam-runtime-tools/system-info.c b/steam-runtime-tools/system-info.c
index 180f44831ea531c432e11c624b0351295b612b40..8136281f994e789b64f19d2bc5c88bd5bf29e733 100644
--- a/steam-runtime-tools/system-info.c
+++ b/steam-runtime-tools/system-info.c
@@ -27,6 +27,7 @@
 
 #include "steam-runtime-tools/architecture.h"
 #include "steam-runtime-tools/architecture-internal.h"
+#include "steam-runtime-tools/desktop-entry-internal.h"
 #include "steam-runtime-tools/glib-compat.h"
 #include "steam-runtime-tools/graphics.h"
 #include "steam-runtime-tools/graphics-internal.h"
@@ -148,6 +149,11 @@ struct _SrtSystemInfo
     gchar *host_directory;
     gboolean have_data;
   } container;
+  struct
+  {
+    GList *values;
+    gboolean have_data;
+  } desktop_entry;
   SrtOsRelease os_release;
   SrtTestFlags test_flags;
   Tristate can_write_uinput;
@@ -342,6 +348,14 @@ srt_system_info_set_property (GObject *object,
     }
 }
 
+static void
+forget_desktop_entries (SrtSystemInfo *self)
+{
+  self->desktop_entry.have_data = FALSE;
+  g_list_free_full (self->desktop_entry.values, g_object_unref);
+  self->desktop_entry.values = NULL;
+}
+
 /*
  * Forget any cached information about container information.
  */
@@ -441,6 +455,7 @@ srt_system_info_finalize (GObject *object)
 {
   SrtSystemInfo *self = SRT_SYSTEM_INFO (object);
 
+  forget_desktop_entries (self);
   forget_container_info (self);
   forget_icds (self);
   forget_locales (self);
@@ -2969,3 +2984,53 @@ srt_system_info_dup_container_host_directory (SrtSystemInfo *self)
   ensure_container_info (self);
   return g_strdup (self->container.host_directory);
 }
+
+static void
+ensure_desktop_entries (SrtSystemInfo *self)
+{
+  if (self->desktop_entry.have_data)
+    return;
+
+  g_assert (self->desktop_entry.values == NULL);
+
+  self->desktop_entry.values = _srt_list_steam_desktop_entries ();
+  self->desktop_entry.have_data = TRUE;
+}
+
+/**
+ * srt_system_info_list_desktop_entries:
+ * @self: The #SrtSystemInfo object
+ *
+ * List all the available desktop applications that are able to handle the
+ * type "x-scheme-handler/steam".
+ *
+ * This function will also search for well known desktop applications ID like
+ * the Flathub `com.valvesoftware.Steam.desktop` and they'll be included even
+ * if they are not able to handle the `steam:` URI.
+ * Using `srt_desktop_entry_is_steam_handler()` it is possible to filter them out.
+ *
+ * The returned list is in no particular order.
+ *
+ * Please note that the environment variables of the current process will be used.
+ * Any possible custom environ set with `srt_system_info_set_environ()` will be
+ * ignored.
+ *
+ * Returns: (transfer full) (element-type SrtDesktopEntry) (nullable): A list of
+ *  opaque #SrtDesktopEntry objects or %NULL if nothing was found. Free with
+ *  `g_list_free_full (entries, g_object_unref)`.
+ */
+GList *
+srt_system_info_list_desktop_entries (SrtSystemInfo *self)
+{
+  GList *ret = NULL;
+  const GList *iter;
+
+  g_return_val_if_fail (SRT_IS_SYSTEM_INFO (self), NULL);
+
+  ensure_desktop_entries (self);
+
+  for (iter = self->desktop_entry.values; iter != NULL; iter = iter->next)
+    ret = g_list_prepend (ret, g_object_ref (iter->data));
+
+  return g_list_reverse (ret);
+}
diff --git a/steam-runtime-tools/system-info.h b/steam-runtime-tools/system-info.h
index f860b5a0305114e9ec623f636aa295d61338e848..731d5d6227cad7450aafc3159ae760e04b4a9518 100644
--- a/steam-runtime-tools/system-info.h
+++ b/steam-runtime-tools/system-info.h
@@ -194,6 +194,8 @@ gchar *srt_system_info_dup_os_version_id (SrtSystemInfo *self);
 
 gchar **srt_system_info_list_driver_environment (SrtSystemInfo *self);
 
+GList *srt_system_info_list_desktop_entries (SrtSystemInfo *self);
+
 #ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC
 G_DEFINE_AUTOPTR_CLEANUP_FUNC (SrtSystemInfo, g_object_unref)
 #endif
diff --git a/tests/desktop-entry.c b/tests/desktop-entry.c
new file mode 100644
index 0000000000000000000000000000000000000000..82e7d2cc5e653fbe00a250cc89775a3b80114c04
--- /dev/null
+++ b/tests/desktop-entry.c
@@ -0,0 +1,192 @@
+/*
+ * Copyright © 2020 Collabora Ltd.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <steam-runtime-tools/steam-runtime-tools.h>
+
+#include <string.h>
+#include <unistd.h>
+
+#include <glib.h>
+#include <glib/gstdio.h>
+
+#include "steam-runtime-tools/desktop-entry-internal.h"
+#include "test-utils.h"
+#include "fake-home.h"
+
+static const char *argv0;
+static gchar *fake_home_path;
+
+typedef struct
+{
+  gchar *builddir;
+} Fixture;
+
+typedef struct
+{
+  int unused;
+} Config;
+
+static void
+setup (Fixture *f,
+       gconstpointer context)
+{
+  G_GNUC_UNUSED const Config *config = context;
+  f->builddir = g_strdup (g_getenv ("G_TEST_BUILDDIR"));
+
+  if (f->builddir == NULL)
+    f->builddir = g_path_get_dirname (argv0);
+}
+
+static void
+teardown (Fixture *f,
+          gconstpointer context)
+{
+  G_GNUC_UNUSED const Config *config = context;
+
+  g_free (f->builddir);
+
+  /* We expect that fake_home already cleaned this up, but just to be sure we
+   * do it too */
+  _srt_rm_rf (fake_home_path);
+}
+
+/*
+ * Test basic functionality of the SrtDesktopEntry object.
+ */
+static void
+test_object (Fixture *f,
+             gconstpointer context)
+{
+  SrtDesktopEntry *entry;
+  gchar *id = NULL;
+  gchar *cmd = NULL;
+  gchar *filename = NULL;
+  gboolean is_default = FALSE;
+  gboolean is_steam_handler = FALSE;
+
+  entry = _srt_desktop_entry_new ("steam.desktop",
+                                  "/usr/bin/steam %U",
+                                  "/usr/share/applications/steam.desktop",
+                                  TRUE,
+                                  TRUE);
+  g_assert_cmpstr (srt_desktop_entry_get_id (entry), ==, "steam.desktop");
+  g_assert_cmpstr (srt_desktop_entry_get_commandline (entry), ==, "/usr/bin/steam %U");
+  g_assert_cmpstr (srt_desktop_entry_get_filename (entry), ==, "/usr/share/applications/steam.desktop");
+  g_assert_cmpint (srt_desktop_entry_is_default_handler (entry), ==, TRUE);
+  g_assert_cmpint (srt_desktop_entry_is_steam_handler (entry), ==, TRUE);
+  g_object_get (entry,
+                "id", &id,
+                "commandline", &cmd,
+                "filename", &filename,
+                "is-default-handler", &is_default,
+                "is-steam-handler", &is_steam_handler,
+                NULL);
+  g_assert_cmpstr (id, ==, "steam.desktop");
+  g_assert_cmpstr (cmd, ==, "/usr/bin/steam %U");
+  g_assert_cmpstr (filename, ==, "/usr/share/applications/steam.desktop");
+  g_assert_cmpint (is_default, ==, TRUE);
+  g_assert_cmpint (is_steam_handler, ==, TRUE);
+  g_free (id);
+  g_free (cmd);
+  g_free (filename);
+  g_object_unref (entry);
+}
+
+static void
+test_default_entry (Fixture *f,
+                    gconstpointer context)
+{
+  SrtSystemInfo *info;
+  FakeHome *fake_home;
+  GList *desktop_entries = NULL;
+  const gchar *filename = NULL;
+
+  fake_home = fake_home_new (fake_home_path);
+  fake_home->create_pinning_libs = FALSE;
+  fake_home->create_i386_folders = FALSE;
+  fake_home->create_amd64_folders = FALSE;
+  fake_home->create_root_symlink = FALSE;
+  fake_home->create_steam_symlink = FALSE;
+  fake_home->create_steamrt_files = FALSE;
+  fake_home->add_environments = FALSE;
+  fake_home_create_structure (fake_home);
+
+  info = srt_system_info_new (NULL);
+  fake_home_apply_to_system_info (fake_home, info);
+
+  desktop_entries = srt_system_info_list_desktop_entries (info);
+  g_assert_null (desktop_entries->next);
+  g_assert_cmpstr (srt_desktop_entry_get_id (desktop_entries->data), ==, "steam.desktop");
+  g_assert_cmpstr (srt_desktop_entry_get_commandline (desktop_entries->data), ==, "/usr/bin/env steam %U");
+  filename = srt_desktop_entry_get_filename (desktop_entries->data);
+  g_assert_true (g_str_has_prefix (filename, "/"));
+  g_assert_true (g_str_has_suffix (filename, "/steam.desktop"));
+  g_assert_true (srt_desktop_entry_is_default_handler (desktop_entries->data));
+  g_assert_true (srt_desktop_entry_is_steam_handler (desktop_entries->data));
+
+  g_list_free_full (desktop_entries, g_object_unref);
+
+  /* Do the check again, this time using the cache */
+  desktop_entries = srt_system_info_list_desktop_entries (info);
+  g_assert_null (desktop_entries->next);
+  g_assert_cmpstr (srt_desktop_entry_get_id (desktop_entries->data), ==, "steam.desktop");
+  g_assert_cmpstr (srt_desktop_entry_get_commandline (desktop_entries->data), ==, "/usr/bin/env steam %U");
+  filename = srt_desktop_entry_get_filename (desktop_entries->data);
+  g_assert_true (g_str_has_prefix (filename, "/"));
+  g_assert_true (g_str_has_suffix (filename, "/steam.desktop"));
+  g_assert_true (srt_desktop_entry_is_default_handler (desktop_entries->data));
+  g_assert_true (srt_desktop_entry_is_steam_handler (desktop_entries->data));
+
+  g_list_free_full (desktop_entries, g_object_unref);
+  fake_home_clean_up (fake_home);
+  g_clear_object (&info);
+}
+
+int
+main (int argc,
+      char **argv)
+{
+  int status;
+  argv0 = argv[0];
+
+  /* We can't use %G_TEST_OPTION_ISOLATE_DIRS because we are targeting an older glib verion.
+   * As a workaround we use our function `setup_env()`.
+   * We can't use an environ because in `_srt_steam_check()` we call `g_app_info_get_*` that
+   * doesn't support a custom environ. */
+  g_test_init (&argc, &argv, NULL);
+  fake_home_path = _srt_global_setup_private_xdg_dirs ();
+
+  g_test_add ("/desktop-entry/object", Fixture, NULL,
+              setup, test_object, teardown);
+  g_test_add ("/desktop-entry/default_entry", Fixture, NULL,
+              setup, test_default_entry, teardown);
+
+  status = g_test_run ();
+
+  if (!_srt_global_teardown_private_xdg_dirs ())
+    g_debug ("Unable to remove the fake home parent directory of: %s", fake_home_path);
+
+  return status;
+}
diff --git a/tests/fake-home.c b/tests/fake-home.c
index d10ec2cfaeb9e4048bf18cf81ebcb59063bd9e21..7bb855b9e9e651871821fc49598f8b6aac2b5720 100644
--- a/tests/fake-home.c
+++ b/tests/fake-home.c
@@ -37,18 +37,34 @@
 
 /**
  * fake_home_new:
+ * @home: (nullable) (type filename): Path to a temporary directory that will
+ *  be used, which must be in a trusted directory (not `/tmp` or `/var/tmp`).
+ *  If it doesn't exist yet, it will be created. If @home is %NULL a
+ *  random temporary directory will be used instead.
  *
  * Create a new #FakeHome object and a temporary folder in the file system
  *
  * Returns: the newely created #FakeHome object
  */
 FakeHome *
-fake_home_new (void)
+fake_home_new (const gchar *home)
 {
   GError *error = NULL;
   FakeHome *fake_home = g_slice_new (FakeHome);
-  fake_home->home = g_dir_make_tmp ("fake-home-XXXXXX", &error);
-  g_assert_no_error (error);
+  if (home)
+    {
+      gchar *dirname = g_path_get_dirname (home);
+      g_assert_cmpstr (dirname, !=, "/tmp");
+      g_assert_cmpstr (dirname, !=, "/var/tmp");
+      fake_home->home = g_strdup (home);
+      g_assert_cmpint (g_mkdir_with_parents (fake_home->home, 0755), ==, 0);
+      g_free (dirname);
+    }
+  else
+    {
+      fake_home->home = g_dir_make_tmp ("fake-home-XXXXXX", &error);
+      g_assert_no_error (error);
+    }
 
   fake_home->create_pinning_libs = TRUE;
   fake_home->create_i386_folders = TRUE;
@@ -59,6 +75,7 @@ fake_home_new (void)
   fake_home->add_environments = TRUE;
   fake_home->has_debian_bug_916303 = FALSE;
   fake_home->testing_beta_client = FALSE;
+  fake_home->create_steam_mime_apps = TRUE;
 
   return fake_home;
 }
@@ -90,9 +107,33 @@ fake_home_create_structure (FakeHome *f)
   gchar *ld_path = NULL;
   gchar *prepended_path = NULL;
   gchar *ubuntu12_32 = NULL;
+  gchar *app_home = NULL;
+  gchar *data_name = NULL;
   GError *error = NULL;
   int saved_errno;
 
+/* Instead of `/usr/bin/steam` we set Exec to `/usr/bin/env steam` because it
+ * needs to point to something that we are sure to have */
+const gchar *steam_data =
+  "[Desktop Entry]\n"
+  "Name=Steam\n"
+  "Exec=/usr/bin/env steam %U\n"
+  "Type=Application\n"
+  "Actions=Library;\n"
+  "MimeType=x-scheme-handler/steam;\n"
+  "\n"
+  "[Desktop Action Library]\n"
+  "Name=Library\n"
+  "Exec=steam steam://open/games";
+
+const gchar *mime_list =
+  "[Default Applications]\n"
+  "x-scheme-handler/steam=steam.desktop;\n";
+
+const gchar *mime_cache =
+  "[MIME Cache]\n"
+  "x-scheme-handler/steam=steam.desktop;\n";
+
   g_return_val_if_fail (f != NULL, FALSE);
 
   dot_steam = g_build_filename (f->home, ".steam", NULL);
@@ -274,6 +315,31 @@ fake_home_create_structure (FakeHome *f)
       f->env = g_environ_setenv (f->env, "PATH", prepended_path, TRUE);
     }
 
+  if (f->create_steam_mime_apps)
+    {
+      app_home = g_build_filename (local_share, "applications", NULL);
+      if (g_mkdir_with_parents (app_home, 0755) != 0)
+        goto out;
+
+      /* Instead of `/usr/bin/steam` we set it to `/usr/bin/env`, like the "steam.desktop"
+       * that we are going to create */
+      f->env = g_environ_setenv (f->env, "STEAMSCRIPT", "/usr/bin/env", TRUE);
+
+      data_name = g_build_filename (app_home, "steam.desktop", NULL);
+      g_file_set_contents (data_name, steam_data, -1, &error);
+      g_assert_no_error (error);
+      g_free (data_name);
+
+      data_name = g_build_filename (app_home, "mimeapps.list", NULL);
+      g_file_set_contents (data_name, mime_list, -1, &error);
+      g_assert_no_error (error);
+      g_free (data_name);
+
+      data_name = g_build_filename (app_home, "mimeinfo.cache", NULL);
+      g_file_set_contents (data_name, mime_cache, -1, &error);
+      g_assert_no_error (error);
+    }
+
   ret = TRUE;
 
   out:
@@ -290,6 +356,8 @@ fake_home_create_structure (FakeHome *f)
     g_free (ld_path);
     g_free (prepended_path);
     g_free (ubuntu12_32);
+    g_free (app_home);
+    g_free (data_name);
 
     if (!ret)
       g_warning ("Unable to create directories: %s", g_strerror (saved_errno));
diff --git a/tests/fake-home.h b/tests/fake-home.h
index bf589aa4cc4a86d0c77b0cb90bea6db6b2bd7684..2c74f07a2a328c5b0e7311c6075dd869eb00e090 100644
--- a/tests/fake-home.h
+++ b/tests/fake-home.h
@@ -41,6 +41,7 @@ typedef struct
   gboolean add_environments;
   gboolean has_debian_bug_916303;
   gboolean testing_beta_client;
+  gboolean create_steam_mime_apps;
 
   gchar *home;
   gchar *steam_install;
@@ -63,7 +64,7 @@ typedef struct
   GStrv env;
 } FakeHome;
 
-FakeHome * fake_home_new (void);
+FakeHome * fake_home_new (const gchar *home);
 gboolean fake_home_create_structure (FakeHome *fake_home);
 void fake_home_clean_up (FakeHome *f);
 void fake_home_apply_to_system_info (FakeHome *fake_home,
diff --git a/tests/meson.build b/tests/meson.build
index 9f03b5b25b62687c05f3eb5bb03534648d903f9c..cb8183b1907352588d1a09197dc8a554ac584027 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -29,6 +29,7 @@ test_env.prepend('PATH', join_paths(meson.current_build_dir(), '..', 'bin'))
 
 tests = [
   'architecture',
+  'desktop-entry',
   'graphics',
   'library',
   'locale',
@@ -39,6 +40,7 @@ tests = [
 
 tests_utils = [
   'fake-home.c',
+  'test-utils.c',
 ]
 
 tests_dir = join_paths(
diff --git a/tests/system-info-cli.c b/tests/system-info-cli.c
index 12051e8725c1f70c10edc5246e6c4c4d8765b424..050220b88c4b3dd94b13a205e494c9b0ead1e7bf 100644
--- a/tests/system-info-cli.c
+++ b/tests/system-info-cli.c
@@ -500,7 +500,7 @@ steam_presence (Fixture *f,
   const gchar *argv[] = { "steam-runtime-system-info", NULL };
   FakeHome *fake_home;
 
-  fake_home = fake_home_new ();
+  fake_home = fake_home_new (NULL);
   fake_home_create_structure (fake_home);
 
   result = g_spawn_sync (NULL,    /* working directory */
@@ -594,7 +594,7 @@ steam_issues (Fixture *f,
   const gchar *argv[] = { "steam-runtime-system-info", NULL };
   FakeHome *fake_home;
 
-  fake_home = fake_home_new ();
+  fake_home = fake_home_new (NULL);
   fake_home->create_pinning_libs = FALSE;
   fake_home->create_steam_symlink = FALSE;
   fake_home->create_steamrt_files = FALSE;
diff --git a/tests/system-info.c b/tests/system-info.c
index 6d6baa17c4d66fe7a38d01fd2aa87fa4eb25a969..7905874e465197e00ead9b929631e92fd37c10ce 100644
--- a/tests/system-info.c
+++ b/tests/system-info.c
@@ -42,6 +42,7 @@
 #include "fake-home.h"
 
 static const char *argv0;
+static gchar *fake_home_path;
 
 typedef struct
 {
@@ -78,6 +79,10 @@ teardown (Fixture *f,
 
   g_free (f->srcdir);
   g_free (f->builddir);
+
+  /* We expect that fake_home already cleaned this up, but just to be sure we
+   * do it too */
+  _srt_rm_rf (fake_home_path);
 }
 
 /*
@@ -732,7 +737,7 @@ steam_runtime (Fixture *f,
   gchar *installation_path = NULL;
   FakeHome *fake_home;
 
-  fake_home = fake_home_new ();
+  fake_home = fake_home_new (fake_home_path);
   fake_home_create_structure (fake_home);
 
   info = srt_system_info_new (NULL);
@@ -758,11 +763,11 @@ steam_runtime (Fixture *f,
 
   /* Check for Steam issues */
   steam_issues = srt_system_info_get_steam_issues (info);
-  g_assert_cmpint (steam_issues, ==, SRT_RUNTIME_ISSUES_NONE);
+  g_assert_cmpint (steam_issues, ==, SRT_STEAM_ISSUES_NONE);
 
   /* Do the check again, this time using the cache */
   steam_issues = srt_system_info_get_steam_issues (info);
-  g_assert_cmpint (steam_issues, ==, SRT_RUNTIME_ISSUES_NONE);
+  g_assert_cmpint (steam_issues, ==, SRT_STEAM_ISSUES_NONE);
 
   fake_home_clean_up (fake_home);
   g_object_unref (info);
@@ -780,7 +785,7 @@ steam_runtime_missing (Fixture *f,
   gchar *full_ld_path = NULL;
   FakeHome *fake_home;
 
-  fake_home = fake_home_new ();
+  fake_home = fake_home_new (fake_home_path);
   fake_home_create_structure (fake_home);
 
   full_ld_path = g_strdup (g_environ_getenv (fake_home->env, "LD_LIBRARY_PATH"));
@@ -825,7 +830,7 @@ steam_runtime_pinned (Fixture *f,
   gchar *ld_path = NULL;
   FakeHome *fake_home;
 
-  fake_home = fake_home_new ();
+  fake_home = fake_home_new (fake_home_path);
   fake_home_create_structure (fake_home);
 
   full_ld_path = g_strdup (g_environ_getenv (fake_home->env, "LD_LIBRARY_PATH"));
@@ -890,7 +895,7 @@ runtime_disabled_or_missing (Fixture *f,
   gchar *runtime_path = NULL;
   FakeHome *fake_home;
 
-  fake_home = fake_home_new ();
+  fake_home = fake_home_new (fake_home_path);
   fake_home->create_steamrt_files = FALSE;
   fake_home_create_structure (fake_home);
 
@@ -944,7 +949,7 @@ runtime_version (Fixture *f,
   GError *error = NULL;
   FakeHome *fake_home;
 
-  fake_home = fake_home_new ();
+  fake_home = fake_home_new (fake_home_path);
   fake_home_create_structure (fake_home);
 
   version = g_build_filename (fake_home->runtime, "version.txt", NULL);
@@ -1058,7 +1063,7 @@ runtime_unexpected_location (Fixture *f,
   GError *error = NULL;
   FakeHome *fake_home;
 
-  fake_home = fake_home_new ();
+  fake_home = fake_home_new (fake_home_path);
   fake_home->create_root_symlink = FALSE;
   fake_home_create_structure (fake_home);
 
@@ -1131,7 +1136,7 @@ steam_symlink (Fixture *f,
   GError *error = NULL;
   FakeHome *fake_home;
 
-  fake_home = fake_home_new ();
+  fake_home = fake_home_new (fake_home_path);
   fake_home->create_steam_symlink = FALSE;
   fake_home_create_structure (fake_home);
 
@@ -1200,7 +1205,7 @@ debian_bug_916303 (Fixture *f,
   gchar *installation_path;
   gchar *data_path;
 
-  fake_home = fake_home_new ();
+  fake_home = fake_home_new (fake_home_path);
   fake_home->has_debian_bug_916303 = TRUE;
   fake_home_create_structure (fake_home);
 
@@ -1233,7 +1238,7 @@ testing_beta_client (Fixture *f,
   gchar *installation_path;
   gchar *data_path;
 
-  fake_home = fake_home_new ();
+  fake_home = fake_home_new (fake_home_path);
   fake_home->testing_beta_client = TRUE;
   fake_home_create_structure (fake_home);
 
@@ -1837,7 +1842,7 @@ pinned_libraries (Fixture *f,
   gsize i;
   GError *error = NULL;
 
-  fake_home = fake_home_new ();
+  fake_home = fake_home_new (fake_home_path);
   fake_home_create_structure (fake_home);
 
   info = srt_system_info_new (NULL);
@@ -1985,7 +1990,7 @@ pinned_libraries_permission (Fixture *f,
   gboolean seen_no_access;
   gsize i;
 
-  fake_home = fake_home_new ();
+  fake_home = fake_home_new (fake_home_path);
   fake_home_create_structure (fake_home);
 
   info = srt_system_info_new (NULL);
@@ -2069,7 +2074,7 @@ pinned_libraries_missing (Fixture *f,
   gchar **values = NULL;
   gchar **messages = NULL;
 
-  fake_home = fake_home_new ();
+  fake_home = fake_home_new (fake_home_path);
   fake_home_create_structure (fake_home);
 
   info = srt_system_info_new (NULL);
@@ -2255,9 +2260,16 @@ int
 main (int argc,
       char **argv)
 {
+  int status;
   argv0 = argv[0];
 
+  /* We can't use %G_TEST_OPTION_ISOLATE_DIRS because we are targeting an older glib verion.
+   * As a workaround we use our function `setup_env()`.
+   * We can't use an environ because in `_srt_steam_check()` we call `g_app_info_get_*` that
+   * doesn't support a custom environ. */
   g_test_init (&argc, &argv, NULL);
+  fake_home_path = _srt_global_setup_private_xdg_dirs ();
+
   g_test_add ("/system-info/object", Fixture, NULL,
               setup, test_object, teardown);
   g_test_add ("/system-info/libraries_presence", Fixture, NULL,
@@ -2324,5 +2336,10 @@ main (int argc,
   g_test_add ("/system-info/containers", Fixture, NULL,
               setup, test_containers, teardown);
 
-  return g_test_run ();
+  status = g_test_run ();
+
+  if (!_srt_global_teardown_private_xdg_dirs ())
+    g_debug ("Unable to remove the fake home parent directory of: %s", fake_home_path);
+
+  return status;
 }
diff --git a/tests/test-utils.c b/tests/test-utils.c
new file mode 100644
index 0000000000000000000000000000000000000000..c3a6dded9d3da0343345ee8f5488902c522b7bd6
--- /dev/null
+++ b/tests/test-utils.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright © 2020 Collabora Ltd.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "test-utils.h"
+
+#include <glib-object.h>
+#include "steam-runtime-tools/glib-compat.h"
+#include <steam-runtime-tools/steam-runtime-tools.h>
+
+static gchar *fake_home_parent = NULL;
+
+/**
+ * _srt_global_setup_private_xdg_dirs:
+ *
+ * Setup a fake home directory and, following the [XDG standard]
+ * (https://specifications.freedesktop.org/mime-apps-spec/mime-apps-spec-1.0.html)
+ * mask every XDG used in the MIME lookup to avoid altering the tests if there
+ * were already other user defined MIME lists.
+ *
+ * Call this function one time before launching the tests because changing the
+ * environment variables is not thread safe.
+ *
+ * Returns: (type filename) (transfer full): Absolute path to the newly created
+ *  fake home directory.
+ */
+gchar *
+_srt_global_setup_private_xdg_dirs (void)
+{
+  GError *error = NULL;
+  gchar *fake_home_path = NULL;
+  gchar *xdg_data_home = NULL;
+
+  g_return_val_if_fail (fake_home_parent == NULL, NULL);
+
+  /* Create a directory that we control, and then put the fake home
+   * directory inside it, so we can delete and recreate the fake home
+   * directory without being vulnerable to symlink attacks. */
+  fake_home_parent = g_dir_make_tmp ("fake-home-XXXXXX", &error);
+  g_assert_no_error (error);
+  fake_home_path = g_build_filename (fake_home_parent, "home", NULL);
+
+  xdg_data_home = g_build_filename (fake_home_path, ".local", "share", NULL);
+
+  g_setenv ("XDG_CONFIG_HOME", xdg_data_home, TRUE);
+  g_setenv ("XDG_CONFIG_DIRS", xdg_data_home, TRUE);
+  g_setenv ("XDG_DATA_HOME", xdg_data_home, TRUE);
+  g_setenv ("XDG_DATA_DIRS", xdg_data_home, TRUE);
+
+  g_free (xdg_data_home);
+
+  return fake_home_path;
+}
+
+/**
+ * _srt_global_teardown_private_xdg_dirs:
+ *
+ * Teardown the previously created temporary directory.
+ *
+ * Returns: %TRUE if no errors occurred removing the temporary directory.
+ */
+gboolean
+_srt_global_teardown_private_xdg_dirs (void)
+{
+  gboolean result;
+  g_return_val_if_fail (fake_home_parent != NULL, FALSE);
+
+  result = _srt_rm_rf (fake_home_parent);
+  g_free (fake_home_parent);
+  fake_home_parent = NULL;
+
+  return result;
+}
\ No newline at end of file
diff --git a/tests/test-utils.h b/tests/test-utils.h
index e963a25495cc255fcff308d79ac4162e1ff079f8..2973e2bc720ad216d58e6319635d8e18d262bcbc 100644
--- a/tests/test-utils.h
+++ b/tests/test-utils.h
@@ -64,3 +64,6 @@
 #if !GLIB_CHECK_VERSION(2, 38, 0)
 #define g_test_skip(msg) g_test_message ("SKIP: %s", msg)
 #endif
+
+gchar *_srt_global_setup_private_xdg_dirs (void);
+gboolean _srt_global_teardown_private_xdg_dirs (void);