From b463ba18e521d9f842c31297e1a9061d13869259 Mon Sep 17 00:00:00 2001 From: Alexander Mikhaylenko Date: Thu, 9 Aug 2018 18:15:04 +0500 Subject: [PATCH 1/6] tracker: Add TrackerMetadata --- src/meson.build | 1 + src/tracker/tracker-metadata.vala | 69 +++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+) create mode 100644 src/tracker/tracker-metadata.vala diff --git a/src/meson.build b/src/meson.build index 6c556d47..73d83ab1 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 00000000..f7b4ccae --- /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; + } +} -- GitLab From 0ab17763b887572746d93371d27a8d47e0851291 Mon Sep 17 00:00:00 2001 From: Alexander Mikhaylenko Date: Thu, 9 Aug 2018 20:04:52 +0500 Subject: [PATCH 2/6] tracker: Add prefix --- src/tracker/tracker-uri-iterator.vala | 6 ++++-- src/tracker/tracker-uri-source.vala | 8 +++++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/tracker/tracker-uri-iterator.vala b/src/tracker/tracker-uri-iterator.vala index f04130db..a8e0f241 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 3a6ec58d..7d5e47ea 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); } } -- GitLab From c8a316b5b5fc9febdcf21215bcf1bd870b68f0b0 Mon Sep 17 00:00:00 2001 From: Alexander Mikhaylenko Date: Thu, 9 Aug 2018 20:05:02 +0500 Subject: [PATCH 3/6] desktop: Add DesktopTrackerAppInfo This will allow to get desktop app metadata via tracker exclusively. --- .../desktop/src/desktop-tracker-app-info.vala | 67 +++++++++++++++++++ plugins/desktop/src/meson.build | 1 + 2 files changed, 68 insertions(+) create mode 100644 plugins/desktop/src/desktop-tracker-app-info.vala 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 00000000..d6702a36 --- /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/meson.build b/plugins/desktop/src/meson.build index e139521e..0738dc78 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', ] -- GitLab From 4e43561c39b0a4f2080eb922d7f4ba2540224b7e Mon Sep 17 00:00:00 2001 From: Alexander Mikhaylenko Date: Thu, 9 Aug 2018 20:05:02 +0500 Subject: [PATCH 4/6] desktop: Fetch metadata via DesktopTrackerAppInfo Avoid using GLib.DesktopAppInfo, because that doesn't work in sandbox. --- plugins/desktop/src/desktop-icon.vala | 8 +-- plugins/desktop/src/desktop-plugin.vala | 73 +++++++++---------------- plugins/desktop/src/desktop-uid.vala | 9 ++- 3 files changed, 34 insertions(+), 56 deletions(-) diff --git a/plugins/desktop/src/desktop-icon.vala b/plugins/desktop/src/desktop-icon.vala index c556b405..f4bffd64 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 62d51582..f39d6e51 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"); @@ -11,16 +13,13 @@ private class Games.DesktopPlugin : Object, Plugin { platform = new GenericPlatform (PLATFORM_ID, PLATFORM_NAME); } - public string[] get_mime_types () { - return { MIME_TYPE }; - } - public UriSource[] get_uri_sources () { var query = new DesktopTrackerUriQuery (); try { 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 +33,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 file = uri.to_file (); - var path = file.get_path (); + var filename = info.get_filename (); + var command = info.get_command (); - 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); +// 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 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 +65,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 +73,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-uid.vala b/plugins/desktop/src/desktop-uid.vala index 0547c2df..3ccbb171 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"; -- GitLab From d647ef5f9286be992cbc1681e34bb62b97e763f6 Mon Sep 17 00:00:00 2001 From: Alexander Mikhaylenko Date: Fri, 10 Aug 2018 20:06:34 +0500 Subject: [PATCH 5/6] flatpak: Open access to flatpak icon exports path This is needed to be able to get icons for Flatpak-ed desktop games and Steam. --- flatpak/org.gnome.Games.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/flatpak/org.gnome.Games.json b/flatpak/org.gnome.Games.json index 9947d479..a212c864 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" ], -- GitLab From 693817cffa8473cb1837f0bc35a307dcebf6d776 Mon Sep 17 00:00:00 2001 From: Alexander Mikhaylenko Date: Fri, 10 Aug 2018 20:07:45 +0500 Subject: [PATCH 6/6] desktop: Add Flatpak icon paths --- plugins/desktop/src/desktop-plugin.vala | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/plugins/desktop/src/desktop-plugin.vala b/plugins/desktop/src/desktop-plugin.vala index f39d6e51..55b7d874 100644 --- a/plugins/desktop/src/desktop-plugin.vala +++ b/plugins/desktop/src/desktop-plugin.vala @@ -11,6 +11,11 @@ private class Games.DesktopPlugin : Object, Plugin { static construct { platform = new GenericPlatform (PLATFORM_ID, PLATFORM_NAME); + + 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 () { -- GitLab