Ejemplo n.º 1
0
 def __init__(self, app):
     DBusGMainLoop(set_as_default=True)
     name = dbus.service.BusName('org.mpris.MediaPlayer2.GnomeMusic',
                                 dbus.SessionBus())
     dbus.service.Object.__init__(self, name, '/org/mpris/MediaPlayer2')
     self.app = app
     self.player = app.get_active_window().player
     self.player.connect('current-changed', self._on_current_changed)
     self.player.connect('thumbnail-updated', self._on_thumbnail_updated)
     self.player.connect('playback-status-changed',
                         self._on_playback_status_changed)
     self.player.connect('repeat-mode-changed',
                         self._on_repeat_mode_changed)
     self.player.connect('volume-changed', self._on_volume_changed)
     self.player.connect('prev-next-invalidated',
                         self._on_prev_next_invalidated)
     self.player.connect('seeked', self._on_seeked)
     self.player.connect('playlist-changed', self._on_playlist_changed)
     playlists = Playlists.get_default()
     playlists.connect('playlist-created', self._on_playlists_count_changed)
     playlists.connect('playlist-deleted', self._on_playlists_count_changed)
     grilo.connect('ready', self._on_grilo_ready)
     self.playlists = []
     self.playlist = None
     self.playlist_insert_handler = 0
     self.playlist_delete_handler = 0
     self.first_song_handler = 0
Ejemplo n.º 2
0
    def __init__(self, parent):
        self.ui = Gtk.Builder()
        self.ui.add_from_resource('/org/gnome/Music/PlaylistDialog.ui')
        self.dialog_box = self.ui.get_object('dialog1')
        self.dialog_box.set_transient_for(parent)

        self.view = self.ui.get_object('treeview1')
        self.selection = self.ui.get_object('treeview-selection1')
        self._add_list_renderers()
        self.view.connect('row-activated', self._on_item_activated)

        self.model = self.ui.get_object('liststore1')
        self.populate()

        self.title_bar = self.ui.get_object('headerbar1')
        self.dialog_box.set_titlebar(self.title_bar)

        self._cancel_button = self.ui.get_object('cancel-button')
        self._select_button = self.ui.get_object('select-button')
        self._select_button.set_sensitive(False)
        self._cancel_button.connect('clicked', self._on_cancel_button_clicked)
        self._select_button.connect('clicked', self._on_selection)

        self.playlist = Playlists.get_default()
        self.playlist.connect('playlist-created', self._on_playlist_created)
Ejemplo n.º 3
0
    def __init__(self, app):
        self.con = Gio.bus_get_sync(Gio.BusType.SESSION, None)
        Gio.bus_own_name_on_connection(self.con,
                                       'org.mpris.MediaPlayer2.GnomeMusic',
                                       Gio.BusNameOwnerFlags.NONE,
                                       None,
                                       None)
        super().__init__(self.con, '/org/mpris/MediaPlayer2')

        self.app = app
        self.player = app.get_active_window().player
        self.player.connect('current-changed', self._on_current_changed)
        self.player.connect('thumbnail-updated', self._on_thumbnail_updated)
        self.player.connect('playback-status-changed', self._on_playback_status_changed)
        self.player.connect('repeat-mode-changed', self._on_repeat_mode_changed)
        self.player.connect('volume-changed', self._on_volume_changed)
        self.player.connect('prev-next-invalidated', self._on_prev_next_invalidated)
        self.player.connect('seeked', self._on_seeked)
        self.player.connect('playlist-changed', self._on_playlist_changed)
        playlists = Playlists.get_default()
        playlists.connect('playlist-created', self._on_playlists_count_changed)
        playlists.connect('playlist-deleted', self._on_playlists_count_changed)
        grilo.connect('ready', self._on_grilo_ready)
        self.playlists = []
        self.playlist = None
        self.playlist_insert_handler = 0
        self.playlist_delete_handler = 0
        self.first_song_handler = 0
