[gnome-games/wip/aplazas/run-uri: 4/4] Add GameSource.game_for_uri()



commit 9705143e5fd7d332920c3e85ef86f48ad4cd29ef
Author: Adrien Plazas <kekun plazas laposte net>
Date:   Wed Mar 29 14:56:38 2017 +0200

    Add GameSource.game_for_uri()

 data/org.gnome.Games.desktop.in                    |    1 +
 plugins/desktop/src/desktop-tracker-query.vala     |    6 +++
 plugins/libretro/src/Makefile.am                   |    1 +
 plugins/libretro/src/libretro-error.vala           |    6 +++
 plugins/libretro/src/libretro-game-source.vala     |   16 ++++++++
 plugins/mame/src/mame-game-info.vala               |   38 +++++++++++++++++-
 plugins/mame/src/mame-game-uri-adapter.vala        |   34 +++++++++++++++-
 .../playstation/src/playstation-game-factory.vala  |    4 ++
 plugins/steam/src/steam-game-source.vala           |   26 ++++++++++---
 src/core/game-source.vala                          |    1 +
 src/core/game-uri-adapter.vala                     |    3 +-
 src/core/uri-game-factory.vala                     |    1 +
 src/dummy/dummy-game-source.vala                   |    4 ++
 src/dummy/dummy-game.vala                          |    2 +-
 src/generic/generic-sync-game-uri-adapter.vala     |    9 ++++-
 src/generic/generic-uri-game-factory.vala          |   20 +++++++---
 src/tracker/mime-type-tracker-query.vala           |   14 +++++++
 src/tracker/tracker-game-source.vala               |   12 ++++++
 src/tracker/tracker-query.vala                     |    1 +
 src/ui/application.vala                            |   41 +++++++++++++++++++-
 20 files changed, 219 insertions(+), 21 deletions(-)
---
diff --git a/data/org.gnome.Games.desktop.in b/data/org.gnome.Games.desktop.in
index cfadc7f..c70e76b 100644
--- a/data/org.gnome.Games.desktop.in
+++ b/data/org.gnome.Games.desktop.in
@@ -9,3 +9,4 @@ Terminal=false
 Type=Application
 StartupNotify=true
 Categories=GNOME;GTK;Player;Game;
+MimeType=application/vnd.nintendo.snes.rom;application/x-amiga-disk-format;application/x-atari-2600-rom;application/x-atari-7800-rom;application/x-cue;application/x-dc-rom;application/x-doom-wad;application/x-fds-disk;application/x-gameboy-color-rom;application/x-gameboy-rom;application/x-gamecube-rom;application/x-gamegear-rom;application/x-gba-rom;application/x-genesis-32x-rom;application/x-genesis-rom;application/x-love-game;application/x-mame-rom;application/x-n64-rom;application/x-neo-geo-pocket-rom;application/x-nes-rom;application/x-nintendo-ds-rom;application/x-pc-engine-rom;application/x-playstation-rom;application/x-saturn-rom;application/x-sega-cd-rom;application/x-sega-pico-rom;application/x-sg1000-rom;application/x-sms-rom;application/x-wii-rom;application/x-wii-wad;application/zip;
diff --git a/plugins/desktop/src/desktop-tracker-query.vala b/plugins/desktop/src/desktop-tracker-query.vala
index 174b44e..ccdfebd 100644
--- a/plugins/desktop/src/desktop-tracker-query.vala
+++ b/plugins/desktop/src/desktop-tracker-query.vala
@@ -39,6 +39,12 @@ private class Games.DesktopTrackerQuery : Object, TrackerQuery {
                }
        }
 
