Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • steamrt/steam-runtime-tools
1 result
Show changes
Commits on Source (8)
Showing
with 1324 additions and 69 deletions
......@@ -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);
......
......@@ -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
......
steam-runtime-tools (0.20200317.0-0+steamrt1.1) UNRELEASED; urgency=medium
steam-runtime-tools (0.20200331.1-0+steamrt1.1) scout; urgency=medium
* Fix version number
* Update symbols file
-- Simon McVittie <smcv@collabora.com> Tue, 31 Mar 2020 21:00:28 +0100
steam-runtime-tools (0.20200331.0-0+steamrt1.1) scout; urgency=medium
[ Ludovico de Nittis ]
* Add srt_vdpau_driver_resolve_library_path, etc. methods.
......@@ -20,7 +27,7 @@ steam-runtime-tools (0.20200317.0-0+steamrt1.1) UNRELEASED; urgency=medium
The Steam Runtime has a backport of meson 0.49.0, originally from Debian
stretch-backports, which is the oldest thing we'll even try to support.
-- Simon McVittie <smcv@collabora.com> Tue, 17 Mar 2020 17:11:42 +0000
-- Simon McVittie <smcv@collabora.com> Tue, 31 Mar 2020 20:40:41 +0100
steam-runtime-tools (0.20200306.0-0+steamrt1.1) scout; urgency=medium
......
......@@ -10,6 +10,7 @@ libsteam-runtime-tools-0.so.0 libsteam-runtime-tools-0-0 #MINVER#
srt_dri_driver_get_library_path@Base 0.20200109.0
srt_dri_driver_get_type@Base 0.20200109.0
srt_dri_driver_is_extra@Base 0.20200109.0
srt_dri_driver_resolve_library_path@Base 0.20200331.1
srt_driver_flags_get_type@Base 0.20200109.0
srt_egl_icd_check_error@Base 0.20190926.0
srt_egl_icd_get_json_path@Base 0.20190926.0
......@@ -109,10 +110,12 @@ libsteam-runtime-tools-0.so.0 libsteam-runtime-tools-0-0 #MINVER#
srt_va_api_driver_get_library_path@Base 0.20200109.0
srt_va_api_driver_get_type@Base 0.20200109.0
srt_va_api_driver_is_extra@Base 0.20200109.0
srt_va_api_driver_resolve_library_path@Base 0.20200331.1
srt_vdpau_driver_get_library_link@Base 0.20200306.0
srt_vdpau_driver_get_library_path@Base 0.20200306.0
srt_vdpau_driver_get_type@Base 0.20200306.0
srt_vdpau_driver_is_extra@Base 0.20200306.0
srt_vdpau_driver_resolve_library_path@Base 0.20200331.1
srt_vulkan_icd_check_error@Base 0.20190926.0
srt_vulkan_icd_get_api_version@Base 0.20190926.0
srt_vulkan_icd_get_json_path@Base 0.20190926.0
......
......@@ -23,7 +23,7 @@
project(
'steam-runtime-tools', 'c',
version : '0.20200306.0',
version : '0.20200331.1',
default_options: [
'c_std=c99',
'cpp_std=c++11',
......@@ -35,7 +35,7 @@ add_languages('cpp')
api_major = '0'
abi_major = '0'
abi_minor = '20200306.0'
abi_minor = '20200331.1'
pkg = import('pkgconfig')
gnome = import('gnome')
......@@ -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',
......
/*< 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);
/*
* 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);
}
/*
* 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);
......@@ -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,
......
/*<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);
......@@ -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>
......
/*
* Copyright © 2019 Collabora Ltd.
* Copyright © 2019-2020 Collabora Ltd.
*
* SPDX-License-Identifier: MIT
*
......@@ -32,7 +32,9 @@
#include <string.h>
#include <glib.h>
#include <gio/gio.h>
#include "steam-runtime-tools/enums.h"
#include "steam-runtime-tools/glib-compat.h"
#include "steam-runtime-tools/utils.h"
......@@ -46,46 +48,265 @@
* 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()`.
*
* 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
*/
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;
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);
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 +477,88 @@ _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);
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 (data_path_out != NULL)
*data_path_out = g_strdup (data_path);
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 (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);
......
......@@ -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
......@@ -56,6 +70,16 @@
* 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)
......@@ -72,5 +96,14 @@ 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;
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);
......@@ -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"
......@@ -104,6 +105,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 +114,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 */
......@@ -156,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;
......@@ -350,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.
*/
......@@ -401,10 +407,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;
}
/*
......@@ -450,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);
......@@ -1626,13 +1632,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 +1652,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 +1694,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 +1736,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 +2084,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,
......@@ -2983,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);
}
......@@ -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
/*
* 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;
}
......@@ -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));
......
......@@ -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,
......
......@@ -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(
......
......@@ -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;
......