Ejemplo n.º 4
0
    def __init__(self, parent):
        self.ui = Gtk.Builder()
        self.ui.add_from_resource('/org/gnome/Music/PlaylistDialog.ui')
        self.dialog_box = self.ui.get_object('dialog1')
        self.dialog_box.set_transient_for(parent)

        self.view = self.ui.get_object('treeview1')
        self.selection = self.ui.get_object('treeview-selection1')
        self.selection.connect('changed', self._on_selection_changed)
        self._add_list_renderers()
        self.view.connect('row-activated', self._on_item_activated)

        self.model = self.ui.get_object('liststore1')
        self.populate()

        self.title_bar = self.ui.get_object('headerbar1')
        self.dialog_box.set_titlebar(self.title_bar)

        self._cancel_button = self.ui.get_object('cancel-button')
        self._select_button = self.ui.get_object('select-button')
        self._select_button.set_sensitive(False)
        self._cancel_button.connect('clicked', self._on_cancel_button_clicked)
        self._select_button.connect('clicked', self._on_selection)

        self.playlist = Playlists.get_default()
        self.playlist.connect('playlist-created', self._on_playlist_created)
Ejemplo n.º 5
0
    def __init__(self, app):
        self.con = Gio.bus_get_sync(Gio.BusType.SESSION, None)
        Gio.bus_own_name_on_connection(self.con,
                                       'org.mpris.MediaPlayer2.GnomeMusic',
                                       Gio.BusNameOwnerFlags.NONE, None, None)
        super().__init__(self.con, '/org/mpris/MediaPlayer2')

        self.app = app
        self.player = app.props.player
        self.player.connect('song-changed', self._on_current_song_changed)
        self.player.connect('notify::state', self._on_player_state_changed)
        self.player.connect('notify::repeat-mode',
                            self._on_repeat_mode_changed)
        self.player.connect('seek-finished', self._on_seek_finished)
        self.player.connect('playlist-changed',
                            self._on_player_playlist_changed)
        self._playlists = Playlists.get_default()
        self._playlists.connect('playlist-created',
                                self._on_playlists_count_changed)
        self._playlists.connect('playlist-deleted',
                                self._on_playlists_count_changed)
        self._playlists.connect('playlist-renamed', self._on_playlist_renamed)
        grilo.connect('ready', self._on_grilo_ready)
        self._stored_playlists = []
        self._player_previous_type = None
        self._path_list = []
        self._metadata_list = []
        self._previous_can_go_next = False
        self._previous_can_go_previous = False
        self._previous_can_play = False
        self._previous_is_shuffled = None
        self._previous_loop_status = ""
        self._previous_mpris_playlist = self._get_active_playlist()
        self._previous_playback_status = "Stopped"
Ejemplo n.º 6
0
    def __init__(self, app):
        self.con = Gio.bus_get_sync(Gio.BusType.SESSION, None)
        Gio.bus_own_name_on_connection(self.con,
                                       'org.mpris.MediaPlayer2.GnomeMusic',
                                       Gio.BusNameOwnerFlags.NONE, None, None)
        super().__init__(self.con, '/org/mpris/MediaPlayer2')

        self.app = app
        self.player = app.get_active_window()._player
        self.player.connect('song-changed', self._on_current_song_changed)
        self.player.connect('notify::state', self._on_player_state_changed)
        self.player.connect('notify::repeat-mode',
                            self._on_repeat_mode_changed)
        self.player.connect('volume-changed', self._on_volume_changed)
        self.player.connect('prev-next-invalidated',
                            self._on_prev_next_invalidated)
        self.player.connect('seek-finished', self._on_seek_finished)
        self.player.connect('playlist-changed',
                            self._on_player_playlist_changed)
        self.player_toolbar = app.get_active_window()._player_toolbar
        self.player_toolbar.connect('thumbnail-updated',
                                    self._on_thumbnail_updated)
        playlists = Playlists.get_default()
        playlists.connect('playlist-created', self._on_playlists_count_changed)
        playlists.connect('playlist-deleted', self._on_playlists_count_changed)
        grilo.connect('ready', self._on_grilo_ready)
        self.playlists = []
        self._player_previous_type = None
        self._path_list = []
        self._metadata_list = []