+       public Game game_for_uri (string uri) throws Error {
+               throw new GenericUriGameFactoryError.INVALID_URI ("Invalid URI: %s.", uri);
+
+               return new DummyGame ("Dummy desktop game");
+       }
+
        public void process_uri (string uri) throws Error {
                check_uri (uri);
 
diff --git a/plugins/libretro/src/Makefile.am b/plugins/libretro/src/Makefile.am
index a5dbff0..6bbb3f6 100644
--- a/plugins/libretro/src/Makefile.am
+++ b/plugins/libretro/src/Makefile.am
@@ -6,6 +6,7 @@ libgames_libretro_plugin_la_DEPENDENCIES = \
        $(NULL)
 
 libgames_libretro_plugin_la_SOURCES = \
+       libretro-error.vala \
        libretro-game-source.vala \
        libretro-icon.vala \
        libretro-plugin.vala \
diff --git a/plugins/libretro/src/libretro-error.vala b/plugins/libretro/src/libretro-error.vala
new file mode 100644
index 0000000..a106ac7
--- /dev/null
+++ b/plugins/libretro/src/libretro-error.vala
@@ -0,0 +1,6 @@
+// This file is part of GNOME Games. License: GPLv3
+
+errordomain Games.LibretroError {
+       NOT_A_LIBRETRO_DESCRIPTOR,
+       NOT_A_GAME,
+}
diff --git a/plugins/libretro/src/libretro-game-source.vala b/plugins/libretro/src/libretro-game-source.vala
index 8432cd0..3ab9206 100644
--- a/plugins/libretro/src/libretro-game-source.vala
+++ b/plugins/libretro/src/libretro-game-source.vala
@@ -3,6 +3,22 @@
 public class Games.LibretroGameSource : Object, GameSource {
        private Game[] games;
 
+       public Game game_for_uri (string uri) throws Error {
+               if (!uri.has_prefix ("file:") || !uri.has_suffix (".libretro"))
+                       throw new LibretroError.NOT_A_LIBRETRO_DESCRIPTOR ("This isn’t a Libretro core 
descriptor: %s", uri);
+
+               var file = File.new_for_uri (uri);
+               if (!file.query_exists ())
+                       throw new LibretroError.NOT_A_LIBRETRO_DESCRIPTOR ("This isn’t a Libretro core 
descriptor: %s", uri);
+
+               var path = file.get_path ();
+               var core_descriptor = new Retro.CoreDescriptor (path);
+               if (!core_descriptor.get_is_game ())
+                       throw new LibretroError.NOT_A_GAME ("This Libretro core descriptor doesn't isn’t a 
game: %s", uri);
+
+               return game_for_core_descriptor (core_descriptor);
+       }
+
        public async void each_game (GameCallback callback) {
                if (games == null)
                        yield fetch_games ();
diff --git a/plugins/mame/src/mame-game-info.vala b/plugins/mame/src/mame-game-info.vala
index d8744bd..7e2dbb3 100644
--- a/plugins/mame/src/mame-game-info.vala
+++ b/plugins/mame/src/mame-game-info.vala
@@ -7,7 +7,39 @@ private struct Games.MameGameInfo {
        public string id;
        public string name;
 
-       public static async HashTable<string, MameGameInfo?> get_supported_games () throws Error {
+       public static HashTable<string, MameGameInfo?> get_supported_games () throws Error {
+               if (supported_games != null)
+                       return supported_games;
+
+               supported_games = new HashTable<string, MameGameInfo?> (str_hash, str_equal);
+
+               var bytes = resources_lookup_data ("/org/gnome/Games/plugins/mame/supported-games", 
ResourceLookupFlags.NONE);
+               var text = (string) bytes.get_data ();
+
+               if (game_regex == null) {
+                       // Data is of the form: 
GAME[L](YEAR,NAME,PARENT,MACHINE,INPUT,CLASS,INIT,MONITOR,COMPANY,FULLNAME,FLAGS[,LAYOUT])
+                       var simple = " *([^,]+) *";
+                       var quoted = " *\" *(.*?) *\" *";
+                       var pattern = 
@"$simple,$simple,$simple,$simple,$simple,$simple,$simple,$simple,$quoted,$quoted,$simple(?:,$simple)?";
+                       game_regex = new Regex ("^GAMEL?\\(" + pattern + "\\) *$");
+               }
+
+               foreach (var line in text.split ("\n")) {
+                       MatchInfo match_info;
+                       if (!game_regex.match (line, 0, out match_info))
+                               continue;
+
+                       var game_info = MameGameInfo() {
+                               id = cleanup_string (match_info.fetch (2)), // NAME
+                               name = cleanup_string (match_info.fetch (10)) // FULLNAME
+                       };
+                       supported_games[game_info.id] = game_info;
+               }
+
+               return supported_games;
+       }
+
+       public static async HashTable<string, MameGameInfo?> get_supported_games_async () throws Error {
                if (supported_games != null)
                        return supported_games;
 
@@ -23,7 +55,7 @@ private struct Games.MameGameInfo {
                        var pattern = 
@"$simple,$simple,$simple,$simple,$simple,$simple,$simple,$simple,$quoted,$quoted,$simple(?:,$simple)?";
                        game_regex = new Regex ("^GAMEL?\\(" + pattern + "\\) *$");
 
-                       Idle.add (get_supported_games.callback);
+                       Idle.add (get_supported_games_async.callback);
                        yield;
                }
 
@@ -38,7 +70,7 @@ private struct Games.MameGameInfo {
                        };
                        supported_games[game_info.id] = game_info;
 
-                       Idle.add (get_supported_games.callback);
+                       Idle.add (get_supported_games_async.callback);
                        yield;
                }
 
diff --git a/plugins/mame/src/mame-game-uri-adapter.vala b/plugins/mame/src/mame-game-uri-adapter.vala
index beea624..813ee4d 100644
--- a/plugins/mame/src/mame-game-uri-adapter.vala
+++ b/plugins/mame/src/mame-game-uri-adapter.vala
@@ -5,8 +5,8 @@ private class Games.MameGameUriAdapter : GameUriAdapter, Object {
        private const string SPECIFIC_MIME_TYPE = "application/x-mame-rom";
        private const string PLATFORM = "MAME";
 
-       public async Game game_for_uri (string uri) throws Error {
-               var supported_games = yield MameGameInfo.get_supported_games ();
+       public Game game_for_uri (string uri) throws Error {
+               var supported_games = MameGameInfo.get_supported_games ();
 
                var file = File.new_for_uri (uri);
                var game_id = file.get_basename ();
@@ -31,4 +31,34 @@ private class Games.MameGameUriAdapter : GameUriAdapter, Object {
 
                return new GenericGame (title, icon, cover, runner);
        }
+
+       public async Game game_for_uri_async (string uri) throws Error {
+               var supported_games = yield MameGameInfo.get_supported_games_async ();
+
+               var file = File.new_for_uri (uri);
+               var game_id = file.get_basename ();
+               game_id = /\.zip$/.replace (game_id, game_id.length, 0, "");
+
+               if (!supported_games.contains (game_id))
+                       throw new MameError.INVALID_GAME_ID (_("Invalid MAME game id “%s” for “%s”."), 
game_id, uri);
+
+               var uid_string = @"mame-$game_id".down ();
+               var uid = new GenericUid (uid_string);
+
+               var info = supported_games[game_id];
+               var title_string = info.name;
+               title_string = title_string.split ("(")[0];
+               title_string = title_string.strip ();
+               var title = new GenericTitle (title_string);
+
+               var icon = new DummyIcon ();
+               var cover = new LocalCover (uri);
+               var core_source = new RetroCoreSource (PLATFORM, { SEARCHED_MIME_TYPE, SPECIFIC_MIME_TYPE });
+               var runner = new RetroRunner (core_source, uri, uid, title);
+
+               Idle.add (this.game_for_uri_async.callback);
+               yield;
+
+               return new GenericGame (title, icon, cover, runner);
+       }
 }
diff --git a/plugins/playstation/src/playstation-game-factory.vala 
b/plugins/playstation/src/playstation-game-factory.vala
index 0979547..a7c033a 100644
--- a/plugins/playstation/src/playstation-game-factory.vala
+++ b/plugins/playstation/src/playstation-game-factory.vala
@@ -32,6 +32,10 @@ public class Games.PlayStationGameFactory : Object, UriGameFactory {
                return file.query_exists ();
        }
 
+       public Game game_for_uri (string uri) throws Error {
+               return new DummyGame ("Dummy playstation game");
+       }
+
        public void add_uri (string uri) {
                string disc_id;
 
diff --git a/plugins/steam/src/steam-game-source.vala b/plugins/steam/src/steam-game-source.vala
index 09db976..17cb43e 100644
--- a/plugins/steam/src/steam-game-source.vala
+++ b/plugins/steam/src/steam-game-source.vala
@@ -46,6 +46,18 @@ private class Games.SteamGameSource : Object, GameSource {
                }
        }
 
+       public Game game_for_uri (string uri) throws Error {
+               // TODO Check URI is file://
+               var file = File.new_for_uri (uri);
+               // if (!file.query_exists ())
+                       // TODO throw Error
+
+               var path = file.get_path ();
+               string game_id;
+
+               return game_for_appmanifest_path (path, out game_id);
+       }
+
        public async void each_game (GameCallback game_callback) {
                if (games == null)
                        games = new HashTable<string, Game> (str_hash, str_equal);
@@ -76,7 +88,10 @@ private class Games.SteamGameSource : Object, GameSource {
                var name = info.get_name ();
                if (appmanifest_regex.match (name)) {
                        try {
-                               game_for_appmanifest_path (@"$directory/$name");
+                               string game_id;
+                               var game = game_for_appmanifest_path (@"$directory/$name", out game_id);
+                               if (!(game_id in games))
+                                       games[game_id] = game;
 
                                Idle.add (this.game_for_file_info.callback);
                                yield;
@@ -87,7 +102,7 @@ private class Games.SteamGameSource : Object, GameSource {
                }
        }
 
-       private void game_for_appmanifest_path (string appmanifest_path) throws Error {
+       private Game game_for_appmanifest_path (string appmanifest_path, out string id) throws Error {
                var registry = new SteamRegistry (appmanifest_path);
                var game_id = registry.get_data ({"AppState", "appid"});
                /* The game_id sometimes is identified by appID
@@ -98,15 +113,14 @@ private class Games.SteamGameSource : Object, GameSource {
                if (game_id == null)
                        throw new SteamError.NO_APPID (_("Couldn’t get Steam appid from manifest “%s”."), 
appmanifest_path);
 
-               if (game_id in games)
-                       return;
-
                var title = new SteamTitle (registry);
                var icon = new SteamIcon (game_id);
                var cover = new SteamCover (game_id);
                string[] args = { "steam", @"steam://rungameid/" + game_id };
                var runner = new CommandRunner (args, false);
 
-               games[game_id] = new GenericGame (title, icon, cover, runner);
+               id = game_id;
+
+               return new GenericGame (title, icon, cover, runner);
        }
 }
diff --git a/src/core/game-source.vala b/src/core/game-source.vala
index 1156b1d..9213d54 100644
--- a/src/core/game-source.vala
+++ b/src/core/game-source.vala
@@ -1,6 +1,7 @@
 // This file is part of GNOME Games. License: GPL-3.0+.
 
 public interface Games.GameSource : Object {
+       public abstract Game game_for_uri (string uri) throws Error;
        public abstract async void each_game (GameCallback callback);
 }
 
diff --git a/src/core/game-uri-adapter.vala b/src/core/game-uri-adapter.vala
index 65ae670..70a311e 100644
--- a/src/core/game-uri-adapter.vala
+++ b/src/core/game-uri-adapter.vala
@@ -1,5 +1,6 @@
 // This file is part of GNOME Games. License: GPL-3.0+.
 
 public interface Games.GameUriAdapter : Object {
-       public abstract async Game game_for_uri (string uri) throws Error;
+       public abstract Game game_for_uri (string uri) throws Error;
+       public abstract async Game game_for_uri_async (string uri) throws Error;
 }
diff --git a/src/core/uri-game-factory.vala b/src/core/uri-game-factory.vala
index b60b51c..e3f5896 100644
--- a/src/core/uri-game-factory.vala
+++ b/src/core/uri-game-factory.vala
@@ -1,5 +1,6 @@
 public interface Games.UriGameFactory : Object {
        public abstract bool is_uri_valid (string uri);
        public abstract void add_uri (string uri);
+       public abstract Game game_for_uri (string uri) throws Error;
        public abstract async void foreach_game (Games.GameCallback game_callback);
 }
diff --git a/src/dummy/dummy-game-source.vala b/src/dummy/dummy-game-source.vala
index 6fc5573..e651e27 100644
--- a/src/dummy/dummy-game-source.vala
+++ b/src/dummy/dummy-game-source.vala
@@ -1,6 +1,10 @@
 // This file is part of GNOME Games. License: GPL-3.0+.
 
 private class Games.DummyGameSource : Object, GameSource {
+       public Game game_for_uri (string uri) throws Error {
+               return new DummyGame ("Dummy from URI");
+       }
+
        public async void each_game (GameCallback callback) {
                callback (new DummyGame ("Mines"));
                callback (new DummyGame ("Sudoku"));
diff --git a/src/dummy/dummy-game.vala b/src/dummy/dummy-game.vala
index 69c3251..f4373a2 100644
--- a/src/dummy/dummy-game.vala
+++ b/src/dummy/dummy-game.vala
@@ -1,6 +1,6 @@
 // This file is part of GNOME Games. License: GPL-3.0+.
 
-private class Games.DummyGame : Object, Game {
+public class Games.DummyGame : Object, Game {
        private string _name;
        public string name {
                get { return _name; }
diff --git a/src/generic/generic-sync-game-uri-adapter.vala b/src/generic/generic-sync-game-uri-adapter.vala
index 5fcb585..186b038 100644
--- a/src/generic/generic-sync-game-uri-adapter.vala
+++ b/src/generic/generic-sync-game-uri-adapter.vala
@@ -9,7 +9,14 @@ public class Games.GenericSyncGameUriAdapter : GameUriAdapter, Object {
                this.callback = (owned) callback;
        }
 
-       public async Game game_for_uri (string uri) throws Error {
+       public Game game_for_uri (string uri) throws Error {
                return callback (uri);
        }
+
+       public async Game game_for_uri_async (string uri) throws Error {
+               Idle.add (this.game_for_uri_async.callback);
+               yield;
+
+               return game_for_uri (uri);
+       }
 }
diff --git a/src/generic/generic-uri-game-factory.vala b/src/generic/generic-uri-game-factory.vala
index b118248..28b47e2 100644
--- a/src/generic/generic-uri-game-factory.vala
+++ b/src/generic/generic-uri-game-factory.vala
@@ -4,19 +4,16 @@ public class Games.GenericUriGameFactory : Object, UriGameFactory {
        private const uint HANDLED_URIS_PER_CYCLE = 5;
 
        private GameUriAdapter game_uri_adapter;
-       private UriTest? uri_validity_test;
+       private UriTest uri_validity_test;
        private string[] uris;
 
-       public GenericUriGameFactory (GameUriAdapter game_uri_adapter, UriTest? uri_validity_test = null) {
+       public GenericUriGameFactory (GameUriAdapter game_uri_adapter, UriTest uri_validity_test) {
                this.game_uri_adapter = game_uri_adapter;
                this.uri_validity_test = uri_validity_test;
                this.uris = {};
        }
 
        public bool is_uri_valid (string uri) {
-               if (uri_validity_test == null)
-                       return true;
-
                return uri_validity_test.is_uri_valid (uri);
        }
 
@@ -24,6 +21,13 @@ public class Games.GenericUriGameFactory : Object, UriGameFactory {
                uris += uri;
        }
 
+       public Game game_for_uri (string uri) throws Error {
+               if (!is_uri_valid (uri))
+                       throw new GenericUriGameFactoryError.INVALID_URI ("Invalid URI: %s.", uri);
+
+               return game_uri_adapter.game_for_uri (uri);
+       }
+
        public async void foreach_game (GameCallback game_callback) {
                uint handled_uris = 0;
                foreach (var uri in uris) {
@@ -32,7 +36,7 @@ public class Games.GenericUriGameFactory : Object, UriGameFactory {
                                continue;
 
                        try {
-                               Game game = yield game_uri_adapter.game_for_uri (uri);
+                               Game game = yield game_uri_adapter.game_for_uri_async (uri);
                                game_callback (game);
                        }
                        catch (Error e) {
@@ -55,3 +59,7 @@ public class Games.GenericUriGameFactory : Object, UriGameFactory {
                }
        }
 }
+
+public errordomain GenericUriGameFactoryError {
+       INVALID_URI,
+}
diff --git a/src/tracker/mime-type-tracker-query.vala b/src/tracker/mime-type-tracker-query.vala
index c68f282..429c088 100644
--- a/src/tracker/mime-type-tracker-query.vala
+++ b/src/tracker/mime-type-tracker-query.vala
@@ -24,6 +24,20 @@ public class Games.MimeTypeTrackerQuery : Object, TrackerQuery {
                uri_game_factory.add_uri (uri);
        }
 
+       public Game game_for_uri (string uri) throws Error {
+               // FIXME
+//             if (!uri.has_prefix ("file:") || !uri.has_suffix (".libretro"))
+//                     throw new LibretroError.NOT_A_LIBRETRO_DESCRIPTOR ("This isn’t a Libretro core 
descriptor: %s", uri);
+
+//             var file = File.new_for_uri (uri);
+//             if (!file.query_exists ())
+//                     throw new LibretroError.NOT_A_LIBRETRO_DESCRIPTOR ("This isn’t a Libretro core 
descriptor: %s", uri);
+
+//             var path = file.get_path ();
+
+               return uri_game_factory.game_for_uri (uri);
+       }
+
        public async void foreach_game (GameCallback game_callback) {
                yield uri_game_factory.foreach_game (game_callback);
        }
diff --git a/src/tracker/tracker-game-source.vala b/src/tracker/tracker-game-source.vala
index 65681f0..e6ced9c 100644
--- a/src/tracker/tracker-game-source.vala
+++ b/src/tracker/tracker-game-source.vala
@@ -18,6 +18,17 @@ public class Games.TrackerGameSource : Object, GameSource {
                queries += query;
        }
 
+       public Game game_for_uri (string uri) throws Error {
+               foreach (var query in queries)
+                       try {
+                               return query.game_for_uri (uri);
+                       }
+                       catch (Error e) {
+                       }
+
+               throw new TrackerError.NOT_A_GAME ("This isn’t a game: %s", uri);
+       }
+
        public async void each_game (GameCallback game_callback) {
                for (size_t i = 0 ; i < queries.length ; i++)
                        yield each_game_for_query (game_callback, queries[i]);
@@ -76,4 +87,5 @@ public class Games.TrackerGameSource : Object, GameSource {
 
 public errordomain TrackerError {
        FILE_NOT_FOUND,
+       NOT_A_GAME,
 }
diff --git a/src/tracker/tracker-query.vala b/src/tracker/tracker-query.vala
index 69facd0..96ee38a 100644
--- a/src/tracker/tracker-query.vala
+++ b/src/tracker/tracker-query.vala
@@ -4,5 +4,6 @@ public interface Games.TrackerQuery : Object {
        public abstract bool is_cursor_valid (Tracker.Sparql.Cursor cursor);
        public abstract string get_query ();
        public abstract void process_cursor (Tracker.Sparql.Cursor cursor);
+       public abstract Game game_for_uri (string uri) throws Error;
        public abstract async void foreach_game (GameCallback game_callback);
 }
diff --git a/src/ui/application.vala b/src/ui/application.vala
index ea4d6a6..a8556c2 100644
--- a/src/ui/application.vala
+++ b/src/ui/application.vala
@@ -9,7 +9,7 @@ public class Games.Application : Gtk.Application {
 
        internal Application () {
                Object (application_id: "org.gnome.Games",
-                       flags: ApplicationFlags.FLAGS_NONE);
+                       flags: ApplicationFlags.HANDLES_OPEN);
        }
 
        construct {
@@ -106,6 +106,22 @@ public class Games.Application : Gtk.Application {
                return @"$data_dir/medias";
        }
 
+       protected override void open (File[] files, string hint) {
+               if (window == null)
+                       activate ();
+
+               if (files.length == 0)
+                       return;
+
+               var uri = files[0].get_uri ();
+               var game = game_for_uri (uri);
+
+               if (game != null)
+                       window.run_game (game);
+               // else
+                       // TODO Display an error
+       }
+
        protected override void activate () {
                Gtk.Settings.get_default ().gtk_application_prefer_dark_theme = true;
 
@@ -133,6 +149,29 @@ public class Games.Application : Gtk.Application {
                return false;
        }
 
+       private Game? game_for_uri (string uri) {
+               Game? game = null;
+
+               var register = PluginRegister.get_register ();
+               register.foreach_plugin_registrar ((plugin_registrar) => {
+                       if (game != null)
+                               return;
+
+                       try {
+                               var plugin = plugin_registrar.get_plugin ();
+                               var source = plugin.get_game_source ();
+                               if (source == null)
+                                       return;
+
+                               game = source.game_for_uri (uri);
+                       }
+                       catch (Error e) {
+                       }
+               });
+
+               return game;
+       }
+
        internal async void load_game_list () {
                GameSource[] sources = {};
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]