class AltToolbarShared(AltToolbarBase): ''' shared components for the compact and headerbar toolbar types ''' def __init__(self): ''' Initialises the object. ''' super(AltToolbarShared, self).__init__() # Prepare Album Art Displaying self.album_art_db = GObject.new(RB.ExtDB, name="album-art") what, width, height = Gtk.icon_size_lookup(Gtk.IconSize.SMALL_TOOLBAR) self.icon_width = width self.cover_pixbuf = None def initialise(self, plugin): super(AltToolbarShared, self).initialise(plugin) ui = rb.find_plugin_file(plugin, 'ui/alttoolbar.ui') builder = Gtk.Builder() builder.add_from_file(ui) self.load_builder_content(builder) self.connect_builder_content(builder) def post_initialise(self): self.volume_button.bind_property("value", self.shell.props.shell_player, "volume", Gio.SettingsBindFlags.DEFAULT) self.volume_button.props.value = self.shell.props.shell_player.props.volume self.volume_button.set_visible(self.plugin.volume_control) self.volume_button.set_relief(Gtk.ReliefStyle.NORMAL) child = self.volume_button.get_child() child.set_margin_left(5) child.set_margin_right(5) if self.plugin.inline_label: self.song_box.remove(self.song_button_label) if self.plugin.compact_progressbar: self.song_progress = SmallProgressBar() else: self.song_progress = SmallScale() self.song_progress.connect('control', self._sh_progress_control) self.song_progress.show_all() self.song_progress_box.pack_start(self.song_progress, False, True, 1) # Bring Builtin Actions to plugin for (a, b) in ((self.play_button, "play"), (self.prev_button, "play-previous"), (self.next_button, "play-next"), (self.repeat_toggle, "play-repeat"), (self.shuffle_toggle, "play-shuffle")): a.set_action_name("app." + b) if b == "play-repeat" or b == "play-shuffle": # for some distros you need to set the target_value # for others this would actually disable the action # so work around this by testing if the action is disabled # then reset the action a.set_action_target_value(GLib.Variant("b", True)) print(a.get_sensitive()) if not a.get_sensitive(): a.set_detailed_action_name("app." + b) if gtk_version() >= 3.12: self.cover_popover = Gtk.Popover.new(self.album_cover) image = Gtk.Image.new() self.cover_popover.add(image) def show_cover_tooltip(self, tooltip): if (self.cover_pixbuf is not None): if gtk_version() >= 3.12: if self.cover_popover.get_visible(): return False image = self.cover_popover.get_child() image.set_from_pixbuf( self.cover_pixbuf.scale_simple(300, 300, GdkPixbuf.InterpType.HYPER)) self.cover_popover.show_all() else: tooltip.set_icon( self.cover_pixbuf.scale_simple(300, 300, GdkPixbuf.InterpType.HYPER)) return True else: return False def show_slider(self, visibility): self.song_box.set_visible(visibility) def display_song(self, entry): self.entry = entry self.cover_pixbuf = None self.album_cover.clear() if self.plugin.inline_label: ret = self._inline_progress_label(entry) else: ret = self._combined_progress_label(entry) if ret: key = entry.create_ext_db_key(RB.RhythmDBPropType.ALBUM) self.album_art_db.request(key, self.display_song_album_art_callback, entry) def _inline_progress_label(self, entry): if (entry is None): # self.song_button_label.set_text("") self.inline_box.set_visible(False) return False self.inline_box.set_visible(True) stream_title = self.shell.props.db.entry_request_extra_metadata( entry, RB.RHYTHMDB_PROP_STREAM_SONG_TITLE) stream_artist = self.shell.props.db.entry_request_extra_metadata( entry, RB.RHYTHMDB_PROP_STREAM_SONG_ARTIST) def set_labels(title, artist): for child in self.inline_box: self.inline_box.remove(child) self.song_title = Gtk.Label() self.song_title.set_markup(title) self.song_title.set_ellipsize(Pango.EllipsizeMode.END) self.song_title.show() self.inline_box.pack_start(self.song_title, False, True, 0) print(artist) if artist != "" or artist: print("adding artist") self.song_artist = Gtk.Label() self.song_artist.set_markup(artist) self.song_artist.set_ellipsize(Pango.EllipsizeMode.END) self.song_artist.show() self.inline_box.pack_start(self.song_artist, False, True, 1) if stream_title: print("stream_title") if stream_artist: artist_markup = "<small>{artist}</small>".format( artist=GLib.markup_escape_text(stream_artist)) else: artist_markup = "" title_markup = "<b>{title}</b>".format( title=GLib.markup_escape_text(stream_title)) set_labels(title_markup, artist_markup) return True album = entry.get_string(RB.RhythmDBPropType.ALBUM) if not album or album == "": print("album") title_markup = "<b>{title}</b>".format( title=GLib.markup_escape_text( entry.get_string(RB.RhythmDBPropType.TITLE))) artist = entry.get_string(RB.RhythmDBPropType.ARTIST) if artist and artist != "": artist_markup = "<small>{artist}</small>".format( artist=GLib.markup_escape_text( entry.get_string(RB.RhythmDBPropType.ARTIST))) else: artist_markup = "" set_labels(title_markup, artist_markup) return True if self.plugin.playing_label: print("playing_label") year = entry.get_ulong(RB.RhythmDBPropType.DATE) if year == 0: year = date.today().year else: year = datetime.fromordinal(year).year title_markup = "<b>{album}</b>".format( album=GLib.markup_escape_text( entry.get_string(RB.RhythmDBPropType.ALBUM))) artist_markup = "<small>{genre} - {year}</small>".format( genre=GLib.markup_escape_text( entry.get_string(RB.RhythmDBPropType.GENRE)), year=GLib.markup_escape_text(str(year))) set_labels(title_markup, artist_markup) else: print("not playing_label") title_markup = "<b>{title}</b>".format( title=GLib.markup_escape_text( entry.get_string(RB.RhythmDBPropType.TITLE))) artist_markup = "<small>{artist}</small>".format( artist=GLib.markup_escape_text( entry.get_string(RB.RhythmDBPropType.ARTIST))) set_labels(title_markup, artist_markup) return True def _combined_progress_label(self, entry): ''' utility function to calculate the label to be used when a progress bar has the label above it :param RBEntry ''' if (entry is None): self.song_button_label.set_text("") return False stream_title = self.shell.props.db.entry_request_extra_metadata( entry, RB.RHYTHMDB_PROP_STREAM_SONG_TITLE) stream_artist = self.shell.props.db.entry_request_extra_metadata( entry, RB.RHYTHMDB_PROP_STREAM_SONG_ARTIST) if stream_title: if stream_artist: markup = "<small><b>{title}</b> {artist}</small>".format( title=GLib.markup_escape_text(stream_title), artist=GLib.markup_escape_text(stream_artist)) else: markup = "<small><b>{title}</b></small>".format( title=GLib.markup_escape_text(stream_title)) self.song_button_label.set_markup(markup) return True album = entry.get_string(RB.RhythmDBPropType.ALBUM) if not album or album == "": self.song_button_label.set_markup( "<small><b>{title}</b></small>".format( title=GLib.markup_escape_text( entry.get_string(RB.RhythmDBPropType.TITLE)))) return True if self.plugin.playing_label: year = entry.get_ulong(RB.RhythmDBPropType.DATE) if year == 0: year = date.today().year else: year = datetime.fromordinal(year).year self.song_button_label.set_markup( "<small>{album} - {genre} - {year}</small>".format( album=GLib.markup_escape_text( entry.get_string(RB.RhythmDBPropType.ALBUM)), genre=GLib.markup_escape_text( entry.get_string(RB.RhythmDBPropType.GENRE)), year=GLib.markup_escape_text(str(year)))) else: self.song_button_label.set_markup( "<small><b>{title}</b> {album} - {artist}</small>".format( title=GLib.markup_escape_text( entry.get_string(RB.RhythmDBPropType.TITLE)), album=GLib.markup_escape_text( entry.get_string(RB.RhythmDBPropType.ALBUM)), artist=GLib.markup_escape_text( entry.get_string(RB.RhythmDBPropType.ARTIST)))) return True def display_song_album_art_callback(self, *args): # key, filename, data, entry): ''' RBExtDB signal callback to display the album-art ''' # rhythmbox 3.2 breaks the API - need to find the parameter with the pixbuf data = None for data in args: if isinstance(data, GdkPixbuf.Pixbuf): break if ((data is not None) and (isinstance(data, GdkPixbuf.Pixbuf))): self.cover_pixbuf = data scale_cover = self.cover_pixbuf.scale_simple( 34, 34, GdkPixbuf.InterpType.HYPER) self.album_cover.set_from_pixbuf(scale_cover) else: self.cover_pixbuf = None self.album_cover.clear() self.album_cover.trigger_tooltip_query() def show_cover(self, visibility): self.album_cover.set_visible(self.plugin.show_album_art) def show_small_bar(self): self.small_bar.show_all() self.inline_box.set_visible(False) def play_control_change(self, player, playing): image = self.play_button.get_child() if (playing): if player.get_active_source().can_pause(): icon_name = "media-playback-pause-symbolic" else: icon_name = "media-playback-stop-symbolic" else: icon_name = "media-playback-start-symbolic" image.set_from_icon_name(icon_name, image.props.icon_size) # Builder related utility functions... #################################### def load_builder_content(self, builder): if (not hasattr(self, "__builder_obj_names")): self.__builder_obj_names = list() for obj in builder.get_objects(): if (isinstance(obj, Gtk.Buildable)): name = Gtk.Buildable.get_name(obj).replace(' ', '_') self.__dict__[name] = obj self.__builder_obj_names.append(name) def connect_builder_content(self, builder): builder.connect_signals_full(self.connect_builder_content_func, self) def connect_builder_content_func(self, builder, object, sig_name, handler_name, conn_object, flags, target): handler = None h_name_internal = "_sh_" + handler_name.replace(" ", "_") if (hasattr(target, h_name_internal)): handler = getattr(target, h_name_internal) else: handler = eval(handler_name) object.connect(sig_name, handler) def purge_builder_content(self): for name in self.__builder_obj_names: o = self.__dict__[name] if (isinstance(o, Gtk.Widget)): o.destroy() del self.__dict__[name] del self.__builder_obj_names # Signal Handlers ########################################################## def _sh_progress_control(self, progress, fraction): #if not hasattr(self, 'song_duration'): # return if (self.plugin.song_duration != 0): self.shell.props.shell_player.set_playing_time( self.plugin.song_duration * fraction) def _sh_bigger_cover(self, cover, x, y, key, tooltip): return self.show_cover_tooltip(tooltip)
class AltToolbarShared(AltToolbarBase): """ shared components for the compact and headerbar toolbar types """ def __init__(self): """ Initialises the object. """ super(AltToolbarShared, self).__init__() # Prepare Album Art Displaying self.album_art_db = GObject.new(RB.ExtDB, name="album-art") what, width, height = Gtk.icon_size_lookup(Gtk.IconSize.SMALL_TOOLBAR) self.icon_width = width self.cover_pixbuf = None self._controllers = {} self._tooltip_exceptions = ['album_cover'] self._moved_controls = [] def initialise(self, plugin): super(AltToolbarShared, self).initialise(plugin) ui = rb.find_plugin_file(plugin, 'ui/alttoolbar.ui') builder = Gtk.Builder() builder.add_from_file(ui) self.load_builder_content(builder) self.connect_builder_content(builder) self._controllers['generic'] = AltGenericController(self) # every potential source should have its own controller - we use this to # categorise the source and provide specific capability for inherited classes # where a controller is not specified then a generic controller is used # i.e. use add_controller method to add a controller self.add_controller(AltMusicLibraryController(self)) self.add_controller(AltSoundCloudController(self)) self.add_controller(AltCoverArtBrowserController(self)) self.add_controller(AltCoverArtPlaySourceController(self)) self.add_controller(AltQueueController(self)) self.add_controller(AltStandardOnlineController(self)) self.add_controller(AltStandardLocalController(self)) self.add_controller(AltRadioController(self)) self.add_controller(AltLastFMController(self)) self.add_controller(AltPlaylistController(self)) self.add_controller(AltErrorsController(self)) self.add_controller(AltPodcastController(self)) self.add_controller(AltAndroidController(self)) # support RTL for control, icon_name in [ (self.prev_button, 'media-skip-backward-symbolic'), (self.play_button, 'media-playback-start-symbolic'), (self.next_button, 'media-skip-forward-symbolic') ]: image = control.get_child() icon_name = self.request_rtl_icon(control, icon_name) image.set_from_icon_name(icon_name, image.props.icon_size) # now move current RBDisplayPageTree to listview stack display_tree = self.shell.props.display_page_tree self.display_tree_parent = display_tree.get_parent() self.display_tree_parent.remove(display_tree) self.stack = Gtk.Stack() self.stack.set_transition_type( Gtk.StackTransitionType.SLIDE_LEFT_RIGHT) self.stack.set_transition_duration(1000) image_name = 'view-list-symbolic' box_listview = Gtk.Box() box_listview.pack_start(display_tree, True, True, 0) # box_listview.show_all() self.stack.add_named(box_listview, "listview") self.stack.child_set_property(box_listview, "icon-name", image_name) self.stack.show_all() self.display_tree_parent.pack1(self.stack, True, True) #if 1==2: #self.plugin.enhanced_sidebar: toolbar = self.find(display_tree, 'GtkToolbar', 'by_name') #context = toolbar.get_style_context() #context.add_class('toolbar') box = self.find(toolbar, 'GtkBox', 'by_name') #box.props.margin_top = 2 #box.props.margin_bottom = 0 #box.props.margin_left = 5 context = box.get_style_context() context.add_class('linked') #parent = box.get_parent() #parent.remove(box) #parent_toolbar = toolbar.get_parent() #parent_toolbar.remove(toolbar) #display_tree.attach(box, 0, 10, 1 ,1 ) # child, new-parent, old-parent #self._moved_controls.append((box, display_tree, parent)) #self._moved_controls.append((toolbar, None, parent_toolbar)) # find the actual GtkTreeView in the RBDisplayTree and remove it self.rbtree = self.find(display_tree, 'GtkTreeView', 'by_name') self.rbtreeparent = self.rbtree.get_parent() self.rbtreeparent.remove(self.rbtree) self.sidebar = None def post_initialise(self): super(AltToolbarShared, self).post_initialise() self.volume_button.props.value = self.shell.props.shell_player.props.volume self.volume_button.bind_property("value", self.shell.props.shell_player, "volume", Gio.SettingsBindFlags.DEFAULT) self.volume_button.set_visible(self.plugin.volume_control) self.volume_button.set_relief(Gtk.ReliefStyle.NORMAL) child = self.volume_button.get_child() child.set_margin_left(5) child.set_margin_right(5) if self.plugin.inline_label: self.song_box.remove(self.song_button_label) if self.plugin.compact_progressbar: self.song_progress = SmallProgressBar() else: self.song_progress = SmallScale() self.song_progress.connect('control', self._sh_progress_control) self.song_progress.show_all() self.song_progress_box.pack_start(self.song_progress, False, True, 1) # Bring Builtin Actions to plugin for (a, b) in ((self.play_button, "play"), (self.prev_button, "play-previous"), (self.next_button, "play-next"), (self.repeat_toggle, "play-repeat"), (self.shuffle_toggle, "play-shuffle")): a.set_action_name("app." + b) if b == "play-repeat" or b == "play-shuffle": # for some distros you need to set the target_value # for others this would actually disable the action # so work around this by testing if the action is disabled # then reset the action a.set_action_target_value(GLib.Variant("b", True)) print(a.get_sensitive()) if not a.get_sensitive(): a.set_detailed_action_name("app." + b) # The Play-Repeat button is subject to the plugins Repeat All/one song capability self._repeat = Repeat(self.shell, self.repeat_toggle) if gtk_version() >= 3.12: self.cover_popover = Gtk.Popover.new(self.album_cover) image = Gtk.Image.new() self.cover_popover.add(image) self._popover_inprogress = 0 self.cover_popover.set_modal(False) self.cover_popover.connect('leave-notify-event', self._on_cover_popover_mouse_over) self.cover_popover.connect('enter-notify-event', self._on_cover_popover_mouse_over) # detect when mouse moves out of the cover image (it has a parent eventbox) self.album_cover_eventbox.connect( 'leave-notify-event', self._on_cover_popover_mouse_over) self.album_cover_eventbox.connect( 'enter-notify-event', self._on_cover_popover_mouse_over) def on_startup(self, *args): super(AltToolbarShared, self).on_startup(*args) if self.plugin.enhanced_sidebar: self.sidebar = AltToolbarSidebar(self, self.rbtree) self.sidebar.show_all() self.rbtreeparent.add(self.sidebar) else: self.rbtreeparent.add(self.rbtree) # self.shell.add_widget(self.rbtree, RB.ShellUILocation.SIDEBAR, expand=True, fill=True) def register_moved_control(self, child, old_parent, new_parent=None): """ convenience function to save the GTK child & parents when they are moved. we use this info to cleanup when quitting RB - we need to move stuff back because otherwise there are random crashes due to memory deallocation issues :param child: GTK Widget :param old_parent: original GTK container that the child was moved from :param new_parent: new GTK container that the child was added to (may just have removed without moving) :return: """ # store as a tuple: child, new-parent, old-parent self._moved_controls.append((child, new_parent, old_parent)) def cleanup(self): """ extend :return: """ super(AltToolbarShared, self).cleanup() if self.sidebar: self.sidebar.cleanup() self.display_tree_parent.remove(self.stack) self.display_tree_parent.pack1(self.shell.props.display_page_tree) if self.sidebar: self.rbtreeparent.remove(self.sidebar) # remove our sidebar self.rbtreeparent.add(self.rbtree) # add the original GtkTree view print("####") # child, new-parent, old-parent for child, new_parent, old_parent in reversed(self._moved_controls): if new_parent: new_parent.remove(child) print(child) print(new_parent) print(old_parent) if isinstance(old_parent, Gtk.Grid): print("attaching to grid") old_parent.attach(child, 0, 0, 1, 1) else: print("adding to parent") old_parent.add(child) def add_controller(self, controller): """ register a new controller """ if not controller in self._controllers: self._controllers[controller] = controller def is_controlled(self, source): """ determine if the source has a controller return bool, controller if no specific controller (False) then the generic controller returned """ if source in self._controllers: return True, self._controllers[source] # loop through controllers to find one that is most applicable for controller_type in self._controllers: if self._controllers[controller_type].valid_source(source): return True, self._controllers[controller_type] return False, self._controllers['generic'] def show_cover_tooltip(self, tooltip): if (self.cover_pixbuf is not None): if gtk_version() >= 3.12: if self.cover_popover.get_visible(): return False image = self.cover_popover.get_child() image.set_from_pixbuf( self.cover_pixbuf.scale_simple(300, 300, GdkPixbuf.InterpType.HYPER)) self.cover_popover.show_all() else: tooltip.set_icon( self.cover_pixbuf.scale_simple(300, 300, GdkPixbuf.InterpType.HYPER)) return True else: return False def _on_cover_popover_mouse_over(self, widget, eventcrossing): if eventcrossing.type == Gdk.EventType.ENTER_NOTIFY: if self._popover_inprogress == 0: self._popover_inprogress = 1 else: self._popover_inprogress = 2 self._popover_inprogress_count = 0 print("enter") else: print("exit") self._popover_inprogress = 3 # print (eventcrossing.type) def delayed(*args): if self._popover_inprogress == 3: self._popover_inprogress_count += 1 if self._popover_inprogress_count < 5: return True self.cover_popover.hide() self._popover_inprogress = 0 return False else: return True if self._popover_inprogress == 1: print("addding timeout") self._popover_inprogress = 2 GLib.timeout_add(100, delayed) def show_slider(self, visibility): self.song_box.set_visible(visibility) def display_song(self, entry): self.entry = entry self.cover_pixbuf = None self.album_cover.clear() if self.plugin.inline_label: ret = self._inline_progress_label(entry) else: ret = self._combined_progress_label(entry) if ret: key = entry.create_ext_db_key(RB.RhythmDBPropType.ALBUM) self.album_art_db.request(key, self.display_song_album_art_callback, entry) def _inline_progress_label(self, entry): if (entry is None): # self.song_button_label.set_text("") self.inline_box.set_visible(False) return False self.inline_box.set_visible(True) stream_title = self.shell.props.db.entry_request_extra_metadata( entry, RB.RHYTHMDB_PROP_STREAM_SONG_TITLE) stream_artist = self.shell.props.db.entry_request_extra_metadata( entry, RB.RHYTHMDB_PROP_STREAM_SONG_ARTIST) def set_labels(title, artist): for child in self.inline_box: self.inline_box.remove(child) self.song_title = Gtk.Label() self.song_title.set_markup(title) self.song_title.set_ellipsize(Pango.EllipsizeMode.END) self.song_title.show() self.inline_box.pack_start(self.song_title, False, True, 0) print(artist) if artist != "" or artist: print("adding artist") self.song_artist = Gtk.Label() self.song_artist.set_markup(artist) self.song_artist.set_ellipsize(Pango.EllipsizeMode.END) self.song_artist.show() self.inline_box.pack_start(self.song_artist, False, True, 1) if stream_title: print("stream_title") if stream_artist: artist_markup = "<small>{artist}</small>".format( artist=GLib.markup_escape_text(stream_artist)) else: artist_markup = "" title_markup = "<b>{title}</b>".format( title=GLib.markup_escape_text(stream_title)) set_labels(title_markup, artist_markup) return True album = entry.get_string(RB.RhythmDBPropType.ALBUM) if not album or album == "": print("album") title_markup = "<b>{title}</b>".format( title=GLib.markup_escape_text( entry.get_string(RB.RhythmDBPropType.TITLE))) artist = entry.get_string(RB.RhythmDBPropType.ARTIST) if artist and artist != "": artist_markup = "<small>{artist}</small>".format( artist=GLib.markup_escape_text( entry.get_string(RB.RhythmDBPropType.ARTIST))) else: artist_markup = "" set_labels(title_markup, artist_markup) return True if self.plugin.playing_label: print("playing_label") year = entry.get_ulong(RB.RhythmDBPropType.DATE) if year == 0: year = date.today().year else: year = datetime.fromordinal(year).year title_markup = "<b>{album}</b>".format( album=GLib.markup_escape_text( entry.get_string(RB.RhythmDBPropType.ALBUM))) artist_markup = "<small>{genre} - {year}</small>".format( genre=GLib.markup_escape_text( entry.get_string(RB.RhythmDBPropType.GENRE)), year=GLib.markup_escape_text(str(year))) set_labels(title_markup, artist_markup) else: print("not playing_label") title_markup = "<b>{title}</b>".format( title=GLib.markup_escape_text( entry.get_string(RB.RhythmDBPropType.TITLE))) artist_markup = "<small>{artist}</small>".format( artist=GLib.markup_escape_text( entry.get_string(RB.RhythmDBPropType.ARTIST))) set_labels(title_markup, artist_markup) return True def _combined_progress_label(self, entry): """ utility function to calculate the label to be used when a progress bar has the label above it :param RBEntry """ if (entry is None): self.song_button_label.set_label("") return False stream_title = self.shell.props.db.entry_request_extra_metadata( entry, RB.RHYTHMDB_PROP_STREAM_SONG_TITLE) stream_artist = self.shell.props.db.entry_request_extra_metadata( entry, RB.RHYTHMDB_PROP_STREAM_SONG_ARTIST) if stream_title: if stream_artist: markup = "<small><b>{title}</b> {artist}</small>".format( title=GLib.markup_escape_text(stream_title), artist=GLib.markup_escape_text(stream_artist)) else: markup = "<small><b>{title}</b></small>".format( title=GLib.markup_escape_text(stream_title)) self.song_button_label.set_markup(markup) return True album = entry.get_string(RB.RhythmDBPropType.ALBUM) if not album or album == "": self.song_button_label.set_markup( "<small><b>{title}</b></small>".format( title=GLib.markup_escape_text( entry.get_string(RB.RhythmDBPropType.TITLE)))) return True if self.plugin.playing_label: year = entry.get_ulong(RB.RhythmDBPropType.DATE) if year == 0: year = date.today().year else: year = datetime.fromordinal(year).year self.song_button_label.set_markup( "<small>{album} - {genre} - {year}</small>".format( album=GLib.markup_escape_text( entry.get_string(RB.RhythmDBPropType.ALBUM)), genre=GLib.markup_escape_text( entry.get_string(RB.RhythmDBPropType.GENRE)), year=GLib.markup_escape_text(str(year)))) else: self.song_button_label.set_markup( "<small><b>{title}</b> {album} - {artist}</small>".format( title=GLib.markup_escape_text( entry.get_string(RB.RhythmDBPropType.TITLE)), album=GLib.markup_escape_text( entry.get_string(RB.RhythmDBPropType.ALBUM)), artist=GLib.markup_escape_text( entry.get_string(RB.RhythmDBPropType.ARTIST)))) return True def display_song_album_art_callback(self, *args): # key, filename, data, entry): """ RBExtDB signal callback to display the album-art """ # rhythmbox 3.2 breaks the API - need to find the parameter with the pixbuf data = None for data in args: if isinstance(data, GdkPixbuf.Pixbuf): break if ((data is not None) and (isinstance(data, GdkPixbuf.Pixbuf))): self.cover_pixbuf = data scale_cover = self.cover_pixbuf.scale_simple( 34, 34, GdkPixbuf.InterpType.HYPER) self.album_cover.set_from_pixbuf(scale_cover) else: self.cover_pixbuf = None self.album_cover.clear() self.album_cover.trigger_tooltip_query() def show_cover(self, visibility): self.album_cover.set_visible(self.plugin.show_album_art) def show_small_bar(self): self.small_bar.show_all() self.inline_box.set_visible(False) def request_rtl_icon(self, control, icon_name): if gtk_version() < 3.12: if control.get_direction() == Gtk.TextDirection.RTL: rtl_name = { "media-playback-start-symbolic": "media-playback-start-rtl-symbolic", "media-skip-forward-symbolic": "media-skip-forward-rtl-symbolic", "media-skip-backward-symbolic": "media-skip-backward-rtl-symbolic" } icon_name = rtl_name[icon_name] return icon_name def play_control_change(self, player, playing): image = self.play_button.get_child() if (playing): if player.get_active_source().can_pause(): icon_name = "media-playback-pause-symbolic" else: icon_name = "media-playback-stop-symbolic" else: icon_name = self.request_rtl_icon(self.play_button, "media-playback-start-symbolic") image.set_from_icon_name(icon_name, image.props.icon_size) # Builder related utility functions... #################################### def load_builder_content(self, builder): if (not hasattr(self, "__builder_obj_names")): self.__builder_obj_names = list() for obj in builder.get_objects(): if (isinstance(obj, Gtk.Buildable)): name = Gtk.Buildable.get_name(obj).replace(' ', '_') self.__dict__[name] = obj self.__builder_obj_names.append(name) if not self.plugin.show_tooltips and obj.get_has_tooltip(): if not name in self._tooltip_exceptions: obj.set_has_tooltip(False) def connect_builder_content(self, builder): builder.connect_signals_full(self.connect_builder_content_func, self) def connect_builder_content_func(self, builder, object, sig_name, handler_name, conn_object, flags, target): handler = None h_name_internal = "_sh_" + handler_name.replace(" ", "_") if (hasattr(target, h_name_internal)): handler = getattr(target, h_name_internal) else: handler = eval(handler_name) object.connect(sig_name, handler) def purge_builder_content(self): for name in self.__builder_obj_names: o = self.__dict__[name] if (isinstance(o, Gtk.Widget)): o.destroy() del self.__dict__[name] del self.__builder_obj_names # Signal Handlers ########################################################## def _sh_progress_control(self, progress, fraction): # if not hasattr(self, 'song_duration'): # return if (self.plugin.song_duration != 0): self.shell.props.shell_player.set_playing_time( self.plugin.song_duration * fraction) def _sh_bigger_cover(self, cover, x, y, key, tooltip): return self.show_cover_tooltip(tooltip)
class AltToolbarShared(AltToolbarBase): """ shared components for the compact and headerbar toolbar types """ def __init__(self): """ Initialises the object. """ super(AltToolbarShared, self).__init__() # Prepare Album Art Displaying self.album_art_db = GObject.new(RB.ExtDB, name="album-art") what, width, height = Gtk.icon_size_lookup(Gtk.IconSize.SMALL_TOOLBAR) self.icon_width = width self.cover_pixbuf = None self._controllers = {} self._tooltip_exceptions = ['album_cover'] self._moved_controls = [] def initialise(self, plugin): super(AltToolbarShared, self).initialise(plugin) ui = rb.find_plugin_file(plugin, 'ui/alttoolbar.ui') builder = Gtk.Builder() builder.add_from_file(ui) self.load_builder_content(builder) self.connect_builder_content(builder) self._controllers['generic'] = AltGenericController(self) # every potential source should have its own controller - we use this to # categorise the source and provide specific capability for inherited classes # where a controller is not specified then a generic controller is used # i.e. use add_controller method to add a controller self.add_controller(AltMusicLibraryController(self)) self.add_controller(AltSoundCloudController(self)) self.add_controller(AltCoverArtBrowserController(self)) self.add_controller(AltCoverArtPlaySourceController(self)) self.add_controller(AltQueueController(self)) self.add_controller(AltStandardOnlineController(self)) self.add_controller(AltStandardLocalController(self)) self.add_controller(AltRadioController(self)) self.add_controller(AltLastFMController(self)) self.add_controller(AltPlaylistController(self)) self.add_controller(AltErrorsController(self)) self.add_controller(AltPodcastController(self)) self.add_controller(AltAndroidController(self)) # support RTL for control, icon_name in [(self.prev_button, 'media-skip-backward-symbolic'), (self.play_button, 'media-playback-start-symbolic'), (self.next_button, 'media-skip-forward-symbolic')]: image = control.get_child() icon_name = self.request_rtl_icon(control, icon_name) image.set_from_icon_name(icon_name, image.props.icon_size) # now move current RBDisplayPageTree to listview stack display_tree = self.shell.props.display_page_tree self.display_tree_parent = display_tree.get_parent() self.display_tree_parent.remove(display_tree) self.stack = Gtk.Stack() self.stack.set_transition_type(Gtk.StackTransitionType.SLIDE_LEFT_RIGHT) self.stack.set_transition_duration(1000) image_name = 'view-list-symbolic' box_listview = Gtk.Box() box_listview.pack_start(display_tree, True, True, 0) # box_listview.show_all() self.stack.add_named(box_listview, "listview") self.stack.child_set_property(box_listview, "icon-name", image_name) self.stack.show_all() self.display_tree_parent.pack1(self.stack, True, True) #if 1==2: #self.plugin.enhanced_sidebar: toolbar = self.find(display_tree, 'GtkToolbar', 'by_name') #context = toolbar.get_style_context() #context.add_class('toolbar') box = self.find(toolbar, 'GtkBox', 'by_name') #box.props.margin_top = 2 #box.props.margin_bottom = 0 #box.props.margin_left = 5 context = box.get_style_context() context.add_class('linked') #parent = box.get_parent() #parent.remove(box) #parent_toolbar = toolbar.get_parent() #parent_toolbar.remove(toolbar) #display_tree.attach(box, 0, 10, 1 ,1 ) # child, new-parent, old-parent #self._moved_controls.append((box, display_tree, parent)) #self._moved_controls.append((toolbar, None, parent_toolbar)) # find the actual GtkTreeView in the RBDisplayTree and remove it self.rbtree = self.find(display_tree, 'GtkTreeView', 'by_name') self.rbtreeparent = self.rbtree.get_parent() self.rbtreeparent.remove(self.rbtree) self.sidebar = None def post_initialise(self): super(AltToolbarShared, self).post_initialise() self.volume_button.props.value = self.shell.props.shell_player.props.volume self.volume_button.bind_property("value", self.shell.props.shell_player, "volume", Gio.SettingsBindFlags.DEFAULT) self.volume_button.set_visible(self.plugin.volume_control) self.volume_button.set_relief(Gtk.ReliefStyle.NORMAL) child = self.volume_button.get_child() child.set_margin_left(5) child.set_margin_right(5) if self.plugin.inline_label: self.song_box.remove(self.song_button_label) if self.plugin.compact_progressbar: self.song_progress = SmallProgressBar() else: self.song_progress = SmallScale() self.song_progress.connect('control', self._sh_progress_control) self.song_progress.show_all() self.song_progress_box.pack_start(self.song_progress, False, True, 1) # Bring Builtin Actions to plugin for (a, b) in ((self.play_button, "play"), (self.prev_button, "play-previous"), (self.next_button, "play-next"), (self.repeat_toggle, "play-repeat"), (self.shuffle_toggle, "play-shuffle")): a.set_action_name("app." + b) if b == "play-repeat" or b == "play-shuffle": # for some distros you need to set the target_value # for others this would actually disable the action # so work around this by testing if the action is disabled # then reset the action a.set_action_target_value(GLib.Variant("b", True)) print(a.get_sensitive()) if not a.get_sensitive(): a.set_detailed_action_name("app." + b) # The Play-Repeat button is subject to the plugins Repeat All/one song capability self._repeat = Repeat(self.shell, self.repeat_toggle) if gtk_version() >= 3.12: self.cover_popover = Gtk.Popover.new(self.album_cover) image = Gtk.Image.new() self.cover_popover.add(image) self._popover_inprogress = 0 self.cover_popover.set_modal(False) self.cover_popover.connect('leave-notify-event', self._on_cover_popover_mouse_over) self.cover_popover.connect('enter-notify-event', self._on_cover_popover_mouse_over) # detect when mouse moves out of the cover image (it has a parent eventbox) self.album_cover_eventbox.connect('leave-notify-event', self._on_cover_popover_mouse_over) self.album_cover_eventbox.connect('enter-notify-event', self._on_cover_popover_mouse_over) def on_startup(self, *args): super(AltToolbarShared, self).on_startup(*args) if self.plugin.enhanced_sidebar: self.sidebar = AltToolbarSidebar(self, self.rbtree) self.sidebar.show_all() self.rbtreeparent.add(self.sidebar) else: self.rbtreeparent.add(self.rbtree) # self.shell.add_widget(self.rbtree, RB.ShellUILocation.SIDEBAR, expand=True, fill=True) def register_moved_control(self, child, old_parent, new_parent=None): """ convenience function to save the GTK child & parents when they are moved. we use this info to cleanup when quitting RB - we need to move stuff back because otherwise there are random crashes due to memory deallocation issues :param child: GTK Widget :param old_parent: original GTK container that the child was moved from :param new_parent: new GTK container that the child was added to (may just have removed without moving) :return: """ # store as a tuple: child, new-parent, old-parent self._moved_controls.append((child, new_parent, old_parent)) def cleanup(self): """ extend :return: """ super(AltToolbarShared, self).cleanup() if self.sidebar: self.sidebar.cleanup() self.display_tree_parent.remove(self.stack) self.display_tree_parent.pack1(self.shell.props.display_page_tree) if self.sidebar: self.rbtreeparent.remove(self.sidebar) # remove our sidebar self.rbtreeparent.add(self.rbtree) # add the original GtkTree view print ("####") # child, new-parent, old-parent for child, new_parent, old_parent in reversed(self._moved_controls): if new_parent: new_parent.remove(child) print (child) print (new_parent) print (old_parent) if isinstance(old_parent, Gtk.Grid): print ("attaching to grid") old_parent.attach(child, 0, 0, 1, 1) else: print ("adding to parent") old_parent.add(child) def add_controller(self, controller): """ register a new controller """ if not controller in self._controllers: self._controllers[controller] = controller def is_controlled(self, source): """ determine if the source has a controller return bool, controller if no specific controller (False) then the generic controller returned """ if source in self._controllers: return True, self._controllers[source] # loop through controllers to find one that is most applicable for controller_type in self._controllers: if self._controllers[controller_type].valid_source(source): return True, self._controllers[controller_type] return False, self._controllers['generic'] def show_cover_tooltip(self, tooltip): if ( self.cover_pixbuf is not None ): if gtk_version() >= 3.12: if self.cover_popover.get_visible(): return False image = self.cover_popover.get_child() image.set_from_pixbuf(self.cover_pixbuf.scale_simple(300, 300, GdkPixbuf.InterpType.HYPER)) self.cover_popover.show_all() else: tooltip.set_icon(self.cover_pixbuf.scale_simple(300, 300, GdkPixbuf.InterpType.HYPER)) return True else: return False def _on_cover_popover_mouse_over(self, widget, eventcrossing): if eventcrossing.type == Gdk.EventType.ENTER_NOTIFY: if self._popover_inprogress == 0: self._popover_inprogress = 1 else: self._popover_inprogress = 2 self._popover_inprogress_count = 0 print ("enter") else: print ("exit") self._popover_inprogress = 3 # print (eventcrossing.type) def delayed(*args): if self._popover_inprogress == 3: self._popover_inprogress_count += 1 if self._popover_inprogress_count < 5: return True self.cover_popover.hide() self._popover_inprogress = 0 return False else: return True if self._popover_inprogress == 1: print ("addding timeout") self._popover_inprogress = 2 GLib.timeout_add(100, delayed) def show_slider(self, visibility): self.song_box.set_visible(visibility) def display_song(self, entry): self.entry = entry self.cover_pixbuf = None self.album_cover.clear() if self.plugin.inline_label: ret = self._inline_progress_label(entry) else: ret = self._combined_progress_label(entry) if ret: key = entry.create_ext_db_key(RB.RhythmDBPropType.ALBUM) self.album_art_db.request(key, self.display_song_album_art_callback, entry) def _inline_progress_label(self, entry): if ( entry is None ): # self.song_button_label.set_text("") self.inline_box.set_visible(False) return False self.inline_box.set_visible(True) stream_title = self.shell.props.db.entry_request_extra_metadata(entry, RB.RHYTHMDB_PROP_STREAM_SONG_TITLE) stream_artist = self.shell.props.db.entry_request_extra_metadata(entry, RB.RHYTHMDB_PROP_STREAM_SONG_ARTIST) def set_labels(title, artist): for child in self.inline_box: self.inline_box.remove(child) self.song_title = Gtk.Label() self.song_title.set_markup(title) self.song_title.set_ellipsize(Pango.EllipsizeMode.END) self.song_title.show() self.inline_box.pack_start(self.song_title, False, True, 0) print (artist) if artist != "" or artist: print ("adding artist") self.song_artist = Gtk.Label() self.song_artist.set_markup(artist) self.song_artist.set_ellipsize(Pango.EllipsizeMode.END) self.song_artist.show() self.inline_box.pack_start(self.song_artist, False, True, 1) if stream_title: print ("stream_title") if stream_artist: artist_markup = "<small>{artist}</small>".format( artist=GLib.markup_escape_text(stream_artist)) else: artist_markup = "" title_markup = "<b>{title}</b>".format( title=GLib.markup_escape_text(stream_title)) set_labels(title_markup, artist_markup) return True album = entry.get_string(RB.RhythmDBPropType.ALBUM) if not album or album == "": print ("album") title_markup = "<b>{title}</b>".format( title=GLib.markup_escape_text(entry.get_string(RB.RhythmDBPropType.TITLE))) artist = entry.get_string(RB.RhythmDBPropType.ARTIST) if artist and artist != "": artist_markup = "<small>{artist}</small>".format( artist=GLib.markup_escape_text(entry.get_string(RB.RhythmDBPropType.ARTIST))) else: artist_markup = "" set_labels(title_markup, artist_markup) return True if self.plugin.playing_label: print ("playing_label") year = entry.get_ulong(RB.RhythmDBPropType.DATE) if year == 0: year = date.today().year else: year = datetime.fromordinal(year).year title_markup = "<b>{album}</b>".format( album=GLib.markup_escape_text(entry.get_string(RB.RhythmDBPropType.ALBUM))) artist_markup = "<small>{genre} - {year}</small>".format( genre=GLib.markup_escape_text(entry.get_string(RB.RhythmDBPropType.GENRE)), year=GLib.markup_escape_text(str(year))) set_labels(title_markup, artist_markup) else: print ("not playing_label") title_markup = "<b>{title}</b>".format( title=GLib.markup_escape_text(entry.get_string(RB.RhythmDBPropType.TITLE))) artist_markup = "<small>{artist}</small>".format( artist=GLib.markup_escape_text(entry.get_string(RB.RhythmDBPropType.ARTIST))) set_labels(title_markup, artist_markup) return True def _combined_progress_label(self, entry): """ utility function to calculate the label to be used when a progress bar has the label above it :param RBEntry """ if ( entry is None ): self.song_button_label.set_label("") return False stream_title = self.shell.props.db.entry_request_extra_metadata(entry, RB.RHYTHMDB_PROP_STREAM_SONG_TITLE) stream_artist = self.shell.props.db.entry_request_extra_metadata(entry, RB.RHYTHMDB_PROP_STREAM_SONG_ARTIST) if stream_title: if stream_artist: markup = "<small><b>{title}</b> {artist}</small>".format( title=GLib.markup_escape_text(stream_title), artist=GLib.markup_escape_text(stream_artist)) else: markup = "<small><b>{title}</b></small>".format( title=GLib.markup_escape_text(stream_title)) self.song_button_label.set_markup(markup) return True album = entry.get_string(RB.RhythmDBPropType.ALBUM) if not album or album == "": self.song_button_label.set_markup("<small><b>{title}</b></small>".format( title=GLib.markup_escape_text(entry.get_string(RB.RhythmDBPropType.TITLE)))) return True if self.plugin.playing_label: year = entry.get_ulong(RB.RhythmDBPropType.DATE) if year == 0: year = date.today().year else: year = datetime.fromordinal(year).year self.song_button_label.set_markup( "<small>{album} - {genre} - {year}</small>".format( album=GLib.markup_escape_text(entry.get_string(RB.RhythmDBPropType.ALBUM)), genre=GLib.markup_escape_text(entry.get_string(RB.RhythmDBPropType.GENRE)), year=GLib.markup_escape_text(str(year)))) else: self.song_button_label.set_markup( "<small><b>{title}</b> {album} - {artist}</small>".format( title=GLib.markup_escape_text(entry.get_string(RB.RhythmDBPropType.TITLE)), album=GLib.markup_escape_text(entry.get_string(RB.RhythmDBPropType.ALBUM)), artist=GLib.markup_escape_text(entry.get_string(RB.RhythmDBPropType.ARTIST)))) return True def display_song_album_art_callback(self, *args): # key, filename, data, entry): """ RBExtDB signal callback to display the album-art """ # rhythmbox 3.2 breaks the API - need to find the parameter with the pixbuf data = None for data in args: if isinstance(data, GdkPixbuf.Pixbuf): break if ( ( data is not None ) and ( isinstance(data, GdkPixbuf.Pixbuf) ) ): self.cover_pixbuf = data scale_cover = self.cover_pixbuf.scale_simple(34, 34, GdkPixbuf.InterpType.HYPER) self.album_cover.set_from_pixbuf(scale_cover) else: self.cover_pixbuf = None self.album_cover.clear() self.album_cover.trigger_tooltip_query() def show_cover(self, visibility): self.album_cover.set_visible(self.plugin.show_album_art) def show_small_bar(self): self.small_bar.show_all() self.inline_box.set_visible(False) def request_rtl_icon(self, control, icon_name): if gtk_version() < 3.12: if control.get_direction() == Gtk.TextDirection.RTL: rtl_name = {"media-playback-start-symbolic":"media-playback-start-rtl-symbolic", "media-skip-forward-symbolic":"media-skip-forward-rtl-symbolic", "media-skip-backward-symbolic":"media-skip-backward-rtl-symbolic"} icon_name = rtl_name[icon_name] return icon_name def play_control_change(self, player, playing): image = self.play_button.get_child() if (playing): if player.get_active_source().can_pause(): icon_name = "media-playback-pause-symbolic" else: icon_name = "media-playback-stop-symbolic" else: icon_name = self.request_rtl_icon(self.play_button, "media-playback-start-symbolic") image.set_from_icon_name(icon_name, image.props.icon_size) # Builder related utility functions... #################################### def load_builder_content(self, builder): if ( not hasattr(self, "__builder_obj_names") ): self.__builder_obj_names = list() for obj in builder.get_objects(): if ( isinstance(obj, Gtk.Buildable) ): name = Gtk.Buildable.get_name(obj).replace(' ', '_') self.__dict__[name] = obj self.__builder_obj_names.append(name) if not self.plugin.show_tooltips and obj.get_has_tooltip(): if not name in self._tooltip_exceptions: obj.set_has_tooltip(False) def connect_builder_content(self, builder): builder.connect_signals_full(self.connect_builder_content_func, self) def connect_builder_content_func(self, builder, object, sig_name, handler_name, conn_object, flags, target): handler = None h_name_internal = "_sh_" + handler_name.replace(" ", "_") if ( hasattr(target, h_name_internal) ): handler = getattr(target, h_name_internal) else: handler = eval(handler_name) object.connect(sig_name, handler) def purge_builder_content(self): for name in self.__builder_obj_names: o = self.__dict__[name] if ( isinstance(o, Gtk.Widget) ): o.destroy() del self.__dict__[name] del self.__builder_obj_names # Signal Handlers ########################################################## def _sh_progress_control(self, progress, fraction): # if not hasattr(self, 'song_duration'): # return if ( self.plugin.song_duration != 0 ): self.shell.props.shell_player.set_playing_time(self.plugin.song_duration * fraction) def _sh_bigger_cover(self, cover, x, y, key, tooltip): return self.show_cover_tooltip(tooltip)
class AltToolbarShared(AltToolbarBase): ''' shared components for the compact and headerbar toolbar types ''' def __init__(self): ''' Initialises the object. ''' super(AltToolbarShared, self).__init__() # Prepare Album Art Displaying self.album_art_db = GObject.new(RB.ExtDB, name="album-art") what, width, height = Gtk.icon_size_lookup(Gtk.IconSize.SMALL_TOOLBAR) self.icon_width = width self.cover_pixbuf = None def initialise(self, plugin): super(AltToolbarShared, self).initialise(plugin) ui = rb.find_plugin_file(plugin, 'ui/alttoolbar.ui') builder = Gtk.Builder() builder.add_from_file(ui) self.load_builder_content(builder) self.connect_builder_content(builder) def post_initialise(self): self.volume_button.bind_property("value", self.shell.props.shell_player, "volume", Gio.SettingsBindFlags.DEFAULT) self.volume_button.props.value = self.shell.props.shell_player.props.volume self.volume_button.set_visible(self.plugin.volume_control) self.volume_button.set_relief(Gtk.ReliefStyle.NORMAL) child = self.volume_button.get_child() child.set_margin_left(5) child.set_margin_right(5) if self.plugin.inline_label: self.song_box.remove(self.song_button_label) if self.plugin.compact_progressbar: self.song_progress = SmallProgressBar() else: self.song_progress = SmallScale() self.song_progress.connect('control', self._sh_progress_control) self.song_progress.show_all() self.song_progress_box.pack_start(self.song_progress, False, True, 1) # Bring Builtin Actions to plugin for (a, b) in ((self.play_button, "play"), (self.prev_button, "play-previous"), (self.next_button, "play-next"), (self.repeat_toggle, "play-repeat"), (self.shuffle_toggle, "play-shuffle")): a.set_action_name("app." + b) if b == "play-repeat" or b == "play-shuffle": # for some distros you need to set the target_value # for others this would actually disable the action # so work around this by testing if the action is disabled # then reset the action a.set_action_target_value(GLib.Variant("b", True)) print(a.get_sensitive()) if not a.get_sensitive(): a.set_detailed_action_name("app." + b) if gtk_version() >= 3.12: self.cover_popover = Gtk.Popover.new(self.album_cover) image = Gtk.Image.new() self.cover_popover.add(image) def show_cover_tooltip(self, tooltip): if ( self.cover_pixbuf is not None ): if gtk_version() >= 3.12: if self.cover_popover.get_visible(): return False image = self.cover_popover.get_child() image.set_from_pixbuf(self.cover_pixbuf.scale_simple(300, 300, GdkPixbuf.InterpType.HYPER)) self.cover_popover.show_all() else: tooltip.set_icon(self.cover_pixbuf.scale_simple(300, 300, GdkPixbuf.InterpType.HYPER)) return True else: return False def show_slider(self, visibility): self.song_box.set_visible(visibility) def display_song(self, entry): self.entry = entry self.cover_pixbuf = None self.album_cover.clear() if self.plugin.inline_label: ret = self._inline_progress_label(entry) else: ret = self._combined_progress_label(entry) if ret: key = entry.create_ext_db_key(RB.RhythmDBPropType.ALBUM) self.album_art_db.request(key, self.display_song_album_art_callback, entry) def _inline_progress_label(self, entry): if ( entry is None ): # self.song_button_label.set_text("") self.inline_box.set_visible(False) return False self.inline_box.set_visible(True) stream_title = self.shell.props.db.entry_request_extra_metadata(entry, RB.RHYTHMDB_PROP_STREAM_SONG_TITLE) stream_artist = self.shell.props.db.entry_request_extra_metadata(entry, RB.RHYTHMDB_PROP_STREAM_SONG_ARTIST) def set_labels(title, artist): for child in self.inline_box: self.inline_box.remove(child) self.song_title = Gtk.Label() self.song_title.set_markup(title) self.song_title.set_ellipsize(Pango.EllipsizeMode.END) self.song_title.show() self.inline_box.pack_start(self.song_title, False, True, 0) print (artist) if artist != "" or artist: print ("adding artist") self.song_artist = Gtk.Label() self.song_artist.set_markup(artist) self.song_artist.set_ellipsize(Pango.EllipsizeMode.END) self.song_artist.show() self.inline_box.pack_start(self.song_artist, False, True, 1) if stream_title: print ("stream_title") if stream_artist: artist_markup = "<small>{artist}</small>".format( artist=GLib.markup_escape_text(stream_artist)) else: artist_markup = "" title_markup = "<b>{title}</b>".format( title=GLib.markup_escape_text(stream_title)) set_labels(title_markup, artist_markup) return True album = entry.get_string(RB.RhythmDBPropType.ALBUM) if not album or album == "": print ("album") title_markup = "<b>{title}</b>".format( title=GLib.markup_escape_text(entry.get_string(RB.RhythmDBPropType.TITLE))) artist = entry.get_string(RB.RhythmDBPropType.ARTIST) if artist and artist != "": artist_markup= "<small>{artist}</small>".format( artist=GLib.markup_escape_text(entry.get_string(RB.RhythmDBPropType.ARTIST))) else: artist_markup = "" set_labels(title_markup, artist_markup) return True if self.plugin.playing_label: print ("playing_label") year = entry.get_ulong(RB.RhythmDBPropType.DATE) if year == 0: year = date.today().year else: year = datetime.fromordinal(year).year title_markup = "<b>{album}</b>".format( album=GLib.markup_escape_text(entry.get_string(RB.RhythmDBPropType.ALBUM))) artist_markup = "<small>{genre} - {year}</small>".format( genre=GLib.markup_escape_text(entry.get_string(RB.RhythmDBPropType.GENRE)), year=GLib.markup_escape_text(str(year))) set_labels(title_markup, artist_markup) else: print ("not playing_label") title_markup = "<b>{title}</b>".format( title=GLib.markup_escape_text(entry.get_string(RB.RhythmDBPropType.TITLE))) artist_markup= "<small>{artist}</small>".format( artist=GLib.markup_escape_text(entry.get_string(RB.RhythmDBPropType.ARTIST))) set_labels(title_markup, artist_markup) return True def _combined_progress_label(self, entry): ''' utility function to calculate the label to be used when a progress bar has the label above it :param RBEntry ''' if ( entry is None ): self.song_button_label.set_text("") return False stream_title = self.shell.props.db.entry_request_extra_metadata(entry, RB.RHYTHMDB_PROP_STREAM_SONG_TITLE) stream_artist = self.shell.props.db.entry_request_extra_metadata(entry, RB.RHYTHMDB_PROP_STREAM_SONG_ARTIST) if stream_title: if stream_artist: markup = "<small><b>{title}</b> {artist}</small>".format( title=GLib.markup_escape_text(stream_title), artist=GLib.markup_escape_text(stream_artist)) else: markup = "<small><b>{title}</b></small>".format( title=GLib.markup_escape_text(stream_title)) self.song_button_label.set_markup(markup) return True album = entry.get_string(RB.RhythmDBPropType.ALBUM) if not album or album == "": self.song_button_label.set_markup("<small><b>{title}</b></small>".format( title=GLib.markup_escape_text(entry.get_string(RB.RhythmDBPropType.TITLE)))) return True if self.plugin.playing_label: year = entry.get_ulong(RB.RhythmDBPropType.DATE) if year == 0: year = date.today().year else: year = datetime.fromordinal(year).year self.song_button_label.set_markup( "<small>{album} - {genre} - {year}</small>".format( album=GLib.markup_escape_text(entry.get_string(RB.RhythmDBPropType.ALBUM)), genre=GLib.markup_escape_text(entry.get_string(RB.RhythmDBPropType.GENRE)), year=GLib.markup_escape_text(str(year)))) else: self.song_button_label.set_markup( "<small><b>{title}</b> {album} - {artist}</small>".format( title=GLib.markup_escape_text(entry.get_string(RB.RhythmDBPropType.TITLE)), album=GLib.markup_escape_text(entry.get_string(RB.RhythmDBPropType.ALBUM)), artist=GLib.markup_escape_text(entry.get_string(RB.RhythmDBPropType.ARTIST)))) return True def display_song_album_art_callback(self, *args): # key, filename, data, entry): ''' RBExtDB signal callback to display the album-art ''' # rhythmbox 3.2 breaks the API - need to find the parameter with the pixbuf data = None for data in args: if isinstance(data, GdkPixbuf.Pixbuf): break if ( ( data is not None ) and ( isinstance(data, GdkPixbuf.Pixbuf) ) ): self.cover_pixbuf = data scale_cover = self.cover_pixbuf.scale_simple(34, 34, GdkPixbuf.InterpType.HYPER) self.album_cover.set_from_pixbuf(scale_cover) else: self.cover_pixbuf = None self.album_cover.clear() self.album_cover.trigger_tooltip_query() def show_cover(self, visibility): self.album_cover.set_visible(self.plugin.show_album_art) def show_small_bar(self): self.small_bar.show_all() self.inline_box.set_visible(False) def play_control_change(self, player, playing): image = self.play_button.get_child() if (playing): if player.get_active_source().can_pause(): icon_name = "media-playback-pause-symbolic" else: icon_name = "media-playback-stop-symbolic" else: icon_name = "media-playback-start-symbolic" image.set_from_icon_name(icon_name, image.props.icon_size) # Builder related utility functions... #################################### def load_builder_content(self, builder): if ( not hasattr(self, "__builder_obj_names") ): self.__builder_obj_names = list() for obj in builder.get_objects(): if ( isinstance(obj, Gtk.Buildable) ): name = Gtk.Buildable.get_name(obj).replace(' ', '_') self.__dict__[name] = obj self.__builder_obj_names.append(name) def connect_builder_content(self, builder): builder.connect_signals_full(self.connect_builder_content_func, self) def connect_builder_content_func(self, builder, object, sig_name, handler_name, conn_object, flags, target): handler = None h_name_internal = "_sh_" + handler_name.replace(" ", "_") if ( hasattr(target, h_name_internal) ): handler = getattr(target, h_name_internal) else: handler = eval(handler_name) object.connect(sig_name, handler) def purge_builder_content(self): for name in self.__builder_obj_names: o = self.__dict__[name] if ( isinstance(o, Gtk.Widget) ): o.destroy() del self.__dict__[name] del self.__builder_obj_names # Signal Handlers ########################################################## def _sh_progress_control(self, progress, fraction): #if not hasattr(self, 'song_duration'): # return if ( self.plugin.song_duration != 0 ): self.shell.props.shell_player.set_playing_time(self.plugin.song_duration * fraction) def _sh_bigger_cover(self, cover, x, y, key, tooltip): return self.show_cover_tooltip(tooltip)