Ejemplo n.º 7
0
    def __init__(self, app):
        self.con = Gio.bus_get_sync(Gio.BusType.SESSION, None)
        Gio.bus_own_name_on_connection(self.con,
                                       'org.mpris.MediaPlayer2.GnomeMusic',
                                       Gio.BusNameOwnerFlags.NONE,
                                       None,
                                       None)
        super().__init__(self.con, '/org/mpris/MediaPlayer2')

        self.app = app
        self.player = app.props.player
        self.player.connect(
            'song-changed', self._on_current_song_changed)
        self.player.connect('notify::state', self._on_player_state_changed)
        self.player.connect('notify::repeat-mode', self._on_repeat_mode_changed)
        self.player.connect('seek-finished', self._on_seek_finished)
        self.player.connect(
            'playlist-changed', self._on_player_playlist_changed)
        self.player_toolbar = app.get_active_window()._player_toolbar
        self.player_toolbar.connect(
            'thumbnail-updated', self._on_thumbnail_updated)
        playlists = Playlists.get_default()
        playlists.connect('playlist-created', self._on_playlists_count_changed)
        playlists.connect('playlist-deleted', self._on_playlists_count_changed)
        grilo.connect('ready', self._on_grilo_ready)
        self.playlists = []
        self._player_previous_type = None
        self._path_list = []
        self._metadata_list = []
        self._previous_playback_status = "Stopped"
Ejemplo n.º 8
0
    def __init__(self, app):
        self.con = Gio.bus_get_sync(Gio.BusType.SESSION, None)
        Gio.bus_own_name_on_connection(self.con,
                                       'org.mpris.MediaPlayer2.GnomeMusic',
                                       Gio.BusNameOwnerFlags.NONE, None, None)
        super().__init__(self.con, '/org/mpris/MediaPlayer2')

        self.app = app
        self.player = app.get_active_window().player
        self.player.connect('current-changed', self._on_current_changed)
        self.player.connect('thumbnail-updated', self._on_thumbnail_updated)
        self.player.connect('playback-status-changed',
                            self._on_playback_status_changed)
        self.player.connect('repeat-mode-changed',
                            self._on_repeat_mode_changed)
        self.player.connect('volume-changed', self._on_volume_changed)
        self.player.connect('prev-next-invalidated',
                            self._on_prev_next_invalidated)
        self.player.connect('seeked', self._on_seeked)
        self.player.connect('playlist-changed', self._on_playlist_changed)
        playlists = Playlists.get_default()
        playlists.connect('playlist-created', self._on_playlists_count_changed)
        playlists.connect('playlist-deleted', self._on_playlists_count_changed)
        grilo.connect('ready', self._on_grilo_ready)
        self.playlists = []
        self.playlist = None
        self.playlist_insert_handler = 0
        self.playlist_delete_handler = 0
        self.first_song_handler = 0
Ejemplo n.º 9
0
    def __init__(self, parent, playlists_todelete):
        super().__init__()

        self._add_playlist_button = None
        self._add_playlist_entry = None

        self.props.transient_for = parent
        self.set_titlebar(self._title_bar)
        self._populate()

        self._playlists_todelete_ids = playlists_todelete.keys()

        self._user_playlists_available = False
        self._playlist = Playlists.get_default()
        self._playlist.connect('playlist-created', self._on_playlist_created)
Ejemplo n.º 10
0
    def __init__(self, parent, playlists_todelete):
        self._ui = Gtk.Builder()
        self._ui.add_from_resource('/org/gnome/Music/PlaylistDialog.ui')

        self._dialog_box = self._ui.get_object('dialog')
        self._dialog_box.set_transient_for(parent)

        self._add_playlist_stack = self._ui.get_object('add_playlist_stack')
        self._normal_state = self._ui.get_object('normal_state')
        self._empty_state = self._ui.get_object('empty_state')
        self._title_bar = self._ui.get_object('headerbar')
        self._dialog_box.set_titlebar(self._title_bar)
        self._setup_dialog()

        self._playlists_todelete_ids = playlists_todelete.keys()

        self._playlist = Playlists.get_default()
