[gnome-games/wip/exalm/covers: 3/5] core: Add CoverLoader



commit d362bb733ccf90d61aabd180aff4e13da47af00e
Author: Alexander Mikhaylenko <alexm gnome org>
Date:   Sun Nov 17 16:37:47 2019 +0500

    core: Add CoverLoader
    
    An object that loads covers in a background thread and returns them to the
    asker. This will be used to make cover loading not block the UI.

 src/core/cover-loader.vala | 108 +++++++++++++++++++++++++++++++++++++++++++++
 src/meson.build            |   1 +
 2 files changed, 109 insertions(+)
---
diff --git a/src/core/cover-loader.vala b/src/core/cover-loader.vala
new file mode 100644
index 00000000..e79f27ca
--- /dev/null
+++ b/src/core/cover-loader.vala
@@ -0,0 +1,108 @@
+// This file is part of GNOME Games. License: GPL-3.0+.
+
+public class Games.CoverLoader : Object {
+       public delegate void CoverReadyCallback (int size, Gdk.Pixbuf? pixbuf);
+
+       private struct CoverRequest {
+               Game game;
+               int size;
+               unowned CoverReadyCallback cb;
+       }
+
+       private AsyncQueue<CoverRequest?> request_queue;
+       private Thread thread;
+
+       construct {
+               request_queue = new AsyncQueue<CoverRequest?> ();
+               thread = new Thread<void> (null, run_loader_thread);
+       }
+
+       private void run_callback (CoverRequest request, int size, Gdk.Pixbuf? pixbuf) {
+               Idle.add (() => {
+                       request.cb (size, pixbuf);
+                       return Source.REMOVE;
+               });
+       }
+
+       private void run_loader_thread () {
+               while (true) {
+                       var request = request_queue.pop ();
+                       var game = request.game;
+                       var size = request.size;
+
+                       var pixbuf = load_cover_cache_from_disk (game, size);
+                       if (pixbuf != null) {
+                               run_callback (request, size, pixbuf);
+                               continue;
+                       }
+
+                       var g_icon = game.get_cover ().get_cover ();
+                       if (g_icon == null) {
+                               run_callback (request, size, null);
+                               continue;
+                       }
+
+                       var theme = Gtk.IconTheme.get_default ();
+                       var lookup_flags = Gtk.IconLookupFlags.FORCE_SIZE | Gtk.IconLookupFlags.FORCE_REGULAR;
+                       var icon_info = theme.lookup_by_gicon (g_icon, (int) size, lookup_flags);
+
+                       try {
+                               pixbuf = icon_info.load_icon ();
+                               save_cover_cache_to_disk (game, pixbuf, size);
+                       }
+                       catch (Error e) {
+                               run_callback (request, size, null);
+                               continue;
+                       }
+
+                       run_callback (request, size, pixbuf);
+               }
+       }
+
+       private string get_cover_cache_path (Game game, int size) throws Error {
+               var dir = Application.get_covers_cache_dir (size);
+
+               var uid = game.get_uid ().get_uid ();
+
+               return @"$dir/$uid.png";
+       }
+
+       private Gdk.Pixbuf? load_cover_cache_from_disk (Game game, int size) {
+               string cover_cache_path;
+               try {
+                       cover_cache_path = get_cover_cache_path (game, size);
+               }
+               catch (Error e) {
+                       critical (e.message);
+                       return null;
+               }
+
+               try {
+                       return new Gdk.Pixbuf.from_file (cover_cache_path);
+               }
+               catch (Error e) {
+                       return null;
+               }
+       }
+
+       private void save_cover_cache_to_disk (Game game, Gdk.Pixbuf pixbuf, int size) {
+               Application.try_make_dir (Application.get_covers_cache_dir (size));
+               var now = new GLib.DateTime.now_local ();
+               var creation_time = now.to_string ();
+
+               try {
+                       var cover_cache_path = get_cover_cache_path (game, size);
+                       pixbuf.save (cover_cache_path, "png",
+                                   "tEXt::Software", "GNOME Games",
+                                   "tEXt::Creation Time", creation_time.to_string (),
+                                   null);
+               }
+               catch (Error e) {
+                       critical (e.message);
+               }
+       }
+
+       public void fetch_cover (Game game, int size, CoverReadyCallback cb) {
+               request_queue.push ({ game, size, cb });
+       }
+}
diff --git a/src/meson.build b/src/meson.build
index 4935f3f3..a0444563 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -15,6 +15,7 @@ vala_sources = [
   'command/command-runner.vala',
 
   'core/cover.vala',
+  'core/cover-loader.vala',
   'core/game.vala',
   'core/game-callback.vala',
   'core/game-collection.vala',


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