[gnome-music/wip/mschraal/coverart: 4/4] Introduce HiDPI support
- From: Marinus Schraal <mschraal src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-music/wip/mschraal/coverart: 4/4] Introduce HiDPI support
- Date: Tue, 27 Sep 2016 22:08:30 +0000 (UTC)
commit 94d67a1e8a2e42c4835745dfd7f34480d36a0086
Author: Marinus Schraal <mschraal src gnome org>
Date: Tue Sep 27 14:47:43 2016 +0200
Introduce HiDPI support
Use cairo surfaces to support HiDPI artwork.
Search stil requires us to convert back to GdkPixbuf at the end of the
line, because of libgd limits.
gnomemusic/albumartcache.py | 48 +++++++++++++++----------
gnomemusic/player.py | 11 +++---
gnomemusic/view.py | 81 +++++++++++++++++++++++++++++++------------
gnomemusic/widgets.py | 31 ++++++++++------
4 files changed, 114 insertions(+), 57 deletions(-)
---
diff --git a/gnomemusic/albumartcache.py b/gnomemusic/albumartcache.py
index 385f86f..8f75262 100644
--- a/gnomemusic/albumartcache.py
+++ b/gnomemusic/albumartcache.py
@@ -47,13 +47,13 @@ logger = logging.getLogger(__name__)
@log
-def _make_icon_frame(pixbuf):
- border = 3
+def _make_icon_frame(pixbuf, art_size=None, scale=1):
+ border = 3 * scale
degrees = pi / 180
- radius = 3
+ radius = 3 * scale
- w = pixbuf.get_width()
- h = pixbuf.get_height()
+ w = art_size.width * scale
+ h = art_size.height * scale
new_pixbuf = pixbuf.scale_simple(w - border * 2,
h - border * 2,
@@ -83,7 +83,11 @@ def _make_icon_frame(pixbuf):
border_pixbuf = Gdk.pixbuf_get_from_surface(surface, 0, 0, w, h)
- return border_pixbuf
+ surface = Gdk.cairo_surface_create_from_pixbuf(border_pixbuf,
+ scale,
+ None)
+
+ return surface
class ArtSize(Enum):
@@ -108,14 +112,20 @@ class DefaultIcon(GObject.GObject):
music = 'folder-music-symbolic'
_cache = {}
+ scale = 1
def __repr__(self):
return '<DefaultIcon>'
@log
- def _make_default_icon(self, icon_type, art_size):
- width = art_size.width
- height = art_size.height
+ def __init__(self, scale=1):
+ GObject.GObject.__init__(self)
+ self.scale = scale
+
+ @log
+ def _make_default_icon(self, icon_type, art_size=None):
+ width = art_size.width * self.scale
+ height = art_size.height * self.scale
icon = Gtk.IconTheme.get_default().load_icon(icon_type.value,
max(width, height) / 4,
@@ -138,9 +148,9 @@ class DefaultIcon(GObject.GObject):
icon.get_height() * 3 / 2,
1, 1, GdkPixbuf.InterpType.HYPER, 0x33)
- final_icon = _make_icon_frame(result)
+ icon_surface = _make_icon_frame(result, art_size, self.scale)
- return final_icon
+ return icon_surface
@log
def get(self, icon_type, art_size):
@@ -170,13 +180,15 @@ class AlbumArtCache(GObject.GObject):
"""
_instance = None
blacklist = {}
+ scale = 1
def __repr__(self):
return '<AlbumArtCache>'
@log
- def __init__(self):
+ def __init__(self, scale=1):
GObject.GObject.__init__(self)
+ self.scale = scale
self.cache_dir = os.path.join(GLib.get_user_cache_dir(), 'media-art')
if not os.path.exists(self.cache_dir):
@@ -191,8 +203,8 @@ class AlbumArtCache(GObject.GObject):
"""Find art for the given item
:param item: Grilo media item
- :param int width: Width of the icon to return
- :param int height: Height of the icon to return
+ :param ArtSize art_size: Size of the icon
+ :param int scale: Scale factor (hidpi)
:param callback: Callback function when retrieved
:param itr: Iter to return with callback
"""
@@ -229,12 +241,10 @@ class AlbumArtCache(GObject.GObject):
def do_callback(pixbuf):
if not pixbuf:
- pixbuf = DefaultIcon().get(DefaultIcon.Type.music, art_size)
+ pixbuf = DefaultIcon(self.scale).get(DefaultIcon.Type.music,
+ art_size)
else:
- pixbuf = pixbuf.scale_simple(art_size.width,
- art_size.height,
- GdkPixbuf.InterpType.HYPER)
- pixbuf = _make_icon_frame(pixbuf)
+ pixbuf = _make_icon_frame(pixbuf, art_size, self.scale)
GLib.idle_add(callback, pixbuf, None, itr)
return
diff --git a/gnomemusic/player.py b/gnomemusic/player.py
index 66719d1..cbbb76f 100644
--- a/gnomemusic/player.py
+++ b/gnomemusic/player.py
@@ -108,9 +108,10 @@ class Player(GObject.GObject):
self.currentTrack = None
self.currentTrackUri = None
self._lastState = Gst.State.PAUSED
- self.cache = AlbumArtCache()
- self._no_artwork_icon = DefaultIcon().get(DefaultIcon.Type.music,
- ArtSize.xsmall)
+ scale = parent_window.get_scale_factor()
+ self.cache = AlbumArtCache(scale)
+ self._no_artwork_icon = DefaultIcon(scale).get(DefaultIcon.Type.music,
+ ArtSize.xsmall)
self._missingPluginMessages = []
Gst.init(None)
@@ -605,7 +606,7 @@ class Player(GObject.GObject):
except:
self._currentAlbum = album
- self.coverImg.set_from_pixbuf(self._no_artwork_icon)
+ self.coverImg.set_from_surface(self._no_artwork_icon)
self.cache.lookup(
media, ArtSize.xsmall, self._on_cache_lookup, None)
@@ -662,7 +663,7 @@ class Player(GObject.GObject):
@log
def _on_cache_lookup(self, pixbuf, path, data=None):
if pixbuf is not None:
- self.coverImg.set_from_pixbuf(pixbuf)
+ self.coverImg.set_from_surface(pixbuf)
self.emit('thumbnail-updated', path)
@log
diff --git a/gnomemusic/view.py b/gnomemusic/view.py
index 742d51d..91e87d4 100644
--- a/gnomemusic/view.py
+++ b/gnomemusic/view.py
@@ -30,10 +30,10 @@
# code, but you are not obligated to do so. If you do not wish to do so,
# delete this exception statement from your version.
-
from gi.repository import Gtk
from gi.repository import GObject
from gi.repository import Gd
+from gi.repository import Gdk
from gi.repository import Gio
from gi.repository import Grl
from gi.repository import Pango
@@ -127,9 +127,13 @@ class ViewContainer(Gtk.Stack):
self.show_all()
self.view.hide()
self._items = []
- self.cache = AlbumArtCache()
- self._loading_icon = DefaultIcon().get(DefaultIcon.Type.loading,
- ArtSize.medium)
+
+ scale = self.get_scale_factor()
+ self.cache = AlbumArtCache(scale)
+ self._loading_icon_surface = DefaultIcon(scale).get(
+ DefaultIcon.Type.loading,
+ ArtSize.medium)
+
self._init = False
grilo.connect('ready', self._on_grilo_ready)
@@ -194,7 +198,6 @@ class ViewContainer(Gtk.Stack):
@log
def _on_view_selection_changed(self, widget):
-
if not self.selection_mode:
return
@@ -241,18 +244,33 @@ class ViewContainer(Gtk.Stack):
title = utils.get_media_title(item)
_iter = self.model.append(None)
- self.model.set(_iter,
- [0, 1, 2, 3, 4, 5, 7, 9],
- [str(item.get_id()), '', title,
- artist, self._loading_icon, item,
- 0, False])
+
+ loading_icon = Gdk.pixbuf_get_from_surface(
+ self._loadin_icon_surface, 0, 0,
+ self._loading_icon_surface.get_width(),
+ self._loading_icon_surface.get_height())
+
+ self.model[_iter][0, 1, 2, 3, 4, 5, 7, 9] = [
+ str(item.get_id()),
+ '',
+ title,
+ artist,
+ loading_icon,
+ item,
+ 0,
+ False
+ ]
self.cache.lookup(item, self._iconWidth, self._iconHeight,
self._on_lookup_ready, _iter)
@log
- def _on_lookup_ready(self, icon, path, _iter):
- if icon:
- self.model.set_value(_iter, 4, icon)
+ def _on_lookup_ready(self, surface, path, _iter):
+ if surface:
+ pixbuf = Gdk.pixbuf_get_from_surface(surface, 0, 0,
+ surface.get_width(),
+ surface.get_height())
+
+ self.model[_iter][4] = pixbuf
@log
def _add_list_renderers(self):
@@ -494,13 +512,15 @@ class Albums(ViewContainer):
child.title.set_label(title)
child.subtitle.set_label(artist)
- child.image.set_from_pixbuf(self._loading_icon)
+
+ child.image.set_from_surface(self._loading_icon_surface)
# In the case of off-sized icons (eg. provided in the soundfile)
# keep the size request equal to all other icons to get proper
# alignment with GtkFlowBox.
child.image.set_property("width-request", ArtSize.medium.width)
child.image.set_property("height-request", ArtSize.medium.height)
+
child.events.connect('button-release-event',
self._on_album_event_triggered,
child)
@@ -530,7 +550,7 @@ class Albums(ViewContainer):
child.check.set_active(True)
def _on_lookup_ready(self, icon, path, child):
- child.image.set_from_pixbuf(icon)
+ child.image.set_from_surface(icon)
@log
def _on_child_toggled(self, check, pspec, child):
@@ -1527,10 +1547,14 @@ class Search(ViewContainer):
self._items = {}
self.isStarred = None
self.iter_to_clean = None
- self._loading_icon = DefaultIcon().get(DefaultIcon.Type.loading,
- ArtSize.small)
- self._no_albumart_icon = DefaultIcon().get(DefaultIcon.Type.music,
- ArtSize.small)
+
+ scale = self.get_scale_factor()
+ self._loading_icon_surface = DefaultIcon(scale).get(
+ DefaultIcon.Type.loading,
+ ArtSize.small)
+ self._no_albumart_surface = DefaultIcon(scale).get(
+ DefaultIcon.Type.music,
+ ArtSize.small)
self._add_list_renderers()
self.player = player
self.head_iters = [None, None, None, None]
@@ -1691,27 +1715,40 @@ class Search(ViewContainer):
except:
pass
+ loading_icon = Gdk.pixbuf_get_from_surface(
+ self._loading_icon_surface,
+ 0, 0,
+ self._loading_icon_surface.get_width(),
+ self._loading_icon_surface.get_height())
+ no_albumart_icon = Gdk.pixbuf_get_from_surface(
+ self._no_albumart_surface,
+ 0, 0,
+ self._no_albumart_surface.get_width(),
+ self._no_albumart_surface.get_height())
+
_iter = None
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,
- self._loading_icon, item, 2, category])
+ loading_icon, item, 2, category])
self.cache.lookup(item, ArtSize.small, self._on_lookup_ready, _iter)
elif category == 'song':
_iter = self.model.insert_with_values(
self.head_iters[group], -1,
[0, 2, 3, 4, 5, 9, 11],
[str(item.get_id()), title, artist,
- self._no_albumart_icon, item, 2 if source.get_id() != 'grl-tracker-source' else
bool(item.get_lyrics()), category])
+ no_albumart_icon, item,
+ 2 if source.get_id() != 'grl-tracker-source' \
+ else bool(item.get_lyrics()), 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,
- self._loading_icon, item, 2, category])
+ loading_icon, item, 2, category])
self.cache.lookup(item, ArtSize.small, self._on_lookup_ready,
_iter)
self._artists[artist.casefold()] = {'iter': _iter, 'albums': []}
diff --git a/gnomemusic/widgets.py b/gnomemusic/widgets.py
index bd1bf6a..124c391 100644
--- a/gnomemusic/widgets.py
+++ b/gnomemusic/widgets.py
@@ -123,8 +123,6 @@ class AlbumWidget(Gtk.EventBox):
"""
_duration = 0
- _loading_icon = DefaultIcon().get(DefaultIcon.Type.loading, ArtSize.small)
- _no_artwork_icon = DefaultIcon().get(DefaultIcon.Type.music, ArtSize.small)
def __repr__(self):
return '<AlbumWidget>'
@@ -137,7 +135,14 @@ class AlbumWidget(Gtk.EventBox):
:param parent_view: The view this widget is part of
"""
Gtk.EventBox.__init__(self)
- self._cache = AlbumArtCache()
+
+ scale = self.get_scale_factor()
+ self._cache = AlbumArtCache(scale)
+ self._loading_icon = DefaultIcon(scale).get(DefaultIcon.Type.loading,
+ ArtSize.small)
+ self._no_artwork_icon = DefaultIcon(scale).get(DefaultIcon.Type.music,
+ ArtSize.small)
+
self._player = player
self._iter_to_clean = None
@@ -290,7 +295,7 @@ class AlbumWidget(Gtk.EventBox):
self.selection_toolbar = selection_toolbar
self._header_bar = header_bar
self._album = album
- self._ui.get_object('cover').set_from_pixbuf(self._loading_icon)
+ self._ui.get_object('cover').set_from_surface(self._loading_icon)
self._cache.lookup(item, ArtSize.large, self._on_look_up, None)
self._duration = 0
self._create_model()
@@ -390,7 +395,7 @@ class AlbumWidget(Gtk.EventBox):
_iter = self._iter_to_clean
if not pixbuf:
pixbuf = self._no_artwork_icon
- self._ui.get_object('cover').set_from_pixbuf(pixbuf)
+ self._ui.get_object('cover').set_from_surface(pixbuf)
if _iter:
self.model[_iter][4] = pixbuf
@@ -626,16 +631,20 @@ class ArtistAlbumWidget(Gtk.Box):
'tracks-loaded': (GObject.SignalFlags.RUN_FIRST, None, ()),
}
- _loading_icon = DefaultIcon().get(DefaultIcon.Type.loading, ArtSize.large)
- _no_artwork_icon = DefaultIcon().get(DefaultIcon.Type.music, ArtSize.large)
-
def __repr__(self):
return '<ArtistAlbumWidget>'
@log
def __init__(self, artist, album, player, model, header_bar, selectionModeAllowed):
Gtk.Box.__init__(self, orientation=Gtk.Orientation.HORIZONTAL)
- self._cache = AlbumArtCache()
+
+ scale = self.get_scale_factor()
+ self._cache = AlbumArtCache(scale)
+ self._loading_icon = DefaultIcon(scale).get(DefaultIcon.Type.loading,
+ ArtSize.large)
+ self._no_artwork_icon = DefaultIcon(scale).get(DefaultIcon.Type.music,
+ ArtSize.large)
+
self.player = player
self.album = album
self.artist = artist
@@ -651,7 +660,7 @@ class ArtistAlbumWidget(Gtk.Box):
GLib.idle_add(self._update_album_art)
self.cover = self.ui.get_object('cover')
- self.cover.set_from_pixbuf(self._loading_icon)
+ self.cover.set_from_surface(self._loading_icon)
self.songsGrid = self.ui.get_object('grid1')
self.ui.get_object('title').set_label(album.get_title())
if album.get_creation_date():
@@ -722,7 +731,7 @@ class ArtistAlbumWidget(Gtk.Box):
def _get_album_cover(self, pixbuf, path, data=None):
if not pixbuf:
pixbuf = self._no_artwork_icon
- self.cover.set_from_pixbuf(pixbuf)
+ self.cover.set_from_surface(pixbuf)
@log
def track_selected(self, widget, event):
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]