Ejemplo n.º 11
0
 def __init__(self, app):
     DBusGMainLoop(set_as_default=True)
     name = dbus.service.BusName('org.mpris.MediaPlayer2.GnomeMusic', dbus.SessionBus())
     dbus.service.Object.__init__(self, name, '/org/mpris/MediaPlayer2')
     self.app = app
     self.player = app.get_active_window().player
     self.player.connect('current-changed', self._on_current_changed)
     self.player.connect('thumbnail-updated', self._on_thumbnail_updated)
     self.player.connect('playback-status-changed', self._on_playback_status_changed)
     self.player.connect('repeat-mode-changed', self._on_repeat_mode_changed)
     self.player.connect('volume-changed', self._on_volume_changed)
     self.player.connect('prev-next-invalidated', self._on_prev_next_invalidated)
     self.player.connect('seeked', self._on_seeked)
     self.player.connect('playlist-changed', self._on_playlist_changed)
     playlists = Playlists.get_default()
     playlists.connect('playlist-created', self._on_playlists_count_changed)
     playlists.connect('playlist-deleted', self._on_playlists_count_changed)
     grilo.connect('ready', self._on_grilo_ready)
     self.playlists = []
     self.playlist = None
     self.playlist_insert_handler = 0
     self.playlist_delete_handler = 0
     self.first_song_handler = 0
Ejemplo n.º 12
0
gi.require_version('Gst', '1.0')
gi.require_version('GstAudio', '1.0')
gi.require_version('GstPbutils', '1.0')
from gi.repository import Gtk, Gdk, GLib, Gio, GObject, Gst, GstAudio, GstPbutils
from gettext import gettext as _, ngettext

from gnomemusic import log
from gnomemusic.albumartcache import AlbumArtCache, DefaultIcon, ArtSize
from gnomemusic.grilo import grilo
from gnomemusic.playlists import Playlists
from gnomemusic.scrobbler import LastFmScrobbler
import gnomemusic.utils as utils


logger = logging.getLogger(__name__)
playlists = Playlists.get_default()


class RepeatType:
    NONE = 0
    SONG = 1
    ALL = 2
    SHUFFLE = 3


class PlaybackStatus:
    PLAYING = 0
    PAUSED = 1
    STOPPED = 2

Ejemplo n.º 13
0
from gnomemusic.views.artistsview import ArtistsView
from gnomemusic.views.emptyview import EmptyView
from gnomemusic.views.emptysearchview import EmptySearchView
from gnomemusic.views.initialstateview import InitialStateView
from gnomemusic.views.searchview import SearchView
from gnomemusic.views.songsview import SongsView
from gnomemusic.views.playlistview import PlaylistView
from gnomemusic.widgets.playlistdialog import PlaylistDialog
from gnomemusic.playlists import Playlists
from gnomemusic.grilo import grilo

import logging
logger = logging.getLogger(__name__)

tracker = TrackerWrapper().tracker
playlist = Playlists.get_default()


class Window(Gtk.ApplicationWindow):

    def __repr__(self):
        return '<Window>'

    @log
    def __init__(self, app):
        Gtk.ApplicationWindow.__init__(self,
                                       application=app,
                                       title=_("Music"))
        self.connect('focus-in-event', self._windows_focus_cb)
        self.settings = Gio.Settings.new('org.gnome.Music')
        self.add_action(self.settings.create_action('repeat'))
