diff --git a/flatpak/org.gnome.Games.json b/flatpak/org.gnome.Games.json index 9947d479c62de32f5013f5c8c3d890f1516a92a3..a212c8641e80bdaf5f98e577c38017381b85f93f 100644 --- a/flatpak/org.gnome.Games.json +++ b/flatpak/org.gnome.Games.json @@ -38,6 +38,9 @@ "--talk-name=org.freedesktop.Flatpak", /* Needed to find the ROMs */ "--filesystem=home:ro", + /* Needed to find icons for flatpaked Steam and desktop games */ + "--filesystem=~/.local/share/flatpak:ro", + "--filesystem=/var/lib/flatpak:ro", /* Needed to find flatpaked Steam games */ "--filesystem=~/.var/app/com.valvesoftware.Steam:ro" ], diff --git a/plugins/desktop/src/desktop-icon.vala b/plugins/desktop/src/desktop-icon.vala index c556b4058fdc34bf7a85b187a9a7a8b996106f2f..f4bffd64a2360b1096ba41f0dcd14880c893c549 100644 --- a/plugins/desktop/src/desktop-icon.vala +++ b/plugins/desktop/src/desktop-icon.vala @@ -1,13 +1,13 @@ // This file is part of GNOME Games. License: GPL-3.0+. public class Games.DesktopIcon : Object, Icon { - private DesktopAppInfo app_info; + private GLib.Icon icon; - public DesktopIcon (DesktopAppInfo app_info) { - this.app_info = app_info; + public DesktopIcon (GLib.Icon icon) { + this.icon = icon; } public GLib.Icon? get_icon () { - return app_info.get_icon (); + return icon; } } diff --git a/plugins/desktop/src/desktop-plugin.vala b/plugins/desktop/src/desktop-plugin.vala index 62d51582c8dfd6c797cbce6d5b2606d7868eef53..55b7d874021d00f0c11646d710e2bc644f6d7f08 100644 --- a/plugins/desktop/src/desktop-plugin.vala +++ b/plugins/desktop/src/desktop-plugin.vala @@ -1,7 +1,9 @@ // This file is part of GNOME Games. License: GPL-3.0+. private class Games.DesktopPlugin : Object, Plugin { - private const string MIME_TYPE = "application/x-desktop"; + private const string DESKTOP_URI_PREFIX = "desktop+"; + private const string DESKTOP_FILE_URI_SCHEME = "desktop+file"; + private const string PLATFORM_ID = "Desktop"; private const string PLATFORM_NAME = _("Desktop"); @@ -9,10 +11,11 @@ private class Games.DesktopPlugin : Object, Plugin { static construct { platform = new GenericPlatform (PLATFORM_ID, PLATFORM_NAME); - } - public string[] get_mime_types () { - return { MIME_TYPE }; + var home = Environment.get_home_dir (); + var icon_theme = Gtk.IconTheme.get_default (); + icon_theme.prepend_search_path (home + "/.local/share/flatpak/exports/share/icons"); + icon_theme.prepend_search_path ("/var/lib/flatpak/exports/share/icons"); } public UriSource[] get_uri_sources () { @@ -21,6 +24,7 @@ private class Games.DesktopPlugin : Object, Plugin { var connection = Tracker.Sparql.Connection.@get (); var uri_source = new TrackerUriSource (connection); uri_source.add_query (query); + uri_source.set_prefix (DESKTOP_URI_PREFIX); return { uri_source }; } @@ -34,24 +38,29 @@ private class Games.DesktopPlugin : Object, Plugin { public UriGameFactory[] get_uri_game_factories () { var game_uri_adapter = new GenericGameUriAdapter (game_for_uri); var factory = new GenericUriGameFactory (game_uri_adapter); - factory.add_mime_type (MIME_TYPE); + factory.add_scheme (DESKTOP_FILE_URI_SCHEME); return { factory }; } private static Game game_for_uri (Uri uri) throws Error { - check_uri (uri); + var file_uri = new Uri.from_uri_and_scheme (uri, "file"); + + var info = new DesktopTrackerAppInfo (file_uri); + + var filename = info.get_filename (); + var command = info.get_command (); - var file = uri.to_file (); - var path = file.get_path (); +// check_displayability (app_info); + check_categories (file_uri, info.get_categories ()); + check_executable (file_uri, info.get_executable ()); + check_base_name (file_uri, filename); - var app_info = new DesktopAppInfo.from_filename (path); - var uid = new DesktopUid (app_info); - var title = new DesktopTitle (app_info); - var icon = new DesktopIcon (app_info); + var uid = new DesktopUid (filename); + var title = new GenericTitle (info.get_title ()); + var icon = new DesktopIcon (info.get_icon ()); string[] args; - var command = app_info.get_commandline (); if (!Shell.parse_argv (command, out args)) throw new CommandError.INVALID_COMMAND (_("Invalid command “%s”."), command); var runner = new CommandRunner (args); @@ -61,25 +70,7 @@ private class Games.DesktopPlugin : Object, Plugin { return game; } - - private static void check_uri (Uri uri) throws Error { - var file = uri.to_file (); - - if (!file.query_exists ()) - throw new IOError.NOT_FOUND (_("Tracker listed file not found: “%s”."), uri.to_string ()); - - var path = file.get_path (); - var app_info = new DesktopAppInfo.from_filename (path); - - if (app_info == null) - throw new DesktopError.INVALID_APPINFO (_("Couldn’t parse desktop entry “%s”."), path); - - check_displayability (app_info); - check_categories (app_info); - check_executable (app_info); - check_base_name (file); - } - +/* private static void check_displayability (DesktopAppInfo app_info) throws Error { if (app_info.get_nodisplay ()) throw new DesktopError.BLACKLISTED_GAME (_("“%s” shouldn’t be displayed."), app_info.filename); @@ -87,30 +78,23 @@ private class Games.DesktopPlugin : Object, Plugin { if (app_info.get_is_hidden ()) throw new DesktopError.BLACKLISTED_GAME (_("“%s” is hidden."), app_info.filename); } - - private static void check_categories (DesktopAppInfo app_info) throws Error { - var categories_string = app_info.get_categories (); - var categories = categories_string.split (";"); - +*/ + private static void check_categories (Uri uri, string[] categories) throws Error { foreach (var category in get_categories_black_list ()) if (category in categories) - throw new DesktopError.BLACKLISTED_GAME (_("“%s” has blacklisted category “%s”."), app_info.filename, category); + throw new DesktopError.BLACKLISTED_GAME (_("“%s” has blacklisted category “%s”."), uri.to_string (), category); } - private static void check_executable (DesktopAppInfo app_info) throws Error { - var app_executable = app_info.get_executable (); - + private static void check_executable (Uri uri, string app_executable) throws Error { foreach (var executable in get_executable_black_list ()) if (app_executable == executable || app_executable.has_suffix ("/" + executable)) - throw new DesktopError.BLACKLISTED_GAME (_("“%s” has blacklisted executable “%s”."), app_info.filename, executable); + throw new DesktopError.BLACKLISTED_GAME (_("“%s” has blacklisted executable “%s”."), uri.to_string (), executable); } - private static void check_base_name (File file) throws Error { - var base_name = file.get_basename (); - + private static void check_base_name (Uri uri, string base_name) throws Error { if (base_name in get_base_name_black_list ()) - throw new DesktopError.BLACKLISTED_GAME (_("“%s” is blacklisted."), file.get_path ()); + throw new DesktopError.BLACKLISTED_GAME (_("“%s” is blacklisted."), uri.to_string ()); } private static string[] categories_black_list; diff --git a/plugins/desktop/src/desktop-tracker-app-info.vala b/plugins/desktop/src/desktop-tracker-app-info.vala new file mode 100644 index 0000000000000000000000000000000000000000..d6702a3635083d6fa5ee4d6ef82542f35ace5989 --- /dev/null +++ b/plugins/desktop/src/desktop-tracker-app-info.vala @@ -0,0 +1,67 @@ +// This file is part of GNOME Games. License: GPL-3.0+. + +private class Games.DesktopTrackerAppInfo : Object { + private const string TRACKER_KEY_PREFIX_NFO = "http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#"; + private const string TRACKER_KEY_PREFIX_NIE = "http://www.semanticdesktop.org/ontologies/2007/01/19/nie#"; + private const string TRACKER_KEY_CMDLINE = TRACKER_KEY_PREFIX_NFO + "softwareCmdLine"; + private const string TRACKER_KEY_ICON = TRACKER_KEY_PREFIX_NFO + "softwareIcon"; + private const string TRACKER_KEY_TITLE = TRACKER_KEY_PREFIX_NIE + "title"; + private const string TRACKER_KEY_FILE_NAME = TRACKER_KEY_PREFIX_NFO + "fileName"; + private const string TRACKER_KEY_CATEGORY = TRACKER_KEY_PREFIX_NIE + "isLogicalPartOf"; + + private TrackerMetadata metadata; + + public DesktopTrackerAppInfo (Uri uri) throws Error { + var connection = Tracker.Sparql.Connection.@get (); + metadata = new TrackerMetadata (connection, uri); + } + + public GLib.Icon? get_icon () { + var val = metadata.get_object (TRACKER_KEY_ICON); + var icon = val.replace ("urn:theme-icon:", ""); + + try { + return GLib.Icon.new_for_string (icon); + } catch (Error e) { + debug (e.message); + return null; + } + } + + public string get_title () { + return metadata.get_object (TRACKER_KEY_TITLE); + } + + public string get_filename () { + return metadata.get_object (TRACKER_KEY_FILE_NAME); + } + + public string get_command () { + return metadata.get_object (TRACKER_KEY_CMDLINE); + } + + public string[] get_categories () { + var categories = metadata.get_all_objects (TRACKER_KEY_CATEGORY); + string[] result = {}; + foreach (var category in categories) + result += category.replace ("urn:software-category:", ""); + + return result; + } + + public string get_executable () { + var cmdline = get_command (); + var args = cmdline.split(" "); + + // FIXME + if (args[0].has_suffix ("flatpak")) { + var index = 1; + while (args[index].has_prefix ("-")) + index++; + + return args[index]; + } + + return args[0]; + } +} diff --git a/plugins/desktop/src/desktop-uid.vala b/plugins/desktop/src/desktop-uid.vala index 0547c2df001d16f5fb19b4219d2657889ff7879f..3ccbb171341326b892ca9379cf1ab9562f057cdd 100644 --- a/plugins/desktop/src/desktop-uid.vala +++ b/plugins/desktop/src/desktop-uid.vala @@ -2,18 +2,17 @@ private class Games.DesktopUid: Object, Uid { private string uid; - private DesktopAppInfo app_info; + private string base_name; - public DesktopUid (DesktopAppInfo app_info) { - this.app_info = app_info; + public DesktopUid (string base_name) { + this.base_name = base_name; } public string get_uid () throws Error { if (uid != null) return uid; - var appid = app_info.get_id (); - var hash = Checksum.compute_for_string (ChecksumType.SHA256, appid); + var hash = Checksum.compute_for_string (ChecksumType.SHA256, base_name); uid = @"desktop-$hash"; diff --git a/plugins/desktop/src/meson.build b/plugins/desktop/src/meson.build index e139521e5b0f806551b6c20c60bcd042dd360fa7..0738dc7843fd0d522aee004c8e62bb7afa6a2c3b 100644 --- a/plugins/desktop/src/meson.build +++ b/plugins/desktop/src/meson.build @@ -3,6 +3,7 @@ vala_sources = [ 'desktop-icon.vala', 'desktop-plugin.vala', 'desktop-title.vala', + 'desktop-tracker-app-info.vala', 'desktop-tracker-uri-query.vala', 'desktop-uid.vala', ] diff --git a/src/meson.build b/src/meson.build index 6c556d472ce2af586a0c3d97243860fdcd428998..73d83ab1fc1a6bb9e674f4089590d5bf5ab5b23f 100644 --- a/src/meson.build +++ b/src/meson.build @@ -119,6 +119,7 @@ vala_sources = [ 'tracker/mime-type-tracker-uri-query.vala', 'tracker/tracker-error.vala', + 'tracker/tracker-metadata.vala', 'tracker/tracker-uri-iterator.vala', 'tracker/tracker-uri-query.vala', 'tracker/tracker-uri-source.vala', diff --git a/src/tracker/tracker-metadata.vala b/src/tracker/tracker-metadata.vala new file mode 100644 index 0000000000000000000000000000000000000000..f7b4ccae097fc96c6f3960bbebbd151bf407a883 --- /dev/null +++ b/src/tracker/tracker-metadata.vala @@ -0,0 +1,69 @@ +// This file is part of GNOME Games. License: GPL-3.0+. + +private struct Games.TrackerMetadataPair { + public string predicate; + public string object; +} + +public class Games.TrackerMetadata : Object { + private Tracker.Sparql.Connection connection; + private Uri uri; + private Tracker.Sparql.Cursor cursor; + private TrackerMetadataPair[] pairs; + + public TrackerMetadata (Tracker.Sparql.Connection connection, Uri uri) { + this.connection = connection; + this.uri = uri; + cursor = null; + } + + private void perform_query () throws Error { + var uri_string = uri.to_string (); + var query = @"SELECT ?predicate ?object WHERE { <$uri_string> ?predicate ?object }"; + + cursor = connection.query (query); + + pairs = {}; + while (cursor.next ()) { + var predicate = cursor.get_string (0); + var object = cursor.get_string (1); + + var pair = TrackerMetadataPair (); + pair.predicate = predicate; + pair.object = object; + pairs += pair; + } + } + + private void ensure_is_loaded () { + if (pairs == null) { + try { + perform_query (); + } + catch (Error e) { + critical (e.message); + } + } + } + + public string get_object (string predicate) { + ensure_is_loaded (); + + foreach (var pair in pairs) + if (pair.predicate == predicate) + return pair.object; + + return ""; + } + + public string[] get_all_objects (string predicate) { + ensure_is_loaded (); + + string[] result = {}; + foreach (var pair in pairs) + if (pair.predicate == predicate) + result += pair.object; + + return result; + } +} diff --git a/src/tracker/tracker-uri-iterator.vala b/src/tracker/tracker-uri-iterator.vala index f04130dbf4141f6a197189535cfb242c8b5c0eda..a8e0f2410f57a5cb5531cdf0b0cdbea7bb0ee25d 100644 --- a/src/tracker/tracker-uri-iterator.vala +++ b/src/tracker/tracker-uri-iterator.vala @@ -3,13 +3,15 @@ private class Games.TrackerUriIterator : Object, UriIterator { private Tracker.Sparql.Connection connection; private TrackerUriQuery[] queries; + private string prefix; private int query_index; private Uri? uri; private Tracker.Sparql.Cursor cursor; - internal TrackerUriIterator (Tracker.Sparql.Connection connection, TrackerUriQuery[] queries) { + internal TrackerUriIterator (Tracker.Sparql.Connection connection, TrackerUriQuery[] queries, string prefix) { this.connection = connection; this.queries = queries; + this.prefix = prefix; query_index = 0; uri = null; cursor = null; @@ -54,7 +56,7 @@ private class Games.TrackerUriIterator : Object, UriIterator { if (!cursor.next ()) return false; - uri = new Uri (cursor.get_string (0)); + uri = new Uri (prefix + cursor.get_string (0)); return true; } diff --git a/src/tracker/tracker-uri-source.vala b/src/tracker/tracker-uri-source.vala index 3a6ec58d178ec694005971c3bab67a01308f433c..7d5e47ea2d6ba20a4a65c7083248cef97856adfb 100644 --- a/src/tracker/tracker-uri-source.vala +++ b/src/tracker/tracker-uri-source.vala @@ -3,13 +3,19 @@ public class Games.TrackerUriSource : Object, UriSource { private Tracker.Sparql.Connection connection { get; private set; } private TrackerUriQuery[] queries; + private string prefix; public TrackerUriSource (Tracker.Sparql.Connection connection) { this.connection = connection; } + public void set_prefix (string prefix) { + this.prefix = prefix; + } + construct { queries = {}; + prefix = ""; } public void add_query (TrackerUriQuery query) { @@ -17,6 +23,6 @@ public class Games.TrackerUriSource : Object, UriSource { } public UriIterator iterator () { - return new TrackerUriIterator (connection, queries); + return new TrackerUriIterator (connection, queries, prefix); } }