diff --git a/#prefs3.ui# b/#prefs3.ui# new file mode 100644 index 0000000..dbe26cb --- /dev/null +++ b/#prefs3.ui# @@ -0,0 +1,1232 @@ + + + + + + 100 + 1 + 10 + + + 500 + 1 + 10 + + + True + True + + + True + True + + + True + False + + + + True + False + 15 + 15 + 15 + 15 + 15 + 15 + 10 + True + + + True + False + start + <b>Max widget width</b> +<span size="small"><i>0 to disable</i></span> + True + + + 0 + 0 + + + + + True + True + end + 0 + max_widget_width + + + 0 + 0 + + + + + True + False + start + Track label + + + + + + 0 + 1 + + + + + + True + False + True + + + track-label-sep + True + True + center + + + + 0 + 0 + + + + + track-label-start + True + False + start + + + + 0 + 0 + + + + + track-label-end + True + False + end + + + + 0 + 0 + + + + + 0 + 2 + + + + + True + False + start + vertical + + + True + True + True + https://github.com/cliffniff/media-controls/issues + + + True + False + 5 + + + True + False + mail-mark-junk-symbolic + + + False + True + 0 + + + + + True + False + Report a issue + + + False + True + 1 + + + + + + + False + True + 0 + + + + + True + True + True + https://github.com/cliffniff/media-controls/blob/main/README.md + + + True + False + 5 + + + True + False + go-home-symbolic + + + False + True + 0 + + + + + True + False + Extension home page + + + False + True + 1 + + + + + + + False + True + 1 + + + + + 0 + 4 + + + + + True + False + end + True + vertical + + + True + False + 10 + 10 + + + False + True + 0 + + + + + True + True + + + + True + False + end + 10 + 10 + 10 + 10 + 10 + 10 + True + 10 + 5 + + + True + False + start + Now, the extension does not update itself every <i>x</i> seconds. It watches for changes in the media player and updates itself. + True + True + 0 + + + 1 + 6 + + + + + True + False + start + You can switch on/off individual control icons + 0 + + + 1 + 1 + + + + + -1 + 0 + True + False + start + start + You can choose which parts of the label are visible. +ex. track name, artist + True + 0 + + + 1 + 2 + + + + + True + False + start + Better player icon and name recognition + True + 0 + + + 1 + 3 + + + + + True + False + start + New track information menu which can be opened with a mouse action + True + 0 + + + 1 + 4 + + + + + True + False + start + Left double click, Right double click, Scroll up, Scroll down and Mouse hover added for mouse actions. + True + 0 + + + 1 + 5 + + + + + True + False + center + center + 16 + dialog-information-symbolic + + + 0 + 0 + + + + + True + False + center + start + 16 + pan-end + + + 0 + 1 + + + + + True + False + center + start + 16 + pan-end + + + 0 + 2 + + + + + True + False + center + start + 16 + pan-end + + + 0 + 3 + + + + + True + False + center + start + 16 + pan-end + + + 0 + 4 + + + + + True + False + center + start + 16 + pan-end + + + 0 + 5 + + + + + True + False + center + start + 16 + pan-end + + + 0 + 6 + + + + + True + False + start + center + What's new in v15? + + + + + + + 1 + 0 + + + + + + + True + False + 5 + 5 + 5 + 5 + Release Notes + + + + + + + + + False + True + 1 + + + + + 0 + 3 + + + + + + + + + + + True + False + General + + + False + + + + + True + True + + + True + False + + + + True + False + 15 + 15 + 15 + 15 + 15 + 15 + 10 + True + + + True + False + start + Colored player icon + + + 0 + 3 + + + + + True + True + end + + + 0 + 3 + + + + + Preset + True + True + False + start + True + True + + + + 0 + 6 + + + + + Custom + True + True + False + start + True + preset-radio-btn + + + + 0 + 7 + + + + + True + False + end + + + + 0 + 6 + + + + + True + False + start + 8 + 8 + <b>Seperator characters</b> + True + + + 0 + 5 + + + + + True + True + end + <...> + + + + 0 + 7 + + + + + + True + False + 10 + 10 + 10 + 10 + 8 + True + + + True + True + end + + + 0 + 0 + + + + + True + False + start + Title/Track name + + + 0 + 0 + + + + + True + True + end + + + 0 + 3 + + + + + True + True + end + + + 0 + 4 + + + + + True + False + start + Seperators + + + 0 + 4 + + + + + True + True + end + + + 0 + 1 + + + + + True + False + start + Player icon + + + 0 + 3 + + + + + True + False + start + Player controls + + + 0 + 1 + + + + + True + False + start + Sources menu + + + 0 + 5 + + + + + True + True + end + + + 0 + 5 + + + + + + True + False + 15 + 15 + 15 + 15 + 8 + True + + + True + False + start + Play/pause button + + + 0 + 0 + + + + + True + True + end + + + 0 + 0 + + + + + True + False + start + Previous track button + + + 0 + 1 + + + + + True + False + start + Next track button + + + 0 + 2 + + + + + True + True + end + + + 0 + 1 + + + + + True + True + end + + + 0 + 2 + + + + + 0 + 2 + + + + + 0 + 1 + + + + + True + False + start + <b>Show/hide elements</b> + True + + + 0 + 0 + + + + + True + False + + + 0 + 2 + + + + + True + False + + + 0 + 4 + + + + + + + + + 1 + + + + + True + False + Visibility + + + 1 + False + + + + + True + True + + + True + False + + + + True + False + 15 + 15 + 15 + 15 + 15 + 15 + 10 + True + + + True + False + start + Extension position + + + 0 + 0 + + + + + True + False + start + Extension index + + + 0 + 1 + + + + + True + True + end + 0 + extension_index + + + 0 + 1 + + + + + True + False + start + <b>Element order</b> + True + + + 0 + 2 + + + + + True + False + end + + + + 0 + 0 + + + + + + True + False + 3 + True + + + + + + + + + + + + 0 + 3 + + + + + + + + + 2 + + + + + True + False + Position + + + 2 + False + + + + + True + True + + + True + False + + + + True + False + 15 + 15 + 15 + 15 + 15 + 15 + 10 + True + + + True + False + start + <b>Mouse actions</b> + True + + + 0 + 0 + + + + + True + False + start + center + <b>Cache images</b> + True + + + 0 + 5 + + + + + True + False + start + Media Controls caches album art so they don't need to be redownloaded everytime. You can clear your cache here. + True + 0 + + + 0 + 6 + + + + + + True + False + 10 + + + Clear cache + True + True + True + start + + + + 0 + 0 + + + + + True + False + start + 0 MB + + + 1 + 0 + + + + + True + False + + + 2 + 0 + + + + + 0 + 7 + + + + + + True + False + 5 + True + + + + + + + + + + + + 0 + 1 + + + + + True + True + end + + + 0 + 5 + + + + + True + False + start + Blacklist players + + + 0 + 2 + + + + + True + False + + + 0 + 4 + + + + + True + True + + + + 0 + 3 + + + + + + + + + 3 + + + + + True + False + Other + + + 3 + False + + + + + diff --git a/dbus.js b/dbus.js index de56bb0..3bdb9e7 100644 --- a/dbus.js +++ b/dbus.js @@ -15,8 +15,10 @@ const ifacesXml = ` - - + + + + diff --git a/metadata.json b/metadata.json index a4bd6cf..78f5095 100644 --- a/metadata.json +++ b/metadata.json @@ -1,5 +1,5 @@ { - "_generated": "Generated by SweetTooth, do not edit", + "development": true, "description": "Show controls for the current playing media in the panel", "name": "Media Controls", "settings-schema": "org.gnome.shell.extensions.mediacontrols", diff --git a/player.js b/player.js index fcc876b..f424727 100644 --- a/player.js +++ b/player.js @@ -229,12 +229,10 @@ const Player = GObject.registerClass( if (changed.PlaybackStatus) { this._status = changed.PlaybackStatus; - if (this.isPlaying && !this._active) { - this._extension.activatePlayer(this.menuItem); - } else { - log("Updating player"); - this._extension.updatePlayer(); + if (this.isPlaying && !this._extension.isFixedPlayer && !this._active) { + this._extension.updatePlayer(this.busName); } + this._updateStatusIcons(); } @@ -514,11 +512,7 @@ const Player = GObject.registerClass( style_class: "popup-menu-button", }); - this.infoShuffleButton.connect("button-press-event", () => { - if (typeof this._playerProxy.Shuffle === "boolean") { - this._playerProxy.Shuffle = !this._playerProxy.Shuffle; - } - }); + this.infoShuffleButton.connect("button-press-event", this._toggleShuffle.bind(this)); this.infoShuffleButton.set_child(this.infoShuffleIcon); @@ -532,6 +526,12 @@ const Player = GObject.registerClass( } } + _toggleShuffle() { + if (typeof this._playerProxy.Shuffle === "boolean") { + this._playerProxy.Shuffle = !this._playerProxy.Shuffle; + } + } + _changeLoop() { switch (this._playerProxy.LoopStatus) { case "None": @@ -635,6 +635,18 @@ const Player = GObject.registerClass( this._extension.menu.close(BoxPointer.PopupAnimation.FULL); this.menu.toggle(); break; + case "toggle_loop": + this._changeLoop(); + break; + case "toggle_shuffle": + this._toggleShuffle(); + break; + case "raise": + this._otherProxy.RaiseRemote(); + break; + case "quit": + this._otherProxy.QuitRemote(); + break; default: break; } diff --git a/prefs.js b/prefs.js index 57eba9a..3831a99 100644 --- a/prefs.js +++ b/prefs.js @@ -24,8 +24,12 @@ const mouseActionNamesMap = { pause: "Pause", next: "Next", previous: "Previous", + toggle_loop: "Cycle loop options", + toggle_shuffle: "Toggle shuffle", toggle_menu: "Open sources menu", toggle_info: "Open track information menu", + raise: "Raise player", + quit: "Quit player", }; let mouseActionNameIds = Object.keys(mouseActionNamesMap); @@ -84,7 +88,8 @@ let settings, elementOrderWidgets, trackLabelStart, trackLabelSep, - trackLabelEnd; + trackLabelEnd, + widgetBacklistBox; let elementOrder, trackLabelLock; @@ -172,6 +177,14 @@ const signalHandler = { settings.set_strv("track-label", trackLabelArray); }, + + on_backlist_entry_changed: (entry) => { + let currentBacklistApps = settings.get_strv("backlist-apps"); + currentBacklistApps.push(entry.get_text()); + addToBacklistListBox(entry.get_text()); + settings.set_strv("backlist-apps", currentBacklistApps); + entry.set_text(""); + }, }; const bindSettings = () => { @@ -275,6 +288,7 @@ const initWidgets = () => { elementIds.forEach((element, index) => { let widget = new Gtk.ComboBoxText({ visible: true, + can_focus: false, }); elementIds.forEach((_element) => { @@ -345,6 +359,7 @@ const initWidgets = () => { let widgetCombobox = new Gtk.ComboBoxText({ visible: true, halign: Gtk.Align.END, + can_focus: false, }); mouseActionNameIds.forEach((action) => { @@ -365,6 +380,12 @@ const initWidgets = () => { widgetMouseActionsGrid.attach(widgetCombobox, 1, index, 1, 1); }); + let currentBacklistApps = settings.get_strv("backlist-apps"); + + currentBacklistApps.forEach((app) => { + addToBacklistListBox(app); + }); + (async () => { widgetCacheSize.set_text(await getCacheSize()); })(); @@ -392,6 +413,9 @@ const buildPrefsWidget = () => { trackLabelEnd = builder.get_object("track-label-end"); widgetCacheSize = builder.get_object("cache-size"); widgetElementOrder = builder.get_object("element-order"); + + widgetBacklistBox = builder.get_object("backlist-listbox"); + elementOrderWidgets = []; initWidgets(); bindSettings(); @@ -408,3 +432,32 @@ const getCacheSize = async () => { logError(error); } }; + +const addToBacklistListBox = (app) => { + let box = new Gtk.Box({ + visible: true, + }); + + let label = new Gtk.Label({ + visible: true, + label: app, + hexpand: true, + halign: Gtk.Align.START, + }); + + let deleteButton = Gtk.Button.new_from_icon_name("edit-delete-symbolic", null); + + deleteButton.connect("clicked", (widget) => { + widgetBacklistBox.remove(widget.get_parent().get_parent()); + }); + + if (shellVersion < 40) { + box.pack_start(label, false, false, null); + box.pack_start(deleteButton, false, false, null); + widgetBacklistBox.insert_child(box, -1); + } else { + box.append(label); + box.append(deleteButton); + widgetBacklistBox.append(box); + } +}; diff --git a/prefs3.ui b/prefs3.ui index c6d3349..dbe26cb 100644 --- a/prefs3.ui +++ b/prefs3.ui @@ -1038,7 +1038,7 @@ ex. track name, artist True False - + True False @@ -1074,7 +1074,7 @@ ex. track name, artist 0 - 2 + 5 @@ -1088,7 +1088,7 @@ ex. track name, artist 0 - 3 + 6 @@ -1136,7 +1136,7 @@ ex. track name, artist 0 - 4 + 7 @@ -1167,11 +1167,44 @@ ex. track name, artist True end + + 0 + 5 + + + + + True + False + start + Blacklist players + 0 2 + + + True + False + + + 0 + 4 + + + + + True + True + + + + 0 + 3 + + diff --git a/prefs4.ui b/prefs4.ui index 3fe4818..7a560b1 100644 --- a/prefs4.ui +++ b/prefs4.ui @@ -865,7 +865,7 @@ ex. track name, artist 1 0 - 2 + 5 @@ -877,7 +877,7 @@ ex. track name, artist 0 0 - 3 + 6 @@ -917,7 +917,7 @@ ex. track name, artist 0 - 4 + 7 @@ -944,12 +944,40 @@ ex. track name, artist 1 end + + 0 + 5 + + + + + + start + Blacklist players 0 2 + + + + 0 + 4 + + + + + + 1 + + + 0 + 3 + + + diff --git a/schemas/gschemas.compiled b/schemas/gschemas.compiled index 0ede840..d08e65f 100644 Binary files a/schemas/gschemas.compiled and b/schemas/gschemas.compiled differ diff --git a/schemas/org.gnome.shell.extensions.mediacontrols.gschema.xml b/schemas/org.gnome.shell.extensions.mediacontrols.gschema.xml index 936e1e8..eb880f0 100644 --- a/schemas/org.gnome.shell.extensions.mediacontrols.gschema.xml +++ b/schemas/org.gnome.shell.extensions.mediacontrols.gschema.xml @@ -55,5 +55,8 @@ true + + [] + diff --git a/widget.js b/widget.js index 0137bc9..9356cc0 100644 --- a/widget.js +++ b/widget.js @@ -20,7 +20,7 @@ const MediaControls = GObject.registerClass( super._init(0.5, "Media Controls Extension"); this.setSensitive(false); - this._isFixedPlayer = false; + this.isFixedPlayer = false; this._players = {}; this.dataDir = GLib.get_user_config_dir(); @@ -45,6 +45,32 @@ const MediaControls = GObject.registerClass( this.clutterSettings = Clutter.Settings.get_default(); this.clutterSettings.double_click_time = 200; + this._automaticUpdateToggle = new PopupMenu.PopupSwitchMenuItem( + "Determine player automatically", + true + ); + + this._automaticUpdateToggle.track_hover = false; + + this._automaticUpdateToggle.connect("toggled", (widget, value) => { + this.isFixedPlayer = !value; + this.updatePlayer(); + }); + + // this._automaticUpdateToggle.connect("toggled", (widget, value) => { + // if (value) { + // this._isFixedPlayer = true; + // this.updatePlayer(this.player); + // } else { + // this._isFixedPlayer = false; + // this.updatePlayer(); + // } + // log(this._isFixedPlayer); + // }); + + this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); + this.menu.addMenuItem(this._automaticUpdateToggle); + (async () => { try { this._playersProxy = await createProxy( @@ -114,6 +140,7 @@ const MediaControls = GObject.registerClass( this.settings.extensionIndex, this.settings.extensionPosition ); + this.add_child(this.player.container); this.settings.elementOrder.forEach((element) => { @@ -149,23 +176,27 @@ const MediaControls = GObject.registerClass( log("[MediaControls] Removing widgets"); delete Main.panel.statusArea["media_controls_extension"]; - this.remove_child(this.player.container); + if (this.player) { + this.remove_child(this.player.container); - this.player.dummyContainer.remove_child(this.player.buttonPlayer); + this.player.dummyContainer.remove_child(this.player.buttonPlayer); - this.player.dummyContainer.remove_child(this.player.containerButtonLabel); + this.player.dummyContainer.remove_child(this.player.containerButtonLabel); - this.player.subContainerLabel.remove_child(this.player.labelTitle); - this.player.subContainerLabel.remove_child(this.player.labelSeperatorStart); - this.player.subContainerLabel.remove_child(this.player.labelSeperatorEnd); + this.player.subContainerLabel.remove_child(this.player.labelTitle); + this.player.subContainerLabel.remove_child(this.player.labelSeperatorStart); + this.player.subContainerLabel.remove_child(this.player.labelSeperatorEnd); - this.player.dummyContainer.remove_child(this.player.containerControls); + this.player.dummyContainer.remove_child(this.player.containerControls); - this.player.containerControls.remove_child(this.player.buttonPrev); - this.player.containerControls.remove_child(this.player.buttonPlayPause); - this.player.containerControls.remove_child(this.player.buttonNext); + this.player.containerControls.remove_child(this.player.buttonPrev); + this.player.containerControls.remove_child(this.player.buttonPlayPause); + this.player.containerControls.remove_child(this.player.buttonNext); - this.player.dummyContainer.remove_child(this.player.buttonMenu); + this.player.dummyContainer.remove_child(this.player.buttonMenu); + } else { + this.remove_all_children(); + } } async _addPlayer(busName) { @@ -173,7 +204,10 @@ const MediaControls = GObject.registerClass( let playerObj = await new Player(busName, this); let menuItem = playerObj.menuItem; - menuItem.connect("activate", this.activatePlayer.bind(this)); + menuItem.connect("activate", (menuItem) => { + this.toggleActivatePlayer(menuItem.busName); + }); + this.menu.addMenuItem(menuItem); this._players[busName] = playerObj; @@ -186,19 +220,24 @@ const MediaControls = GObject.registerClass( } _removePlayer(busName) { - this.hidePlayer(busName); + let playerObj = this._players[busName]; + + // Remove menu item from the source menu + this.menu.box.remove_child(playerObj.menuItem); + // Remove track information menu menu + Main.panel.menuManager.removeMenu(playerObj.menu); - this._players[busName].destroy(); + playerObj.destroy(); delete this._players[busName]; } updatePlayer(player = null) { - if (!this.player && this._isFixedPlayer) { - this._isFixedPlayer = false; + if (!this.player && this.isFixedPlayer) { + this.isFixedPlayer = false; } - if (!player && !this._isFixedPlayer) { + if (!player && !this.isFixedPlayer) { log("Automatic determine"); const validPlayers = []; for (let playerName in this._players) { @@ -207,7 +246,6 @@ const MediaControls = GObject.registerClass( log(playerObj.busName, playerObj._status); validPlayers.push(playerObj); if (playerObj.isPlaying) { - log("Playing"); player = playerObj; } } @@ -222,11 +260,13 @@ const MediaControls = GObject.registerClass( if (this.player) { this.player.active = false; this.removeWidgets(); + Gio.bus_unwatch_name(this.playerWatchId); Main.panel.menuManager.removeMenu(this.player.menu); } this.player = typeof player === "string" ? this._players[player] : player; + if (!this.player.dummyContainer) { this.player.initWidgets(); } @@ -241,25 +281,27 @@ const MediaControls = GObject.registerClass( this.playerVanished.bind(this) ); - // this.removeWidgets(); + this.removeWidgets(); this.addWidgets(); this.player.active = true; } else if (!this.player) { log("Removing all"); - this.remove_all_children(); + this.removeWidgets(); } log("[MediaControls] Updated player", player ? player.busName : player); + log("No. of players", Object.values(this._players).length); + log("Fixed player", this.isFixedPlayer); } - activatePlayer(playerItem) { - if (this._isFixedPlayer && playerItem.busName === this.player.busName) { - this._isFixedPlayer = false; + toggleActivatePlayer(busName) { + if (this.isFixedPlayer && this.player && busName === this.player.busName) { + this.fixedPlayer = false; this.updatePlayer(); } else { - this._isFixedPlayer = true; - this.updatePlayer(playerItem.busName); + this.fixedPlayer = true; + this.updatePlayer(busName); } } @@ -267,15 +309,17 @@ const MediaControls = GObject.registerClass( const playerObj = this._players[busName]; if (playerObj) { + // Remove menu item from the source menu this.menu.box.remove_child(playerObj.menuItem); + // Remove track information menu menu Main.panel.menuManager.removeMenu(playerObj.menu); playerObj.hidden = true; - if (this.player && this.player.busName === busName && this._isFixedPlayer) { - this._isFixedPlayer = false; + if (this.player && this.player.busName === busName && this.fixedPlayer) { + this.fixedPlayer = false; this.updatePlayer(); - } else if (this.player && this.player.busName !== busName && this._isFixedPlayer) { + } else if (this.player && this.player.busName !== busName && this.fixedPlayer) { this.updatePlayer(this.player); } else { this.updatePlayer(); @@ -288,7 +332,7 @@ const MediaControls = GObject.registerClass( if (playerObj) { this.menu.addMenuItem(playerObj.menuItem); playerObj.hidden = false; - if (this._isFixedPlayer) { + if (this.isFixedPlayer) { this.updatePlayer(this.player); } else { this.updatePlayer(); @@ -296,9 +340,10 @@ const MediaControls = GObject.registerClass( } } - playerVanished(con, name) { - log("player removed", name); - log(Object.values(this._players).length); + playerVanished(connection, name) { + log("Player Vanished", name); + log("No. of players", Object.values(this._players).length); + if (name === this.player.busName) { Gio.bus_unwatch_name(this.playerWatchId); this._removePlayer(this.player.busName); @@ -309,12 +354,21 @@ const MediaControls = GObject.registerClass( } else { this._removePlayer(name); } - log(Object.values(this._players).length); + log("No. of players", Object.values(this._players).length); } destroy() { super.destroy(); } + + get fixedPlayer() { + return this.isFixedPlayer; + } + + set fixedPlayer(value) { + this.isFixedPlayer = value; + this._automaticUpdateToggle.setToggleState(!value); + } } );