Ejemplo n.º 14
0
class SongWidget(Gtk.EventBox):
    """The single song widget used in DiscListBox

    Contains
     * play icon (depending on state)
     * selection check box (optional)
     * song number on disc (optional)
     * song title
     * song duration (optional)
     * favorite/star picker (optional)
    """

    __gtype_name__ = 'SongWidget'

    __gsignals__ = {
        'selection-changed': (GObject.SignalFlags.RUN_FIRST, None, ()),
    }

    selected = GObject.Property(type=bool, default=False)
    show_duration = GObject.Property(type=bool, default=True)
    show_favorite = GObject.Property(type=bool, default=True)
    show_song_number = GObject.Property(type=bool, default=True)

    _playlists = Playlists.get_default()

    _select_button = Gtk.Template.Child()
    _number_label = Gtk.Template.Child()
    _title_label = Gtk.Template.Child()
    _duration_label = Gtk.Template.Child()
    _star_eventbox = Gtk.Template.Child()
    _star_image = Gtk.Template.Child()
    _play_icon = Gtk.Template.Child()

    class State(IntEnum):
        """The state of the SongWidget
        """
        PLAYED = 0
        PLAYING = 1
        UNPLAYED = 2

    def __repr__(self):
        return '<SongWidget>'

    @log
    def __init__(self, media):
        super().__init__()

        self._media = media
        self._selection_mode = False
        self._state = SongWidget.State.UNPLAYED

        song_number = media.get_track_number()
        if song_number == 0:
            song_number = ""
        self._number_label.set_text(str(song_number))

        title = utils.get_media_title(media)
        self._title_label.set_max_width_chars(50)
        self._title_label.set_text(title)

        time = utils.seconds_to_string(media.get_duration())
        self._duration_label.set_text(time)

        self._star_image.props.favorite = media.get_favourite()

        self._select_button.set_visible(False)

        self._play_icon.set_from_icon_name('media-playback-start-symbolic',
                                           Gtk.IconSize.SMALL_TOOLBAR)
        self._play_icon.set_no_show_all(True)

        self.bind_property(
            'selected', self._select_button, 'active',
            GObject.BindingFlags.BIDIRECTIONAL
            | GObject.BindingFlags.SYNC_CREATE)
        self.bind_property('show-duration', self._duration_label, 'visible',
                           GObject.BindingFlags.SYNC_CREATE)
        self._duration_label.set_no_show_all(True)
        self.bind_property('show-favorite', self._star_eventbox, 'visible',
                           GObject.BindingFlags.SYNC_CREATE)
        self._star_eventbox.set_no_show_all(True)
        self.bind_property('show-song-number', self._number_label, 'visible',
                           GObject.BindingFlags.SYNC_CREATE)
        self._number_label.set_no_show_all(True)

    @Gtk.Template.Callback()
    @log
    def _on_selection_changed(self, klass):
        self.emit('selection-changed')

    @Gtk.Template.Callback()
    @log
    def _on_star_toggle(self, widget, event):
        if event.button != Gdk.BUTTON_PRIMARY:
            return False

        favorite = not self._star_image.favorite
        self._star_image.props.favorite = favorite

        # TODO: Rework and stop updating widgets from here directly.
        grilo.set_favorite(self._media, favorite)
        self._playlists.update_static_playlist(StaticPlaylists.Favorites)

        return True

    @Gtk.Template.Callback()
    @log
    def _on_star_hover(self, widget, event):
        self._star_image.props.hover = True

    @Gtk.Template.Callback()
    @log
    def _on_star_unhover(self, widget, event):
        self._star_image.props.hover = False

    @GObject.Property(type=bool, default=False)
    def selection_mode(self):
        """Selection mode

        :returns: Selection mode
        :rtype: bool
        """
        return self._selection_mode

    @selection_mode.setter
    def selection_mode(self, value):
        """Set the selection mode

        :param bool value: Selection mode
        """
        self._selection_mode = value
        self._select_button.set_visible(value)

        if not value:
            self.props.selected = False

    @GObject.Property
    def state(self):
        """State of the widget

        :returns: Widget state
        :rtype: SongWidget.State
        """
        return self._state

    @state.setter
    def state(self, value):
        """Set state of the of widget

        This influences the look of the widgets label and if there is a
        song play indicator being shown.

        :param SongWidget.State value: Widget state
        """
        self._state = value

        style_ctx = self._title_label.get_style_context()

        style_ctx.remove_class('dim-label')
        style_ctx.remove_class('playing-song-label')
        self._play_icon.set_visible(False)

        if value == SongWidget.State.PLAYED:
            style_ctx.add_class('dim-label')
        elif value == SongWidget.State.PLAYING:
            self._play_icon.set_visible(True)
            style_ctx.add_class('playing-song-label')
