From 1660f26fa5220b7d468632d59181ee29e7789c94 Mon Sep 17 00:00:00 2001 From: Martin Wagner Date: Fri, 23 Apr 2021 21:29:46 +0200 Subject: [PATCH] avoid multiple implementations of simple mpd commands --- bin/mpdevil | 254 +++++++++++++++++++++------------------------------- 1 file changed, 104 insertions(+), 150 deletions(-) diff --git a/bin/mpdevil b/bin/mpdevil index efe9041..6aa7fd6 100755 --- a/bin/mpdevil +++ b/bin/mpdevil @@ -2811,18 +2811,19 @@ class PlaylistWindow(Gtk.Box): self._back_to_current_song_button=Gtk.Button( image=AutoSizedIcon("go-previous-symbolic", "icon-size-sec", self._settings), tooltip_text=_("Scroll to current song"), - relief=Gtk.ReliefStyle.NONE + relief=Gtk.ReliefStyle.NONE, + can_focus=False ) - self._back_to_current_song_button.set_can_focus(False) style_context=self._back_to_current_song_button.get_style_context() style_context.add_provider(provider, 600) - self._clear_button=Gtk.Button( + clear_button=Gtk.Button( image=AutoSizedIcon("edit-clear-symbolic", "icon-size-sec", self._settings), tooltip_text=_("Clear playlist"), - relief=Gtk.ReliefStyle.NONE + relief=Gtk.ReliefStyle.NONE, + action_name="mpd.clear", + can_focus=False ) - self._clear_button.set_can_focus(False) - style_context=self._clear_button.get_style_context() + style_context=clear_button.get_style_context() style_context.add_class("destructive-action") style_context.add_provider(provider, 600) @@ -2877,7 +2878,7 @@ class PlaylistWindow(Gtk.Box): action_bar.pack_start(self._playlist_info) audio.set_margin_end(3) audio.set_margin_start(12) - action_bar.pack_end(self._clear_button) + action_bar.pack_end(clear_button) action_bar.pack_end(audio) # song popover @@ -2892,7 +2893,6 @@ class PlaylistWindow(Gtk.Box): self._row_deleted=self._store.connect("row-deleted", self._on_row_deleted) self._row_inserted=self._store.connect("row-inserted", self._on_row_inserted) self._back_to_current_song_button.connect("clicked", self._on_back_to_current_song_button_clicked) - self._clear_button.connect("clicked", self._on_clear_button_clicked) self._client.emitter.connect("playlist_changed", self._on_playlist_changed) self._client.emitter.connect("current_song_changed", self._on_song_changed) @@ -3059,19 +3059,14 @@ class PlaylistWindow(Gtk.Box): break self._scroll_to_selected_title() - def _on_clear_button_clicked(self, *args): - self._client.clear() - def _on_disconnected(self, *args): self._treeview.set_sensitive(False) self._back_to_current_song_button.set_sensitive(False) - self._clear_button.set_sensitive(False) self._song_popover.popdown() self._clear() def _on_reconnected(self, *args): self._back_to_current_song_button.set_sensitive(True) - self._clear_button.set_sensitive(True) self._treeview.set_sensitive(True) def _on_show_info(self, *args): @@ -3179,27 +3174,26 @@ class PlaybackControl(Gtk.ButtonBox): self._play_icon=AutoSizedIcon("media-playback-start-symbolic", "icon-size", self._settings) self._pause_icon=AutoSizedIcon("media-playback-pause-symbolic", "icon-size", self._settings) self._play_button=Gtk.Button(image=self._play_icon) + self._play_button.set_action_name("mpd.toggle-play") self._play_button.set_can_focus(False) self._stop_button=Gtk.Button(image=AutoSizedIcon("media-playback-stop-symbolic", "icon-size", self._settings)) + self._stop_button.set_property("no-show-all", not(self._settings.get_boolean("show-stop"))) + self._stop_button.set_action_name("mpd.stop") self._stop_button.set_can_focus(False) self._prev_button=Gtk.Button(image=AutoSizedIcon("media-skip-backward-symbolic", "icon-size", self._settings)) + self._prev_button.set_action_name("mpd.prev") self._prev_button.set_can_focus(False) self._next_button=Gtk.Button(image=AutoSizedIcon("media-skip-forward-symbolic", "icon-size", self._settings)) + self._next_button.set_action_name("mpd.next") self._next_button.set_can_focus(False) # connect - self._play_button.connect("clicked", self._on_play_clicked) - self._stop_button.connect("clicked", self._on_stop_clicked) - self._stop_button.set_property("no-show-all", not(self._settings.get_boolean("show-stop"))) - self._prev_button.connect("clicked", self._on_prev_clicked) - self._next_button.connect("clicked", self._on_next_clicked) self._settings.connect("notify::mini-player", self._on_mini_player) self._settings.connect("changed::show-stop", self._on_show_stop_changed) self._client.emitter.connect("state", self._on_state) self._client.emitter.connect("playlist_changed", self._refresh_tooltips) self._client.emitter.connect("current_song_changed", self._refresh_tooltips) self._client.emitter.connect("disconnected", self._on_disconnected) - self._client.emitter.connect("reconnected", self._on_reconnected) # packing self.pack_start(self._prev_button, True, True, 0) @@ -3221,40 +3215,18 @@ class PlaybackControl(Gtk.ButtonBox): self._prev_button.set_tooltip_text("") self._next_button.set_tooltip_text("") - def _on_play_clicked(self, widget): - self._client.toggle_play() - - def _on_stop_clicked(self, widget): - self._client.stop() - - def _on_prev_clicked(self, widget): - self._client.previous() - - def _on_next_clicked(self, widget): - self._client.next() - def _on_state(self, emitter, state): if state == "play": self._play_button.set_image(self._pause_icon) - self._prev_button.set_sensitive(True) - self._next_button.set_sensitive(True) elif state == "pause": self._play_button.set_image(self._play_icon) - self._prev_button.set_sensitive(True) - self._next_button.set_sensitive(True) else: self._play_button.set_image(self._play_icon) - self._prev_button.set_sensitive(False) - self._next_button.set_sensitive(False) def _on_disconnected(self, *args): - self.set_sensitive(False) self._prev_button.set_tooltip_text("") self._next_button.set_tooltip_text("") - def _on_reconnected(self, *args): - self.set_sensitive(True) - def _on_mini_player(self, obj, typestring): self._on_show_stop_changed() @@ -3403,113 +3375,109 @@ class OutputPopover(Gtk.Popover): else: self._client.disableoutput(out_id) -class PlaybackOptions(Gtk.Box): +class VolumeButton(Gtk.VolumeButton): def __init__(self, client, settings): - super().__init__(spacing=6) + super().__init__(use_symbolic=True, size=settings.get_gtk_icon_size("icon-size"), can_focus=False) self._client=client self._settings=settings self._popover=None - - # widgets - icons={} - for icon_name in ("media-playlist-shuffle-symbolic","media-playlist-repeat-symbolic", - "org.mpdevil.mpdevil-single-symbolic","org.mpdevil.mpdevil-consume-symbolic"): - icons[icon_name]=AutoSizedIcon(icon_name, "icon-size", self._settings) - self._random_button=Gtk.ToggleButton(image=icons["media-playlist-shuffle-symbolic"], tooltip_text=_("Random mode")) - self._random_button.set_can_focus(False) - self._repeat_button=Gtk.ToggleButton(image=icons["media-playlist-repeat-symbolic"], tooltip_text=_("Repeat mode")) - self._repeat_button.set_can_focus(False) - self._single_button=Gtk.ToggleButton(image=icons["org.mpdevil.mpdevil-single-symbolic"], tooltip_text=_("Single mode")) - self._single_button.set_can_focus(False) - self._consume_button=Gtk.ToggleButton(image=icons["org.mpdevil.mpdevil-consume-symbolic"], tooltip_text=_("Consume mode")) - self._consume_button.set_can_focus(False) - self._volume_button=Gtk.VolumeButton(use_symbolic=True, size=self._settings.get_gtk_icon_size("icon-size")) - self._volume_button.set_can_focus(False) - self._adj=self._volume_button.get_adjustment() + self._adj=self.get_adjustment() self._adj.set_step_increment(0.05) self._adj.set_page_increment(0.1) self._adj.set_upper(0) # do not allow volume change by user when MPD has not yet reported volume (no output enabled/avail) # connect - self._random_button_toggled=self._random_button.connect("toggled", self._set_option, "random") - self._repeat_button_toggled=self._repeat_button.connect("toggled", self._set_option, "repeat") - self._single_button_toggled=self._single_button.connect("toggled", self._set_option, "single") - self._consume_button_toggled=self._consume_button.connect("toggled", self._set_option, "consume") - self._volume_button_changed=self._volume_button.connect("value-changed", self._set_volume) - self._repeat_changed=self._client.emitter.connect("repeat", self._repeat_refresh) - self._random_changed=self._client.emitter.connect("random", self._random_refresh) - self._single_changed=self._client.emitter.connect("single", self._single_refresh) - self._consume_changed=self._client.emitter.connect("consume", self._consume_refresh) - self._volume_changed=self._client.emitter.connect("volume_changed", self._volume_refresh) - self._single_button.connect("button-press-event", self._on_single_button_press_event) - self._volume_button.connect("button-press-event", self._on_volume_button_press_event) + self._changed=self.connect("value-changed", self._set_volume) + self._client.emitter.connect("volume_changed", self._refresh) self._client.emitter.connect("disconnected", self._on_disconnected) self._client.emitter.connect("reconnected", self._on_reconnected) - self._settings.connect("notify::mini-player", self._on_mini_player) + self.connect("button-press-event", self._on_button_press_event) self._settings.connect("changed::icon-size", self._on_icon_size_changed) - # packing - self._button_box=Gtk.ButtonBox(layout_style=Gtk.ButtonBoxStyle.EXPAND) - self._button_box.pack_start(self._repeat_button, True, True, 0) - self._button_box.pack_start(self._random_button, True, True, 0) - self._button_box.pack_start(self._single_button, True, True, 0) - self._button_box.pack_start(self._consume_button, True, True, 0) - self.pack_start(self._button_box, True, True, 0) - self.pack_start(self._volume_button, True, True, 0) - - def _set_option(self, widget, option): - func=getattr(self._client, option) - if widget.get_active(): - func("1") - else: - func("0") - def _set_volume(self, widget, value): self._client.setvol(str(int(value*100))) - def _repeat_refresh(self, emitter, val): - self._repeat_button.handler_block(self._repeat_button_toggled) - self._repeat_button.set_active(val) - self._repeat_button.handler_unblock(self._repeat_button_toggled) - - def _random_refresh(self, emitter, val): - self._random_button.handler_block(self._random_button_toggled) - self._random_button.set_active(val) - self._random_button.handler_unblock(self._random_button_toggled) - - def _single_refresh(self, emitter, val): - self._single_button.handler_block(self._single_button_toggled) - if val == "1": - self._single_button.get_style_context().remove_class("destructive-action") - self._single_button.set_active(True) - elif val == "oneshot": - self._single_button.get_style_context().add_class("destructive-action") - self._single_button.set_active(False) - else: - self._single_button.get_style_context().remove_class("destructive-action") - self._single_button.set_active(False) - self._single_button.handler_unblock(self._single_button_toggled) - - def _consume_refresh(self, emitter, val): - self._consume_button.handler_block(self._consume_button_toggled) - self._consume_button.set_active(val) - self._consume_button.handler_unblock(self._consume_button_toggled) - - def _volume_refresh(self, emitter, volume): - self._volume_button.handler_block(self._volume_button_changed) + def _refresh(self, emitter, volume): + self.handler_block(self._changed) if volume < 0: - self._volume_button.set_value(0) + self.set_value(0) self._adj.set_upper(0) else: self._adj.set_upper(1) - self._volume_button.set_value(volume/100) - self._volume_button.handler_unblock(self._volume_button_changed) + self.set_value(volume/100) + self.handler_unblock(self._changed) - def _on_volume_button_press_event(self, widget, event): + def _on_button_press_event(self, widget, event): if event.button == 3 and event.type == Gdk.EventType.BUTTON_PRESS: - self._popover=OutputPopover(self._client, self._volume_button) + self._popover=OutputPopover(self._client, self) self._popover.popup() + def _on_reconnected(self, *args): + self.set_sensitive(True) + + def _on_disconnected(self, *args): + self.set_sensitive(False) + self._refresh(None, -1) + if self._popover is not None: + self._popover.destroy() + self._popover=None + + def _on_icon_size_changed(self, *args): + self.set_property("size", self._settings.get_gtk_icon_size("icon-size")) + +class PlaybackOptions(Gtk.ButtonBox): + def __init__(self, client, settings): + super().__init__(layout_style=Gtk.ButtonBoxStyle.EXPAND) + self._client=client + self._settings=settings + + # buttons + self._buttons={} + data=( + ("random", "media-playlist-shuffle-symbolic", _("Random mode")), + ("repeat", "media-playlist-repeat-symbolic", _("Repeat mode")), + ("single", "org.mpdevil.mpdevil-single-symbolic", _("Single mode")), + ("consume", "org.mpdevil.mpdevil-consume-symbolic", _("Consume mode")), + ) + for name, icon, tooltip in data: + self._buttons[name]=Gtk.ToggleButton(image=AutoSizedIcon(icon, "icon-size", self._settings), + tooltip_text=tooltip, can_focus=False, action_name="mpd."+name) + + # connect + self._client.emitter.connect("repeat", self._repeat_refresh) + self._client.emitter.connect("random", self._random_refresh) + self._client.emitter.connect("single", self._single_refresh) + self._client.emitter.connect("consume", self._consume_refresh) + self._buttons["single"].connect("button-press-event", self._on_single_button_press_event) + self._client.emitter.connect_after("disconnected", self._on_disconnected) # connect "after" to ensure all mpd actions are disabled + self._settings.connect("notify::mini-player", self._on_mini_player) + + # packing + self.pack_start(self._buttons["repeat"], True, True, 0) + self.pack_start(self._buttons["random"], True, True, 0) + self.pack_start(self._buttons["single"], True, True, 0) + self.pack_start(self._buttons["consume"], True, True, 0) + + def _repeat_refresh(self, emitter, val): + self._buttons["repeat"].set_active(val) + + def _random_refresh(self, emitter, val): + self._buttons["random"].set_active(val) + + def _single_refresh(self, emitter, val): + if val == "1": + self._buttons["single"].get_style_context().remove_class("destructive-action") + self._buttons["single"].set_active(True) + elif val == "oneshot": + self._buttons["single"].get_style_context().add_class("destructive-action") + self._buttons["single"].set_active(False) + else: + self._buttons["single"].get_style_context().remove_class("destructive-action") + self._buttons["single"].set_active(False) + + def _consume_refresh(self, emitter, val): + self._buttons["consume"].set_active(val) + def _on_single_button_press_event(self, widget, event): if event.button == 3 and event.type == Gdk.EventType.BUTTON_PRESS: state=self._client.status()["single"] @@ -3518,38 +3486,19 @@ class PlaybackOptions(Gtk.Box): else: self._client.single("oneshot") - def _on_reconnected(self, *args): - self._repeat_button.set_sensitive(True) - self._random_button.set_sensitive(True) - self._single_button.set_sensitive(True) - self._consume_button.set_sensitive(True) - self._volume_button.set_sensitive(True) - def _on_disconnected(self, *args): - self._repeat_button.set_sensitive(False) - self._random_button.set_sensitive(False) - self._single_button.set_sensitive(False) - self._consume_button.set_sensitive(False) - self._volume_button.set_sensitive(False) self._repeat_refresh(None, False) self._random_refresh(None, False) self._single_refresh(None, "0") self._consume_refresh(None, False) - self._volume_refresh(None, -1) - if self._popover is not None: - self._popover.destroy() - self._popover=None def _on_mini_player(self, obj, typestring): if obj.get_property("mini-player"): - self._button_box.set_property("no-show-all", True) - self._button_box.set_property("visible", False) + self.set_property("no-show-all", True) + self.set_property("visible", False) else: - self._button_box.set_property("no-show-all", False) - self._button_box.show_all() - - def _on_icon_size_changed(self, *args): - self._volume_button.set_property("size", self._settings.get_gtk_icon_size("icon-size")) + self.set_property("no-show-all", False) + self.show_all() ################### # MPD gio actions # @@ -3758,8 +3707,6 @@ class MainWindow(Gtk.ApplicationWindow): self._profiles_action=Gio.SimpleAction.new_stateful("profiles", GLib.VariantType.new("i"), GLib.Variant("i", 0)) self._profiles_action.connect("change-state", self._on_profiles) self.add_action(self._profiles_action) - self._mpd_action_group=MPDActionGroup(self._client) - self.insert_action_group("mpd", self._mpd_action_group) # shortcuts shortcuts_window=ShortcutsWindow() @@ -3778,6 +3725,7 @@ class MainWindow(Gtk.ApplicationWindow): playback_control=PlaybackControl(self._client, self._settings) seek_bar=SeekBar(self._client) playback_options=PlaybackOptions(self._client, self._settings) + volume_button=VolumeButton(self._client, self._settings) connection_notify=ConnectionNotify(self._client, self._settings) # menu @@ -3809,6 +3757,7 @@ class MainWindow(Gtk.ApplicationWindow): action_bar.pack_start(playback_control) action_bar.pack_start(seek_bar) action_bar.pack_start(playback_options) + action_bar.pack_start(volume_button) # connect self._settings.connect("changed::profiles", self._refresh_profiles_menu) @@ -3959,7 +3908,11 @@ class MainWindow(Gtk.ApplicationWindow): self.lookup_action(action).set_enabled(False) def _on_search_focus_changed(self, obj, focus): - self._mpd_action_group.lookup_action("toggle-play").set_enabled(not(focus)) + app=self.get_application() + if focus: + app.set_accels_for_action("mpd.toggle-play", []) + else: + app.set_accels_for_action("mpd.toggle-play", ["space"]) def _on_size_allocate(self, widget, rect): if not self.is_maximized() and not self._settings.get_property("mini-player"): @@ -4021,6 +3974,7 @@ class mpdevil(Gtk.Application): if not self._window: # allow just one instance self._window=MainWindow(self, self._client, self._settings) self._window.connect("delete-event", self._on_delete_event) + self._window.insert_action_group("mpd", MPDActionGroup(self._client)) # accelerators action_accels=( ("app.quit", ["q"]),("win.mini-player", ["m"]),("win.help", ["F1"]),("win.menu", ["F10"]),