[gnome-music/freeze-break: 45/107] Add support for notifications
- From: Arnel A. Borja <arnelborja src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-music/freeze-break: 45/107] Add support for notifications
- Date: Wed, 11 Sep 2013 13:18:29 +0000 (UTC)
commit 1d1dbf4997fa95631e65748b5184557e89e82311
Author: Giovanni Campagna <gcampagna src gnome org>
Date: Sun Sep 1 16:18:38 2013 +0200
Add support for notifications
Add a NotificationManager object that watches the Player and
keeps a resident notification to control the application.
https://bugzilla.gnome.org/show_bug.cgi?id=702377
gnomemusic/Makefile.am | 1 +
gnomemusic/application.py | 7 ++-
gnomemusic/notification.py | 148 ++++++++++++++++++++++++++++++++++++++++++++
gnomemusic/player.py | 6 ++-
4 files changed, 160 insertions(+), 2 deletions(-)
---
diff --git a/gnomemusic/Makefile.am b/gnomemusic/Makefile.am
index 5fd6c97..b2b8c99 100644
--- a/gnomemusic/Makefile.am
+++ b/gnomemusic/Makefile.am
@@ -6,6 +6,7 @@ app_PYTHON = \
__init__.py \
player.py \
mpris.py \
+ notification.py \
toolbar.py \
view.py \
grilo.py \
diff --git a/gnomemusic/application.py b/gnomemusic/application.py
index c201368..e34c8d8 100644
--- a/gnomemusic/application.py
+++ b/gnomemusic/application.py
@@ -31,10 +31,11 @@
# delete this exception statement from your version.
-from gi.repository import Gtk, Gio, GLib, Gdk
+from gi.repository import Gtk, Gio, GLib, Gdk, Notify
from gettext import gettext as _
from gnomemusic.window import Window
from gnomemusic.mpris import MediaPlayer2Service
+from gnomemusic.notification import NotificationManager
class Application(Gtk.Application):
@@ -98,6 +99,8 @@ class Application(Gtk.Application):
def do_startup(self):
Gtk.Application.do_startup(self)
+ Notify.init(_("Music"))
+
self.build_app_menu()
def quit(self, action, param):
@@ -107,4 +110,6 @@ class Application(Gtk.Application):
if not self._window:
self._window = Window(self)
self.service = MediaPlayer2Service(self)
+ self._notifications = NotificationManager(self._window.player)
+
self._window.present()
diff --git a/gnomemusic/notification.py b/gnomemusic/notification.py
new file mode 100644
index 0000000..d4c4ea5
--- /dev/null
+++ b/gnomemusic/notification.py
@@ -0,0 +1,148 @@
+# Copyright (c) 2013 Giovanni Campagna <scampa giovanni gmail com>
+#
+# GNOME Music is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# GNOME Music is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with GNOME Music; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# The GNOME Music authors hereby grant permission for non-GPL compatible
+# GStreamer plugins to be used and distributed together with GStreamer
+# and GNOME Music. This permission is above and beyond the permissions
+# granted by the GPL license by which GNOME Music is covered. If you
+# modify this code, you may extend this exception to your version of the
+# 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 GLib, Grl, Notify
+
+from gnomemusic.albumArtCache import AlbumArtCache
+
+from gettext import gettext as _
+
+IMAGE_SIZE = 125
+
+
+class NotificationManager:
+ def __init__(self, player):
+ self._player = player
+
+ self._notification = Notify.Notification()
+
+ self._notification.set_category('x-gnome.music')
+ self._notification.set_hint('action-icons', GLib.Variant('b', True))
+ self._notification.set_hint('resident', GLib.Variant('b', True))
+ self._notification.set_hint('desktop-entry', GLib.Variant('s', 'gnome-music'))
+
+ self._isPlaying = False
+
+ self._albumArtCache = AlbumArtCache.get_default()
+ self._symbolicIcon = self._albumArtCache.make_default_icon(IMAGE_SIZE, IMAGE_SIZE)
+
+ self._player.connect('playing-changed', self._on_playing_changed)
+ self._player.connect('current-changed', self._update_track)
+
+ def _on_playing_changed(self, player):
+ # this function might be called from one of the action handlers
+ # from libnotify, and we can't call _set_actions() from there
+ # (we would free the closure we're currently in and corrupt
+ # the stack)
+ GLib.idle_add(self._update_playing)
+
+ def _update_playing(self):
+ isPlaying = self._player.playing
+
+ if self._isPlaying != isPlaying:
+ self._isPlaying = isPlaying
+ self._set_actions(isPlaying)
+ self._update_track(self._player)
+
+ def _update_track(self, player):
+ model = self._player.playlist
+ trackIter = self._player.currentTrack
+
+ if trackIter is None:
+ self._notification.update(_("Not playing"), None, 'gnome-music')
+ self._notification.set_hint('image-data', None)
+ self._notification.show()
+ else:
+ trackField = self._player.playlistField
+ item = model.get_value(trackIter, trackField)
+ artist = item.get_author()
+ if artist is None:
+ artist = item.get_string(Grl.METADATA_KEY_ARTIST)
+ album = item.get_string(Grl.METADATA_KEY_ALBUM)
+
+ self._notification.update(item.get_title(),
+ # TRANSLATORS: by refers to the artist, from to the album
+ _("by %s, from %s") % ('<b>' + artist + '</b>',
+ '<i>' + album + '</i>'),
+ 'gnome-music')
+
+ # Try to pass an image path instead of a serialized pixbuf if possible
+ if item.get_thumbnail():
+ self._notification.set_hint('image-path', GLib.Variant('s', item.get_thumbnail()))
+ self._notification.set_hint('image-data', None)
+ self._notification.show()
+ return
+
+ self._albumArtCache.lookup(item, IMAGE_SIZE, IMAGE_SIZE, self._album_art_loaded)
+
+ def _album_art_loaded(self, image, path, data):
+ if path:
+ self._notification.set_hint('image-path', GLib.Variant('s', path))
+ self._notification.set_hint('image-data', None)
+ else:
+ self._notification.set_hint('image-path', None)
+
+ if not image:
+ image = self._symbolicIcon
+
+ width = image.get_width()
+ height = image.get_height()
+ rowStride = image.get_rowstride()
+ hasAlpha = image.get_has_alpha()
+ bitsPerSample = image.get_bits_per_sample()
+ nChannels = image.get_n_channels()
+ data = image.get_pixels()
+
+ serialized = GLib.Variant('(iiibiiay)',
+ [width, height, rowStride, hasAlpha,
+ bitsPerSample, nChannels, data])
+ self._notification.set_hint('image-data', serialized)
+
+ self._notification.show()
+
+ def _set_actions(self, playing):
+ self._notification.clear_actions()
+
+ self._notification.add_action('media-skip-backward', _("Previous"),
+ self._go_previous, None)
+ if playing:
+ self._notification.add_action('media-playback-pause', _("Pause"),
+ self._pause, None)
+ else:
+ self._notification.add_action('media-playback-start', _("Play"),
+ self._play, None)
+ self._notification.add_action('media-skip-forward', _("Next"),
+ self._go_next, None)
+
+ def _go_previous(self, notification, action, data):
+ self._player.play_previous()
+
+ def _go_next(self, notification, action, data):
+ self._player.play_next()
+
+ def _play(self, notification, action, data):
+ self._player.play()
+
+ def _pause(self, notification, action, data):
+ self._player.pause()
diff --git a/gnomemusic/player.py b/gnomemusic/player.py
index 490ac2e..e592453 100644
--- a/gnomemusic/player.py
+++ b/gnomemusic/player.py
@@ -56,7 +56,6 @@ class PlaybackStatus:
class Player(GObject.GObject):
nextTrack = None
timeout = None
- playing = False
__gsignals__ = {
'playing-changed': (GObject.SIGNAL_RUN_FIRST, None, ()),
@@ -274,6 +273,10 @@ class Player(GObject.GObject):
else:
return False
+ @property
+ def playing(self):
+ return self._get_playing()
+
def _sync_playing(self):
image = self._pauseImage if self._get_playing() else self._playImage
if self.playBtn.get_image() != image:
@@ -345,6 +348,7 @@ class Player(GObject.GObject):
self.timeout = GLib.timeout_add(1000, self._update_position_callback)
self.emit('playback-status-changed')
+ self.emit('playing-changed')
def pause(self):
if self.timeout:
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]