[gnome-music/wip/mschraal/artrework: 22/23] searchview: Use cairo surface instead of pixbuf



commit 9c37772f920353422c6928409803b8c1c5947c84
Author: Marinus Schraal <mschraal gnome org>
Date:   Sat Jan 20 17:04:00 2018 +0100

    searchview: Use cairo surface instead of pixbuf
    
    Surfaces support HiDPI images in Gtk.TreeView.
    
    FIXME: Still a warning being generated

 gnomemusic/albumartcache.py    | 67 ++++++++++++-----------------------------
 gnomemusic/views/baseview.py   | 12 ++------
 gnomemusic/views/searchview.py | 68 ++++++++++++++++++++++++++++--------------
 3 files changed, 66 insertions(+), 81 deletions(-)
---
diff --git a/gnomemusic/albumartcache.py b/gnomemusic/albumartcache.py
index da41b2c..2a1bca0 100644
--- a/gnomemusic/albumartcache.py
+++ b/gnomemusic/albumartcache.py
@@ -206,6 +206,10 @@ class DefaultIcon(GObject.GObject):
 
 class Art(GObject.GObject):
 
+    __gsignals__ = {
+        'finished': (GObject.SignalFlags.RUN_FIRST, None, ())
+    }
+
     _blacklist = {}
     _cache_queue = Queue()
     _embedded_queue = Queue()
@@ -235,7 +239,7 @@ class Art(GObject.GObject):
         self._scale = scale
 
     @log
-    def _start_art_lookup(self):
+    def lookup(self):
         if self._in_blacklist():
             self._no_art_available()
             return
@@ -260,6 +264,8 @@ class Art(GObject.GObject):
         surface = _make_icon_frame(pixbuf, self._size, self._scale)
         self._surface = surface
 
+        self.emit('finished')
+
     def _embedded_art_found(self, klass):
         self._embedded_queue.pop()
 
@@ -297,6 +303,8 @@ class Art(GObject.GObject):
         self._surface = DefaultIcon().get(
             DefaultIcon.Type.music, self._size, self._scale)
 
+        self.emit('finished')
+
     def _add_to_blacklist(self):
         album = utils.get_album_title(self._media)
         artist = utils.get_artist_name(self._media)
@@ -318,6 +326,15 @@ class Art(GObject.GObject):
 
         return False
 
+    @GObject.Property
+    @log
+    def surface(self):
+        if self._surface is None:
+            self._surface = DefaultIcon().get(
+                DefaultIcon.Type.loading, self._size, self._scale)
+
+        return self._surface
+
 
 class ArtImage(Art):
 
@@ -356,54 +373,8 @@ class ArtImage(Art):
 
         self._image.set_from_surface(self._surface)
 
-        self._start_art_lookup()
-
-
-class ArtPixbuf(Art):
-
-    __gsignals__ = {
-        'finished': (GObject.SignalFlags.RUN_FIRST, None, ())
-    }
-
-    def __init__(self, size, media, scale=1):
-        super().__init__(size, media, scale)
-
-        self._iter = None
+        self.lookup()
 
-    def _cache_hit(self, klass, pixbuf):
-        super()._cache_hit(klass, pixbuf)
-
-        self.emit('finished')
-
-    def _no_art_available(self):
-        super()._no_art_available()
-
-        self.emit('finished')
-
-    @GObject.Property
-    @log
-    def pixbuf(self):
-        return Gdk.pixbuf_get_from_surface(
-            self._surface, 0, 0, self._surface.get_width(),
-            self._surface.get_height())
-
-    @pixbuf.setter
-    @log
-    def pixbuf(self, pixbuf):
-        self._surface = DefaultIcon().get(
-            DefaultIcon.Type.loading, self._size, self._scale)
-
-        self._start_art_lookup()
-
-    @GObject.Property(type=Gtk.TreeIter)
-    @log
-    def iter(self):
-        return self._iter
-
-    @iter.setter
-    @log
-    def iter(self, iter_):
-        self._iter = iter_
 
 # 1. libmediaart
 # 2  embedded -> libmediaart