Ejemplo n.º 15
0
class DiscBox(Gtk.Box):
    """A widget which compromises one disc

    DiscBox contains a disc label for the disc number on top
    with a DiscSongsFlowBox beneath.
    """
    __gtype_name__ = 'DiscBox'

    __gsignals__ = {
        'selection-changed': (GObject.SignalFlags.RUN_FIRST, None, ()),
        'selection-toggle': (GObject.SignalFlags.RUN_FIRST, None, ()),
        'song-activated': (GObject.SignalFlags.RUN_FIRST, None, (Gtk.Widget, ))
    }

    _playlists = Playlists.get_default()

    def __repr__(self):
        return '<DiscBox>'

    @log
    def __init__(self, model=None):
        """Initialize

        :param model: The TreeStore to use
        """
        super().__init__()

        self._model = model
        self._model.connect('row-changed', self._model_row_changed)

        builder = Gtk.Builder()
        builder.add_from_resource('/org/gnome/Music/ArtistAlbumWidget.ui')

        self._label = builder.get_object('disclabel')
        self._label.set_no_show_all(True)
        self._disc_songs_flowbox = builder.get_object('discsongsflowbox')

        self._selection_mode = False
        self._selection_mode_allowed = True
        self._selected_items = []
        self._songs = []

        self.pack_start(builder.get_object('disc'), True, True, 0)

    @log
    def set_columns(self, columns):
        """Set the number of columns used by the songs list

        :param int columns: Number of columns to display
        """
        self._disc_songs_flowbox.set_columns(columns)

    @log
    def set_disc_number(self, disc_number):
        """Set the dics number to display

        :param int disc_number: Disc number to display
        """
        self._label.set_markup(_("Disc {}").format(disc_number))
        self._label.get_style_context().add_class('dim-label')
        self._label.set_visible(True)

    @log
    def show_disc_label(self, show_header):
        """Wheter to show the disc number label

        :param bool show_header: Display the disc number label
        """
        self._label.set_visible(False)
        self._label.hide()

    @log
    def show_duration(self, show_duration):
        """Wheter to show the song durations

        :param bool show_duration: Display the song durations
        """
        def child_show_duration(child):
            child.get_child().duration.set_visible(show_duration)

        self._disc_songs_flowbox.foreach(child_show_duration)

    @log
    def show_favorites(self, show_favorites):
        """Where to show the favorite switches

        :param bool show_favorites: Display the favorite
        switches
        """
        def child_show_favorites(child):
            child.get_child().starevent.set_visible(show_favorites)

        self._disc_songs_flowbox.foreach(child_show_favorites)

    @log
    def show_song_numbers(self, show_song_number):
        """Whether to show the song numbers

        :param bool show_song_number: Display the song number
        """
        def child_show_song_number(child):
            child.get_child().number.set_visible(show_song_number)

        self._disc_songs_flowbox.foreach(child_show_song_number)

    @log
    def set_songs(self, songs):
        """Songs to display

        :param list songs: A list of Grilo media items to
        add to the widget
        """
        for song in songs:
            song_widget = self._create_song_widget(song)
            self._disc_songs_flowbox.insert(song_widget, -1)
            song.song_widget = song_widget

    @log
    def set_selection_mode(self, selection_mode):
        """Set selection mode

        :param bool selection_mode: Allow selection mode
        """
        self._selection_mode = selection_mode
        self._disc_songs_flowbox.foreach(self._toggle_widget_selection)

    @log
    def get_selected_items(self):
        """Return all selected items

        :returns: The selected items:
        :rtype: A list if Grilo media items
        """
        self._selected_items = []
        self._disc_songs_flowbox.foreach(self._get_selected)

        return self._selected_items

    @log
    def _get_selected(self, child):
        song_widget = child.get_child()

        if song_widget.check_button.get_active():
            itr = song_widget.itr
            self._selected_items.append(self._model[itr][5])

    # FIXME: select all/none slow probably b/c of the row changes
    # invocations, maybe workaround?
    @log
    def select_all(self):
        """Select all songs"""
        def child_select_all(child):
            song_widget = child.get_child()
            self._model[song_widget.itr][6] = True

        self._disc_songs_flowbox.foreach(child_select_all)

    @log
    def select_none(self):
        """Deselect all songs"""
        def child_select_none(child):
            song_widget = child.get_child()
            self._model[song_widget.itr][6] = False

        self._disc_songs_flowbox.foreach(child_select_none)

    @log
    def _create_song_widget(self, song):
        """Helper function to create a song widget for a
        single song

        :param song: A Grilo media item
        :returns: A complete song widget
        :rtype: Gtk.EventBox
        """
        builder = Gtk.Builder()
        builder.add_from_resource('/org/gnome/Music/TrackWidget.ui')
        song_widget = builder.get_object('eventbox1')
        self._songs.append(song_widget)

        title = utils.get_media_title(song)

        itr = self._model.append(None)

        self._model[itr][0, 1, 2, 5, 6] = [title, '', '', song, False]

        song_widget.itr = itr
        song_widget.model = self._model

        song_number = song.get_track_number()
        if song_number == 0:
            song_number = ""
        song_widget.number = builder.get_object('num')
        song_widget.number.set_markup(
            '<span color=\'grey\'>{}</span>'.format(song_number))
        song_widget.number.set_no_show_all(True)

        song_widget.title = builder.get_object('title')
        song_widget.title.set_text(title)
        song_widget.title.set_max_width_chars(50)

        song_widget.duration = builder.get_object('duration')
        time = utils.seconds_to_string(song.get_duration())
        song_widget.duration.set_text(time)

        song_widget.check_button = builder.get_object('select')
        song_widget.check_button.set_visible(False)
        song_widget.check_button.connect('toggled', self._check_button_toggled,
                                         song_widget)

        song_widget.now_playing_sign = builder.get_object('image1')
        song_widget.now_playing_sign.set_from_icon_name(
            'media-playback-start-symbolic', Gtk.IconSize.SMALL_TOOLBAR)
        song_widget.now_playing_sign.set_no_show_all(True)
        song_widget.can_be_played = True
        song_widget.connect('button-release-event', self._song_activated)

        song_widget.star_image = builder.get_object('starimage')
        song_widget.star_image.set_favorite(song.get_favourite())
        song_widget.star_image.set_visible(True)

        song_widget.starevent = builder.get_object('starevent')
        song_widget.starevent.connect('button-release-event',
                                      self._toggle_favorite, song_widget)
        song_widget.starevent.connect('enter-notify-event',
                                      song_widget.star_image.hover, None)
        song_widget.starevent.connect('leave-notify-event',
                                      song_widget.star_image.unhover, None)
        return song_widget

    @log
    def _toggle_favorite(self, widget, event, song_widget):
        if event.button == Gdk.BUTTON_PRIMARY:
            song_widget.star_image.toggle_favorite()

        # FIXME: ugleh. Should probably be triggered by a
        # signal.
        favorite = song_widget.star_image.get_favorite()
        grilo.set_favorite(self._model[song_widget.itr][5], favorite)
        self._playlists.update_static_playlist(StaticPlaylists.Favorites)

        return True

    @log
    def _check_button_toggled(self, widget, song_widget):
        self.emit('selection-changed')

        return True

    @log
    def _toggle_widget_selection(self, child):
        song_widget = child.get_child()
        song_widget.check_button.set_visible(self._selection_mode)
        if self._selection_mode is False:
            if song_widget.check_button.get_active():
                song_widget.check_button.set_active(False)

    @log
    def _song_activated(self, widget, event):
        # FIXME: don't think keys work correctly, if they did ever
        # even.
        if (not event.button == Gdk.BUTTON_SECONDARY
                or (event.button == Gdk.BUTTON_PRIMARY
                    and event.state & Gdk.ModifierType.CONTROL_MASK)):
            self.emit('song-activated', widget)
            if self._selection_mode:
                itr = widget.itr
                self._model[itr][6] = not self._model[itr][6]
        else:
            self.emit('selection-toggle')
            if self._selection_mode:
                itr = widget.itr
                self._model[itr][6] = True

        return True

    @log
    def _model_row_changed(self, model, path, itr):
        if (not self._selection_mode or not model[itr][5]):
            return

        song_widget = model[itr][5].song_widget
        selected = model[itr][6]
        if selected != song_widget.check_button.get_active():
            song_widget.check_button.set_active(selected)

        return True