diff --git a/gnomemusic/views/baseview.py b/gnomemusic/views/baseview.py
index 83cbcea..7b2ac36 100644
--- a/gnomemusic/views/baseview.py
+++ b/gnomemusic/views/baseview.py
@@ -26,7 +26,7 @@ from gettext import gettext as _, ngettext
 from gi.repository import Gd, Gdk, GdkPixbuf, GObject, Gtk
 
 from gnomemusic import log
-from gnomemusic.albumartcache import Art, ArtPixbuf
+from gnomemusic.albumartcache import Art
 from gnomemusic.grilo import grilo
 from gnomemusic.widgets.starhandlerwidget import StarHandlerWidget
 import gnomemusic.utils as utils
@@ -227,24 +227,16 @@ class BaseView(Gtk.Stack):
 
         itr = self.model.append(None)
 
-        pixbuf = GdkPixbuf.Pixbuf()
-        art = ArtPixbuf(Art.Size.MEDIUM, item)
-        art.pixbuf = pixbuf
-
-        self.model[itr][0, 1, 2, 3, 4, 5, 7, 9] = [
+        self.model[itr][0, 1, 2, 3, 5, 7, 9] = [
             str(item.get_id()),
             '',
             title,
             artist,
-            art,
             item,
             0,
             False
         ]
 
-        art.iter = itr
-        art.connect('finished', self._retrieval_finished)
-
     @log
     def _on_lookup_ready(self, surface, itr):
         if surface:
diff --git a/gnomemusic/views/searchview.py b/gnomemusic/views/searchview.py
index b46b6f1..7f04d86 100644
--- a/gnomemusic/views/searchview.py
+++ b/gnomemusic/views/searchview.py
@@ -25,7 +25,7 @@
 from gettext import gettext as _
 from gi.repository import Gd, GdkPixbuf, GObject, Grl, Gtk, Pango
 
-from gnomemusic.albumartcache import Art, ArtPixbuf
+from gnomemusic.albumartcache import Art
 from gnomemusic.grilo import grilo
 from gnomemusic import log
 from gnomemusic.player import DiscoveryStatus
@@ -188,8 +188,11 @@ class SearchView(BaseView):
         self._add_item(source, None, item, 0, [self.model, 'song'])
 
     @log
-    def _retrieval_finished(self, klass):
-        self.model[klass.iter][4] = klass.pixbuf
+    def _retrieval_finished(self, klass, model, _iter):
+        if not model[_iter][13]:
+            return
+
+        model[_iter][13] = klass.surface
 
     @log
     def _add_item(self, source, param, item, remaining=0, data=None):
@@ -235,18 +238,11 @@ class SearchView(BaseView):
         except:
             pass
 
-        # FIXME: HiDPI icon lookups return a surface that can't be
-        # scaled by GdkPixbuf, so it results in a * scale factor sized
-        # icon for the search view.
         _iter = None
-        scale = self._view.get_scale_factor()
-        pixbuf = GdkPixbuf.Pixbuf()
-        art = ArtPixbuf(Art.Size.SMALL, item, scale)
-        art.pixbuf = pixbuf
         if category == 'album':
             _iter = self.model.insert_with_values(
-                self._head_iters[group], -1, [0, 2, 3, 4, 5, 9, 11],
-                [str(item.get_id()), title, artist, art.pixbuf, item, 2,
+                self._head_iters[group], -1, [0, 2, 3, 5, 9, 11],
+                [str(item.get_id()), title, artist, item, 2,
                  category])
         elif category == 'song':
             # FIXME: source specific hack
@@ -255,14 +251,14 @@ class SearchView(BaseView):
             else:
                 fav = item.get_favourite()
             _iter = self.model.insert_with_values(
-                self._head_iters[group], -1, [0, 2, 3, 4, 5, 9, 11],
-                [str(item.get_id()), title, artist, art.pixbuf, item, fav,
+                self._head_iters[group], -1, [0, 2, 3, 5, 9, 11],
+                [str(item.get_id()), title, artist, item, fav,
                  category])
         else:
             if not artist.casefold() in self._artists:
                 _iter = self.model.insert_with_values(
-                    self._head_iters[group], -1, [0, 2, 4, 5, 9, 11],
-                    [str(item.get_id()), artist, art.pixbuf, item, 2,
+                    self._head_iters[group], -1, [0, 2, 5, 9, 11],
+                    [str(item.get_id()), artist, item, 2,
                      category])
                 self._artists[artist.casefold()] = {
                     'iter': _iter,
@@ -272,8 +268,13 @@ class SearchView(BaseView):
 
         # FIXME: Figure out why iter can be None here, seems illogical.
         if _iter is not None:
-            art.iter = _iter
-            art.connect('finished', self._retrieval_finished)
+            scale = self._view.get_scale_factor()
+            art = Art(Art.Size.SMALL, item, scale)
+            self.model[_iter][13] = art.surface
+            art.connect(
+                'finished', self._retrieval_finished, self.model, _iter)
+            art.lookup()
+
 
         if self.model.iter_n_children(self._head_iters[group]) == 1:
             path = self.model.get_path(self._head_iters[group])
@@ -294,13 +295,31 @@ class SearchView(BaseView):
             title_renderer, self._on_list_widget_title_render, None)
         cols[0].add_attribute(title_renderer, 'text', 2)
 
-        self._star_handler.add_star_renderers(list_widget, cols[0])
+        # Add our own surface renderer, instead of the one provided by
+        # Gd. This avoids us having to set the model to a cairo.Surface
+        # which is currently not a working solution in pygobject.
+        # https://gitlab.gnome.org/GNOME/pygobject/issues/155
+        pixbuf_renderer = Gtk.CellRendererPixbuf(
+            xalign=0.5, yalign=0.5, xpad=12, ypad=2)
+        list_widget.add_renderer(
+            pixbuf_renderer, self._on_list_widget_pixbuf_renderer, None)
+        cols[0].add_attribute(pixbuf_renderer, 'surface', 13)
 
+        self._star_handler.add_star_renderers(list_widget, cols[0])
         cells = cols[0].get_cells()
         cols[0].reorder(cells[0], -1)
+        cols[0].reorder(cells[4], 1)
         cols[0].set_cell_data_func(
             cells[0], self._on_list_widget_selection_render, None)
 
+    @log
+    def _on_list_widget_pixbuf_renderer(self, col, cell, model, _iter, data):
+        if not model[_iter][13]:
+            return
+
+        cell.set_property("surface", model[_iter][13])
+
+    @log
     def _on_list_widget_selection_render(self, col, cell, model, _iter, data):
         if (self._view.get_selection_mode()
                 and model.iter_parent(_iter) is not None):
@@ -308,11 +327,13 @@ class SearchView(BaseView):
         else:
             cell.set_visible(False)
 
+    @log
     def _on_list_widget_title_render(self, col, cell, model, _iter, data):
         cells = col.get_cells()
-        cells[0].set_visible(model.iter_parent(_iter) is not None)
+        cells[0].set_visible(False)
         cells[1].set_visible(model.iter_parent(_iter) is not None)
-        cells[2].set_visible(model.iter_parent(_iter) is None)
+        cells[2].set_visible(model.iter_parent(_iter) is not None)
+        cells[3].set_visible(model.iter_parent(_iter) is None)
 
     @log
     def populate(self):
@@ -455,7 +476,7 @@ class SearchView(BaseView):
             GObject.TYPE_STRING,
             GObject.TYPE_STRING,    # item title or header text
             GObject.TYPE_STRING,    # artist for albums and songs
-            GdkPixbuf.Pixbuf,       # album art
+            GdkPixbuf.Pixbuf,       # Gd placeholder album art
             GObject.TYPE_OBJECT,    # item
             GObject.TYPE_BOOLEAN,
             GObject.TYPE_INT,
@@ -463,7 +484,8 @@ class SearchView(BaseView):
             GObject.TYPE_INT,
             GObject.TYPE_BOOLEAN,
             GObject.TYPE_STRING,    # type
-            GObject.TYPE_INT
+            GObject.TYPE_INT,
+            object                  # album art surface
         )
 
         self._filter_model = self.model.filter_new(None)


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