aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRobert Tari <robert@tari.in>2020-08-11 12:20:04 +0200
committerMike Gabriel <mike.gabriel@das-netzwerkteam.de>2020-08-11 21:29:33 +0200
commit11ea05685763cd7a233b56e11cd231c7774f69e1 (patch)
treea5277807f5f415486fb0134dc994e32dd268734d /src
parenta3bc5a97496f357c47ddf069bd8c67af9143d2bf (diff)
downloadayatana-indicator-sound-11ea05685763cd7a233b56e11cd231c7774f69e1.tar.gz
ayatana-indicator-sound-11ea05685763cd7a233b56e11cd231c7774f69e1.tar.bz2
ayatana-indicator-sound-11ea05685763cd7a233b56e11cd231c7774f69e1.zip
Replace x-canonical attributes
Diffstat (limited to 'src')
-rw-r--r--src/gmenuharness/MenuItemMatcher.cpp2
-rw-r--r--src/info-notification.vala172
-rw-r--r--src/sound-menu.vala904
-rw-r--r--src/warn-notification.vala60
4 files changed, 569 insertions, 569 deletions
diff --git a/src/gmenuharness/MenuItemMatcher.cpp b/src/gmenuharness/MenuItemMatcher.cpp
index f39acef..f2d5fe8 100644
--- a/src/gmenuharness/MenuItemMatcher.cpp
+++ b/src/gmenuharness/MenuItemMatcher.cpp
@@ -306,7 +306,7 @@ MenuItemMatcher& MenuItemMatcher::themed_icon(const std::string& iconName, const
MenuItemMatcher& MenuItemMatcher::widget(const string& widget)
{
- return string_attribute("x-canonical-type", widget);
+ return string_attribute("x-ayatana-type", widget);
}
MenuItemMatcher& MenuItemMatcher::pass_through_attribute(const string& actionName, const shared_ptr<GVariant>& value)
diff --git a/src/info-notification.vala b/src/info-notification.vala
index 84987dc..e093aae 100644
--- a/src/info-notification.vala
+++ b/src/info-notification.vala
@@ -21,102 +21,102 @@ using Notify;
public class IndicatorSound.InfoNotification: Notification
{
- protected override Notify.Notification create_notification () {
- return new Notify.Notification (_("Volume"), "", "audio-volume-muted");
- }
+ protected override Notify.Notification create_notification () {
+ return new Notify.Notification (_("Volume"), "", "audio-volume-muted");
+ }
- public void show (VolumeControl.ActiveOutput active_output,
- double volume,
- bool is_high_volume) {
- if (!notify_server_supports ("x-canonical-private-synchronous"))
- return;
+ public void show (VolumeControl.ActiveOutput active_output,
+ double volume,
+ bool is_high_volume) {
+ if (!notify_server_supports ("x-canonical-private-synchronous"))
+ return;
- /* Determine Label */
- unowned string volume_label = get_notification_label (active_output);
+ /* Determine Label */
+ unowned string volume_label = get_notification_label (active_output);
- /* Choose an icon */
- unowned string icon = get_volume_notification_icon (active_output, volume, is_high_volume);
+ /* Choose an icon */
+ unowned string icon = get_volume_notification_icon (active_output, volume, is_high_volume);
- /* Reset the notification */
- var n = _notification;
- n.update (_("Volume"), volume_label, icon);
- n.clear_hints();
- n.set_hint ("x-canonical-non-shaped-icon", "true");
- n.set_hint ("x-canonical-private-synchronous", "true");
- n.set_hint ("x-canonical-value-bar-tint", is_high_volume ? "true" : "false");
- n.set_hint ("value", ((int32)((volume * 100.0) + 0.5)).clamp(0, 100));
- show_notification ();
- }
+ /* Reset the notification */
+ var n = _notification;
+ n.update (_("Volume"), volume_label, icon);
+ n.clear_hints();
+ n.set_hint ("x-canonical-non-shaped-icon", "true");
+ n.set_hint ("x-canonical-private-synchronous", "true");
+ n.set_hint ("x-canonical-value-bar-tint", is_high_volume ? "true" : "false");
+ n.set_hint ("value", ((int32)((volume * 100.0) + 0.5)).clamp(0, 100));
+ show_notification ();
+ }
- private static unowned string get_notification_label (VolumeControl.ActiveOutput active_output) {
+ private static unowned string get_notification_label (VolumeControl.ActiveOutput active_output) {
- switch (active_output) {
- case VolumeControl.ActiveOutput.SPEAKERS:
- return _("Speakers");
- case VolumeControl.ActiveOutput.HEADPHONES:
- return _("Headphones");
- case VolumeControl.ActiveOutput.BLUETOOTH_HEADPHONES:
- return _("Bluetooth headphones");
- case VolumeControl.ActiveOutput.BLUETOOTH_SPEAKER:
- return _("Bluetooth speaker");
- case VolumeControl.ActiveOutput.USB_SPEAKER:
- return _("Usb speaker");
- case VolumeControl.ActiveOutput.USB_HEADPHONES:
- return _("Usb headphones");
- case VolumeControl.ActiveOutput.HDMI_SPEAKER:
- return _("HDMI speaker");
- case VolumeControl.ActiveOutput.HDMI_HEADPHONES:
- return _("HDMI headphones");
- default:
- return "";
- }
- }
+ switch (active_output) {
+ case VolumeControl.ActiveOutput.SPEAKERS:
+ return _("Speakers");
+ case VolumeControl.ActiveOutput.HEADPHONES:
+ return _("Headphones");
+ case VolumeControl.ActiveOutput.BLUETOOTH_HEADPHONES:
+ return _("Bluetooth headphones");
+ case VolumeControl.ActiveOutput.BLUETOOTH_SPEAKER:
+ return _("Bluetooth speaker");
+ case VolumeControl.ActiveOutput.USB_SPEAKER:
+ return _("Usb speaker");
+ case VolumeControl.ActiveOutput.USB_HEADPHONES:
+ return _("Usb headphones");
+ case VolumeControl.ActiveOutput.HDMI_SPEAKER:
+ return _("HDMI speaker");
+ case VolumeControl.ActiveOutput.HDMI_HEADPHONES:
+ return _("HDMI headphones");
+ default:
+ return "";
+ }
+ }
- private static unowned string get_volume_notification_icon (VolumeControl.ActiveOutput active_output,
- double volume,
- bool is_high_volume) {
+ private static unowned string get_volume_notification_icon (VolumeControl.ActiveOutput active_output,
+ double volume,
+ bool is_high_volume) {
- if (!is_high_volume)
- return get_volume_icon (active_output, volume);
+ if (!is_high_volume)
+ return get_volume_icon (active_output, volume);
- switch (active_output) {
- case VolumeControl.ActiveOutput.SPEAKERS:
- case VolumeControl.ActiveOutput.HEADPHONES:
- case VolumeControl.ActiveOutput.BLUETOOTH_HEADPHONES:
- case VolumeControl.ActiveOutput.BLUETOOTH_SPEAKER:
- case VolumeControl.ActiveOutput.USB_SPEAKER:
- case VolumeControl.ActiveOutput.USB_HEADPHONES:
- case VolumeControl.ActiveOutput.HDMI_SPEAKER:
- case VolumeControl.ActiveOutput.HDMI_HEADPHONES:
- return "audio-volume-high";
+ switch (active_output) {
+ case VolumeControl.ActiveOutput.SPEAKERS:
+ case VolumeControl.ActiveOutput.HEADPHONES:
+ case VolumeControl.ActiveOutput.BLUETOOTH_HEADPHONES:
+ case VolumeControl.ActiveOutput.BLUETOOTH_SPEAKER:
+ case VolumeControl.ActiveOutput.USB_SPEAKER:
+ case VolumeControl.ActiveOutput.USB_HEADPHONES:
+ case VolumeControl.ActiveOutput.HDMI_SPEAKER:
+ case VolumeControl.ActiveOutput.HDMI_HEADPHONES:
+ return "audio-volume-high";
- default:
- return "";
- }
- }
+ default:
+ return "";
+ }
+ }
- private static unowned string get_volume_icon (VolumeControl.ActiveOutput active_output,
- double volume)
- {
- switch (active_output) {
- case VolumeControl.ActiveOutput.SPEAKERS:
- case VolumeControl.ActiveOutput.HEADPHONES:
- case VolumeControl.ActiveOutput.BLUETOOTH_HEADPHONES:
- case VolumeControl.ActiveOutput.BLUETOOTH_SPEAKER:
- case VolumeControl.ActiveOutput.USB_SPEAKER:
- case VolumeControl.ActiveOutput.USB_HEADPHONES:
- case VolumeControl.ActiveOutput.HDMI_SPEAKER:
- case VolumeControl.ActiveOutput.HDMI_HEADPHONES:
- if (volume <= 0.0)
- return "audio-volume-muted";
- if (volume <= 0.3)
- return "audio-volume-low";
- if (volume <= 0.7)
- return "audio-volume-medium";
- return "audio-volume-high";
+ private static unowned string get_volume_icon (VolumeControl.ActiveOutput active_output,
+ double volume)
+ {
+ switch (active_output) {
+ case VolumeControl.ActiveOutput.SPEAKERS:
+ case VolumeControl.ActiveOutput.HEADPHONES:
+ case VolumeControl.ActiveOutput.BLUETOOTH_HEADPHONES:
+ case VolumeControl.ActiveOutput.BLUETOOTH_SPEAKER:
+ case VolumeControl.ActiveOutput.USB_SPEAKER:
+ case VolumeControl.ActiveOutput.USB_HEADPHONES:
+ case VolumeControl.ActiveOutput.HDMI_SPEAKER:
+ case VolumeControl.ActiveOutput.HDMI_HEADPHONES:
+ if (volume <= 0.0)
+ return "audio-volume-muted";
+ if (volume <= 0.3)
+ return "audio-volume-low";
+ if (volume <= 0.7)
+ return "audio-volume-medium";
+ return "audio-volume-high";
- default:
- return "";
- }
- }
+ default:
+ return "";
+ }
+ }
}
diff --git a/src/sound-menu.vala b/src/sound-menu.vala
index e0a05a1..957238c 100644
--- a/src/sound-menu.vala
+++ b/src/sound-menu.vala
@@ -19,456 +19,456 @@
public class SoundMenu: Object
{
- public enum DisplayFlags {
- NONE = 0,
- SHOW_MUTE = 1,
- HIDE_INACTIVE_PLAYERS = 2,
- HIDE_PLAYERS = 4,
- GREETER_PLAYERS = 8,
- SHOW_SILENT_MODE = 16,
- HIDE_INACTIVE_PLAYERS_PLAY_CONTROLS = 32,
- ADD_PLAY_CONTROL_INACTIVE_PLAYER = 64
- }
-
- public enum PlayerSectionPosition {
- LABEL = 0,
- PLAYER_CONTROLS = 1,
- PLAYLIST = 2
- }
-
- const string PLAYBACK_ITEM_TYPE = "org.ayatana.unity.playback-item";
-
- public SoundMenu (string? settings_action, DisplayFlags flags) {
- /* A sound menu always has at least two sections: the volume section (this.volume_section)
- * at the start of the menu, and the settings section at the end. Between those two,
- * it has a dynamic amount of player sections, one for each registered player.
- */
-
- this.volume_section = new Menu ();
-
- if ((flags & DisplayFlags.SHOW_MUTE) != 0)
- volume_section.append (_("Mute"), "indicator.mute");
- if ((flags & DisplayFlags.SHOW_SILENT_MODE) != 0) {
- var item = new MenuItem(_("Silent Mode"), "indicator.silent-mode");
- item.set_attribute("x-canonical-type", "s", "org.ayatana.indicator.switch");
- volume_section.append_item(item);
- }
-
- volume_section.append_item (this.create_slider_menu_item (_("Volume"), "indicator.volume(0)", 0.0, 1.0, 0.01,
- "audio-volume-low-zero-panel",
- "audio-volume-high-panel", true));
-
- this.menu = new Menu ();
- this.menu.append_section (null, volume_section);
-
- if (settings_action != null) {
- settings_shown = true;
- this.menu.append (_("Sound Settingsā€¦"), settings_action);
- }
-
- var root_item = new MenuItem (null, "indicator.root");
- root_item.set_attribute ("x-canonical-type", "s", "org.ayatana.indicator.root");
- root_item.set_attribute ("x-canonical-scroll-action", "s", "indicator.scroll");
- root_item.set_attribute ("x-canonical-secondary-action", "s", "indicator.mute");
- root_item.set_attribute ("submenu-action", "s", "indicator.indicator-shown");
- root_item.set_submenu (this.menu);
-
- this.root = new Menu ();
- root.append_item (root_item);
-
- this.hide_players = (flags & DisplayFlags.HIDE_PLAYERS) != 0;
- this.hide_inactive = (flags & DisplayFlags.HIDE_INACTIVE_PLAYERS) != 0;
- this.hide_inactive_player_controls = (flags & DisplayFlags.HIDE_INACTIVE_PLAYERS_PLAY_CONTROLS) != 0;
- this.add_play_button_inactive_player = (flags & DisplayFlags.ADD_PLAY_CONTROL_INACTIVE_PLAYER) != 0;
- this.notify_handlers = new HashTable<MediaPlayer, ulong> (direct_hash, direct_equal);
-
- this.greeter_players = (flags & DisplayFlags.GREETER_PLAYERS) != 0;
- }
-
- ~SoundMenu () {
- if (export_id != 0) {
- bus.unexport_menu_model(export_id);
- export_id = 0;
- }
- }
-
- public void set_default_player (string default_player_id) {
- this.default_player = default_player_id;
- foreach (var player_stored in notify_handlers.get_keys ()) {
- int index = this.find_player_section(player_stored);
- if (index != -1 && player_stored.id == this.default_player) {
- add_player_playback_controls (player_stored, index, true);
- }
- }
- }
-
- DBusConnection? bus = null;
- uint export_id = 0;
-
- public void export (DBusConnection connection, string object_path) {
- bus = connection;
- try {
- export_id = bus.export_menu_model (object_path, this.root);
- } catch (Error e) {
- critical ("%s", e.message);
- }
- }
-
- public bool show_mic_volume {
- get {
- return this.mic_volume_shown;
- }
- set {
- if (value && !this.mic_volume_shown) {
- var slider = this.create_slider_menu_item (_("Microphone Volume"), "indicator.mic-volume", 0.0, 1.0, 0.01,
- "audio-input-microphone-low-zero-panel",
- "audio-input-microphone-high-panel", false);
- volume_section.append_item (slider);
- this.mic_volume_shown = true;
- }
- else if (!value && this.mic_volume_shown) {
- int location = -1;
- while ((location = find_action(this.volume_section, "indicator.mic-volume")) != -1) {
- this.volume_section.remove (location);
- }
- this.mic_volume_shown = false;
- }
- }
- }
-
- public bool show_high_volume_warning {
- get {
- return this.high_volume_warning_shown;
- }
- set {
- if (value && !this.high_volume_warning_shown) {
- /* NOTE: Action doesn't really exist, just used to find below when removing */
- var item = new MenuItem(_("High volume can damage your hearing."), "indicator.high-volume-warning-item");
- volume_section.append_item (item);
- this.high_volume_warning_shown = true;
- }
- else if (!value && this.high_volume_warning_shown) {
- int location = -1;
- while ((location = find_action(this.volume_section, "indicator.high-volume-warning-item")) != -1) {
- this.volume_section.remove (location);
- }
- this.high_volume_warning_shown = false;
- }
- }
- }
-
- int find_action (Menu menu, string in_action) {
- int n = menu.get_n_items ();
- for (int i = 0; i < n; i++) {
- string action;
- menu.get_item_attribute (i, "action", "s", out action);
- if (in_action == action)
- return i;
- }
-
- return -1;
- }
-
- public void update_all_players_play_section() {
- foreach (var player_stored in notify_handlers.get_keys ()) {
- int index = this.find_player_section(player_stored);
- if (index != -1) {
- // just update to verify if we must hide the player controls
- update_player_section (player_stored, index);
- }
- }
- }
-
- private void check_last_running_player () {
- foreach (var player in notify_handlers.get_keys ()) {
- if (player.is_running && number_of_running_players == 1) {
- // this is the first or the last player running...
- // store its id
- this.last_player_updated (player.id);
- }
- }
- }
-
- public void add_player (MediaPlayer player) {
- if (this.notify_handlers.contains (player))
- return;
-
- if (player.is_running || !this.hide_inactive)
- this.insert_player_section (player);
- this.update_playlists (player);
-
- var handler_id = player.notify["is-running"].connect ( () => {
- int index = this.find_player_section(player);
- if (player.is_running) {
- if (index == -1) {
- this.insert_player_section (player);
- }
- number_of_running_players++;
- }
- else {
- number_of_running_players--;
- if (this.hide_inactive)
- this.remove_player_section (player);
- }
- this.update_playlists (player);
-
- // we need to update the rest of players, because we might have
- // a non running player still showing the playback controls
- update_all_players_play_section();
-
- check_last_running_player ();
- });
- this.notify_handlers.insert (player, handler_id);
-
- player.playlists_changed.connect (this.update_playlists);
- player.playbackstatus_changed.connect (this.update_playbackstatus);
-
- check_last_running_player ();
- }
-
- public void remove_player (MediaPlayer player) {
- this.remove_player_section (player);
-
- var id = this.notify_handlers.lookup(player);
- if (id != 0) {
- player.disconnect(id);
- }
-
- player.playlists_changed.disconnect (this.update_playlists);
-
- /* this'll drop our ref to it */
- this.notify_handlers.remove (player);
-
- check_last_running_player ();
- }
-
- public void update_volume_slider (VolumeControl.ActiveOutput active_output) {
- int index = find_action (this.volume_section, "indicator.volume");
- if (index != -1) {
- string label = "Volume";
- switch (active_output) {
- case VolumeControl.ActiveOutput.SPEAKERS:
- label = _("Volume");
- break;
- case VolumeControl.ActiveOutput.HEADPHONES:
- label = _("Volume (Headphones)");
- break;
- case VolumeControl.ActiveOutput.BLUETOOTH_SPEAKER:
- label = _("Volume (Bluetooth)");
- break;
- case VolumeControl.ActiveOutput.USB_SPEAKER:
- label = _("Volume (Usb)");
- break;
- case VolumeControl.ActiveOutput.HDMI_SPEAKER:
- label = _("Volume (HDMI)");
- break;
- case VolumeControl.ActiveOutput.BLUETOOTH_HEADPHONES:
- label = _("Volume (Bluetooth headphones)");
- break;
- case VolumeControl.ActiveOutput.USB_HEADPHONES:
- label = _("Volume (Usb headphones)");
- break;
- case VolumeControl.ActiveOutput.HDMI_HEADPHONES:
- label = _("Volume (HDMI headphones)");
- break;
- }
- this.volume_section.remove (index);
- this.volume_section.insert_item (index, this.create_slider_menu_item (_(label), "indicator.volume(0)", 0.0, 1.0, 0.01,
- "audio-volume-low-zero-panel",
- "audio-volume-high-panel", true));
- }
- }
-
- public Menu root;
- public Menu menu;
- Menu volume_section;
- bool mic_volume_shown;
- bool settings_shown = false;
- bool high_volume_warning_shown = false;
- bool hide_inactive;
- bool hide_players = false;
- bool hide_inactive_player_controls = false;
- bool add_play_button_inactive_player = false;
- HashTable<MediaPlayer, ulong> notify_handlers;
- bool greeter_players = false;
- int number_of_running_players = 0;
- string default_player = "";
-
- /* returns the position in this.menu of the section that's associated with @player */
- int find_player_section (MediaPlayer player) {
- debug("Looking for player: %s", player.id);
- string action_name = @"indicator.$(player.id)";
- int n = this.menu.get_n_items ();
- for (int i = 0; i < n; i++) {
- var section = this.menu.get_item_link (i, Menu.LINK_SECTION);
- if (section == null) continue;
-
- string action;
- section.get_item_attribute (0, "action", "s", out action);
- if (action == action_name)
- return i;
- }
-
- debug("Unable to find section for player: %s", player.id);
- return -1;
- }
-
- int find_player_playback_controls_section (Menu player_menu) {
- int n = player_menu.get_n_items ();
- for (int i = 0; i < n; i++) {
- string type;
- player_menu.get_item_attribute (i, "x-canonical-type", "s", out type);
- if (type == PLAYBACK_ITEM_TYPE)
- return i;
- }
-
- return -1;
- }
-
- MenuItem create_playback_menu_item (MediaPlayer player) {
- var playback_item = new MenuItem (null, null);
- playback_item.set_attribute ("x-canonical-type", "s", PLAYBACK_ITEM_TYPE);
- if (player.is_running) {
- if (player.can_do_play) {
- playback_item.set_attribute ("x-canonical-play-action", "s", "indicator.play." + player.id);
- }
- if (player.can_do_next) {
- playback_item.set_attribute ("x-canonical-next-action", "s", "indicator.next." + player.id);
- }
- if (player.can_do_prev) {
- playback_item.set_attribute ("x-canonical-previous-action", "s", "indicator.previous." + player.id);
- }
- } else {
- if (this.add_play_button_inactive_player) {
- playback_item.set_attribute ("x-canonical-play-action", "s", "indicator.play." + player.id);
- }
- }
- return playback_item;
- }
-
- void insert_player_section (MediaPlayer player) {
- if (this.hide_players)
- return;
-
- var section = new Menu ();
- Icon icon;
-
- debug("Adding section for player: %s (%s)", player.id, player.is_running ? "running" : "not running");
-
- icon = player.icon;
- if (icon == null)
- icon = new ThemedIcon.with_default_fallbacks ("application-default-icon");
-
- var base_action = "indicator." + player.id;
- if (this.greeter_players)
- base_action += ".greeter";
-
- var player_item = new MenuItem (player.name, base_action);
- player_item.set_attribute ("x-canonical-type", "s", "org.ayatana.unity.media-player");
- if (icon != null)
- player_item.set_attribute_value ("icon", icon.serialize ());
- section.append_item (player_item);
-
- if (player.is_running|| !this.hide_inactive_player_controls || player.id == this.default_player) {
- var playback_item = create_playback_menu_item (player);
- section.insert_item (PlayerSectionPosition.PLAYER_CONTROLS, playback_item);
- }
-
- /* Add new players to the end of the player sections, just before the settings */
- if (settings_shown) {
- this.menu.insert_section (this.menu.get_n_items () -1, null, section);
- } else {
- this.menu.append_section (null, section);
- }
- }
-
- void remove_player_section (MediaPlayer player) {
- if (this.hide_players)
- return;
-
- int index = this.find_player_section (player);
- if (index >= 0)
- this.menu.remove (index);
- }
-
- void add_player_playback_controls (MediaPlayer player, int index, bool adding_default_player) {
- var player_section = this.menu.get_item_link(index, Menu.LINK_SECTION) as Menu;
-
- int play_control_index = find_player_playback_controls_section (player_section);
- if (player.is_running || !this.hide_inactive_player_controls || (number_of_running_players == 0 && adding_default_player) ) {
- MenuItem playback_item = create_playback_menu_item (player);
- if (play_control_index != -1) {
- player_section.remove (PlayerSectionPosition.PLAYER_CONTROLS);
- }
- player_section.insert_item (PlayerSectionPosition.PLAYER_CONTROLS, playback_item);
- } else {
- if (play_control_index != -1 && number_of_running_players >= 1) {
- // remove both, playlist and play controls
- player_section.remove (PlayerSectionPosition.PLAYLIST);
- player_section.remove (PlayerSectionPosition.PLAYER_CONTROLS);
- }
- }
- }
-
- void update_player_section (MediaPlayer player, int index) {
- add_player_playback_controls (player, index, false);
- }
-
- void update_playlists (MediaPlayer player) {
- int index = find_player_section (player);
- if (index < 0)
- return;
-
- var player_section = this.menu.get_item_link (index, Menu.LINK_SECTION) as Menu;
-
- /* if a section has three items, the playlists menu is in it */
- if (player_section.get_n_items () == 3)
- player_section.remove (2);
-
- if (!player.is_running)
- return;
-
- var count = player.get_n_playlists ();
- if (count == 0)
- return;
-
- var playlists_section = new Menu ();
- for (int i = 0; i < count; i++) {
- var playlist_id = player.get_playlist_id (i);
- playlists_section.append (player.get_playlist_name (i),
- @"indicator.play-playlist.$(player.id)::$playlist_id");
-
- }
-
- var submenu = new Menu ();
- submenu.append_section (null, playlists_section);
- player_section.append_submenu (_("Choose Playlist"), submenu);
- }
-
- void update_playbackstatus (MediaPlayer player) {
- int index = find_player_section (player);
- if (index != -1) {
- update_player_section (player, index);
- }
- }
-
- MenuItem create_slider_menu_item (string label, string action, double min, double max, double step, string min_icon_name, string max_icon_name, bool sync_action) {
- var min_icon = new ThemedIcon.with_default_fallbacks (min_icon_name);
- var max_icon = new ThemedIcon.with_default_fallbacks (max_icon_name);
-
- var slider = new MenuItem (label, action);
- slider.set_attribute ("x-canonical-type", "s", "org.ayatana.unity.slider");
- slider.set_attribute_value ("min-icon", min_icon.serialize ());
- slider.set_attribute_value ("max-icon", max_icon.serialize ());
- slider.set_attribute ("min-value", "d", min);
- slider.set_attribute ("max-value", "d", max);
- slider.set_attribute ("step", "d", step);
- if (sync_action) {
- slider.set_attribute ("x-canonical-sync-action", "s", "indicator.volume-sync");
- }
-
- return slider;
- }
-
- public signal void last_player_updated (string player_id);
+ public enum DisplayFlags {
+ NONE = 0,
+ SHOW_MUTE = 1,
+ HIDE_INACTIVE_PLAYERS = 2,
+ HIDE_PLAYERS = 4,
+ GREETER_PLAYERS = 8,
+ SHOW_SILENT_MODE = 16,
+ HIDE_INACTIVE_PLAYERS_PLAY_CONTROLS = 32,
+ ADD_PLAY_CONTROL_INACTIVE_PLAYER = 64
+ }
+
+ public enum PlayerSectionPosition {
+ LABEL = 0,
+ PLAYER_CONTROLS = 1,
+ PLAYLIST = 2
+ }
+
+ const string PLAYBACK_ITEM_TYPE = "org.ayatana.unity.playback-item";
+
+ public SoundMenu (string? settings_action, DisplayFlags flags) {
+ /* A sound menu always has at least two sections: the volume section (this.volume_section)
+ * at the start of the menu, and the settings section at the end. Between those two,
+ * it has a dynamic amount of player sections, one for each registered player.
+ */
+
+ this.volume_section = new Menu ();
+
+ if ((flags & DisplayFlags.SHOW_MUTE) != 0)
+ volume_section.append (_("Mute"), "indicator.mute");
+ if ((flags & DisplayFlags.SHOW_SILENT_MODE) != 0) {
+ var item = new MenuItem(_("Silent Mode"), "indicator.silent-mode");
+ item.set_attribute("x-ayatana-type", "s", "org.ayatana.indicator.switch");
+ volume_section.append_item(item);
+ }
+
+ volume_section.append_item (this.create_slider_menu_item (_("Volume"), "indicator.volume(0)", 0.0, 1.0, 0.01,
+ "audio-volume-low-zero-panel",
+ "audio-volume-high-panel", true));
+
+ this.menu = new Menu ();
+ this.menu.append_section (null, volume_section);
+
+ if (settings_action != null) {
+ settings_shown = true;
+ this.menu.append (_("Sound Settingsā€¦"), settings_action);
+ }
+
+ var root_item = new MenuItem (null, "indicator.root");
+ root_item.set_attribute ("x-ayatana-type", "s", "org.ayatana.indicator.root");
+ root_item.set_attribute ("x-ayatana-scroll-action", "s", "indicator.scroll");
+ root_item.set_attribute ("x-ayatana-secondary-action", "s", "indicator.mute");
+ root_item.set_attribute ("submenu-action", "s", "indicator.indicator-shown");
+ root_item.set_submenu (this.menu);
+
+ this.root = new Menu ();
+ root.append_item (root_item);
+
+ this.hide_players = (flags & DisplayFlags.HIDE_PLAYERS) != 0;
+ this.hide_inactive = (flags & DisplayFlags.HIDE_INACTIVE_PLAYERS) != 0;
+ this.hide_inactive_player_controls = (flags & DisplayFlags.HIDE_INACTIVE_PLAYERS_PLAY_CONTROLS) != 0;
+ this.add_play_button_inactive_player = (flags & DisplayFlags.ADD_PLAY_CONTROL_INACTIVE_PLAYER) != 0;
+ this.notify_handlers = new HashTable<MediaPlayer, ulong> (direct_hash, direct_equal);
+
+ this.greeter_players = (flags & DisplayFlags.GREETER_PLAYERS) != 0;
+ }
+
+ ~SoundMenu () {
+ if (export_id != 0) {
+ bus.unexport_menu_model(export_id);
+ export_id = 0;
+ }
+ }
+
+ public void set_default_player (string default_player_id) {
+ this.default_player = default_player_id;
+ foreach (var player_stored in notify_handlers.get_keys ()) {
+ int index = this.find_player_section(player_stored);
+ if (index != -1 && player_stored.id == this.default_player) {
+ add_player_playback_controls (player_stored, index, true);
+ }
+ }
+ }
+
+ DBusConnection? bus = null;
+ uint export_id = 0;
+
+ public void export (DBusConnection connection, string object_path) {
+ bus = connection;
+ try {
+ export_id = bus.export_menu_model (object_path, this.root);
+ } catch (Error e) {
+ critical ("%s", e.message);
+ }
+ }
+
+ public bool show_mic_volume {
+ get {
+ return this.mic_volume_shown;
+ }
+ set {
+ if (value && !this.mic_volume_shown) {
+ var slider = this.create_slider_menu_item (_("Microphone Volume"), "indicator.mic-volume", 0.0, 1.0, 0.01,
+ "audio-input-microphone-low-zero-panel",
+ "audio-input-microphone-high-panel", false);
+ volume_section.append_item (slider);
+ this.mic_volume_shown = true;
+ }
+ else if (!value && this.mic_volume_shown) {
+ int location = -1;
+ while ((location = find_action(this.volume_section, "indicator.mic-volume")) != -1) {
+ this.volume_section.remove (location);
+ }
+ this.mic_volume_shown = false;
+ }
+ }
+ }
+
+ public bool show_high_volume_warning {
+ get {
+ return this.high_volume_warning_shown;
+ }
+ set {
+ if (value && !this.high_volume_warning_shown) {
+ /* NOTE: Action doesn't really exist, just used to find below when removing */
+ var item = new MenuItem(_("High volume can damage your hearing."), "indicator.high-volume-warning-item");
+ volume_section.append_item (item);
+ this.high_volume_warning_shown = true;
+ }
+ else if (!value && this.high_volume_warning_shown) {
+ int location = -1;
+ while ((location = find_action(this.volume_section, "indicator.high-volume-warning-item")) != -1) {
+ this.volume_section.remove (location);
+ }
+ this.high_volume_warning_shown = false;
+ }
+ }
+ }
+
+ int find_action (Menu menu, string in_action) {
+ int n = menu.get_n_items ();
+ for (int i = 0; i < n; i++) {
+ string action;
+ menu.get_item_attribute (i, "action", "s", out action);
+ if (in_action == action)
+ return i;
+ }
+
+ return -1;
+ }
+
+ public void update_all_players_play_section() {
+ foreach (var player_stored in notify_handlers.get_keys ()) {
+ int index = this.find_player_section(player_stored);
+ if (index != -1) {
+ // just update to verify if we must hide the player controls
+ update_player_section (player_stored, index);
+ }
+ }
+ }
+
+ private void check_last_running_player () {
+ foreach (var player in notify_handlers.get_keys ()) {
+ if (player.is_running && number_of_running_players == 1) {
+ // this is the first or the last player running...
+ // store its id
+ this.last_player_updated (player.id);
+ }
+ }
+ }
+
+ public void add_player (MediaPlayer player) {
+ if (this.notify_handlers.contains (player))
+ return;
+
+ if (player.is_running || !this.hide_inactive)
+ this.insert_player_section (player);
+ this.update_playlists (player);
+
+ var handler_id = player.notify["is-running"].connect ( () => {
+ int index = this.find_player_section(player);
+ if (player.is_running) {
+ if (index == -1) {
+ this.insert_player_section (player);
+ }
+ number_of_running_players++;
+ }
+ else {
+ number_of_running_players--;
+ if (this.hide_inactive)
+ this.remove_player_section (player);
+ }
+ this.update_playlists (player);
+
+ // we need to update the rest of players, because we might have
+ // a non running player still showing the playback controls
+ update_all_players_play_section();
+
+ check_last_running_player ();
+ });
+ this.notify_handlers.insert (player, handler_id);
+
+ player.playlists_changed.connect (this.update_playlists);
+ player.playbackstatus_changed.connect (this.update_playbackstatus);
+
+ check_last_running_player ();
+ }
+
+ public void remove_player (MediaPlayer player) {
+ this.remove_player_section (player);
+
+ var id = this.notify_handlers.lookup(player);
+ if (id != 0) {
+ player.disconnect(id);
+ }
+
+ player.playlists_changed.disconnect (this.update_playlists);
+
+ /* this'll drop our ref to it */
+ this.notify_handlers.remove (player);
+
+ check_last_running_player ();
+ }
+
+ public void update_volume_slider (VolumeControl.ActiveOutput active_output) {
+ int index = find_action (this.volume_section, "indicator.volume");
+ if (index != -1) {
+ string label = "Volume";
+ switch (active_output) {
+ case VolumeControl.ActiveOutput.SPEAKERS:
+ label = _("Volume");
+ break;
+ case VolumeControl.ActiveOutput.HEADPHONES:
+ label = _("Volume (Headphones)");
+ break;
+ case VolumeControl.ActiveOutput.BLUETOOTH_SPEAKER:
+ label = _("Volume (Bluetooth)");
+ break;
+ case VolumeControl.ActiveOutput.USB_SPEAKER:
+ label = _("Volume (Usb)");
+ break;
+ case VolumeControl.ActiveOutput.HDMI_SPEAKER:
+ label = _("Volume (HDMI)");
+ break;
+ case VolumeControl.ActiveOutput.BLUETOOTH_HEADPHONES:
+ label = _("Volume (Bluetooth headphones)");
+ break;
+ case VolumeControl.ActiveOutput.USB_HEADPHONES:
+ label = _("Volume (Usb headphones)");
+ break;
+ case VolumeControl.ActiveOutput.HDMI_HEADPHONES:
+ label = _("Volume (HDMI headphones)");
+ break;
+ }
+ this.volume_section.remove (index);
+ this.volume_section.insert_item (index, this.create_slider_menu_item (_(label), "indicator.volume(0)", 0.0, 1.0, 0.01,
+ "audio-volume-low-zero-panel",
+ "audio-volume-high-panel", true));
+ }
+ }
+
+ public Menu root;
+ public Menu menu;
+ Menu volume_section;
+ bool mic_volume_shown;
+ bool settings_shown = false;
+ bool high_volume_warning_shown = false;
+ bool hide_inactive;
+ bool hide_players = false;
+ bool hide_inactive_player_controls = false;
+ bool add_play_button_inactive_player = false;
+ HashTable<MediaPlayer, ulong> notify_handlers;
+ bool greeter_players = false;
+ int number_of_running_players = 0;
+ string default_player = "";
+
+ /* returns the position in this.menu of the section that's associated with @player */
+ int find_player_section (MediaPlayer player) {
+ debug("Looking for player: %s", player.id);
+ string action_name = @"indicator.$(player.id)";
+ int n = this.menu.get_n_items ();
+ for (int i = 0; i < n; i++) {
+ var section = this.menu.get_item_link (i, Menu.LINK_SECTION);
+ if (section == null) continue;
+
+ string action;
+ section.get_item_attribute (0, "action", "s", out action);
+ if (action == action_name)
+ return i;
+ }
+
+ debug("Unable to find section for player: %s", player.id);
+ return -1;
+ }
+
+ int find_player_playback_controls_section (Menu player_menu) {
+ int n = player_menu.get_n_items ();
+ for (int i = 0; i < n; i++) {
+ string type;
+ player_menu.get_item_attribute (i, "x-ayatana-type", "s", out type);
+ if (type == PLAYBACK_ITEM_TYPE)
+ return i;
+ }
+
+ return -1;
+ }
+
+ MenuItem create_playback_menu_item (MediaPlayer player) {
+ var playback_item = new MenuItem (null, null);
+ playback_item.set_attribute ("x-ayatana-type", "s", PLAYBACK_ITEM_TYPE);
+ if (player.is_running) {
+ if (player.can_do_play) {
+ playback_item.set_attribute ("x-ayatana-play-action", "s", "indicator.play." + player.id);
+ }
+ if (player.can_do_next) {
+ playback_item.set_attribute ("x-ayatana-next-action", "s", "indicator.next." + player.id);
+ }
+ if (player.can_do_prev) {
+ playback_item.set_attribute ("x-ayatana-previous-action", "s", "indicator.previous." + player.id);
+ }
+ } else {
+ if (this.add_play_button_inactive_player) {
+ playback_item.set_attribute ("x-ayatana-play-action", "s", "indicator.play." + player.id);
+ }
+ }
+ return playback_item;
+ }
+
+ void insert_player_section (MediaPlayer player) {
+ if (this.hide_players)
+ return;
+
+ var section = new Menu ();
+ Icon icon;
+
+ debug("Adding section for player: %s (%s)", player.id, player.is_running ? "running" : "not running");
+
+ icon = player.icon;
+ if (icon == null)
+ icon = new ThemedIcon.with_default_fallbacks ("application-default-icon");
+
+ var base_action = "indicator." + player.id;
+ if (this.greeter_players)
+ base_action += ".greeter";
+
+ var player_item = new MenuItem (player.name, base_action);
+ player_item.set_attribute ("x-ayatana-type", "s", "org.ayatana.unity.media-player");
+ if (icon != null)
+ player_item.set_attribute_value ("icon", icon.serialize ());
+ section.append_item (player_item);
+
+ if (player.is_running|| !this.hide_inactive_player_controls || player.id == this.default_player) {
+ var playback_item = create_playback_menu_item (player);
+ section.insert_item (PlayerSectionPosition.PLAYER_CONTROLS, playback_item);
+ }
+
+ /* Add new players to the end of the player sections, just before the settings */
+ if (settings_shown) {
+ this.menu.insert_section (this.menu.get_n_items () -1, null, section);
+ } else {
+ this.menu.append_section (null, section);
+ }
+ }
+
+ void remove_player_section (MediaPlayer player) {
+ if (this.hide_players)
+ return;
+
+ int index = this.find_player_section (player);
+ if (index >= 0)
+ this.menu.remove (index);
+ }
+
+ void add_player_playback_controls (MediaPlayer player, int index, bool adding_default_player) {
+ var player_section = this.menu.get_item_link(index, Menu.LINK_SECTION) as Menu;
+
+ int play_control_index = find_player_playback_controls_section (player_section);
+ if (player.is_running || !this.hide_inactive_player_controls || (number_of_running_players == 0 && adding_default_player) ) {
+ MenuItem playback_item = create_playback_menu_item (player);
+ if (play_control_index != -1) {
+ player_section.remove (PlayerSectionPosition.PLAYER_CONTROLS);
+ }
+ player_section.insert_item (PlayerSectionPosition.PLAYER_CONTROLS, playback_item);
+ } else {
+ if (play_control_index != -1 && number_of_running_players >= 1) {
+ // remove both, playlist and play controls
+ player_section.remove (PlayerSectionPosition.PLAYLIST);
+ player_section.remove (PlayerSectionPosition.PLAYER_CONTROLS);
+ }
+ }
+ }
+
+ void update_player_section (MediaPlayer player, int index) {
+ add_player_playback_controls (player, index, false);
+ }
+
+ void update_playlists (MediaPlayer player) {
+ int index = find_player_section (player);
+ if (index < 0)
+ return;
+
+ var player_section = this.menu.get_item_link (index, Menu.LINK_SECTION) as Menu;
+
+ /* if a section has three items, the playlists menu is in it */
+ if (player_section.get_n_items () == 3)
+ player_section.remove (2);
+
+ if (!player.is_running)
+ return;
+
+ var count = player.get_n_playlists ();
+ if (count == 0)
+ return;
+
+ var playlists_section = new Menu ();
+ for (int i = 0; i < count; i++) {
+ var playlist_id = player.get_playlist_id (i);
+ playlists_section.append (player.get_playlist_name (i),
+ @"indicator.play-playlist.$(player.id)::$playlist_id");
+
+ }
+
+ var submenu = new Menu ();
+ submenu.append_section (null, playlists_section);
+ player_section.append_submenu (_("Choose Playlist"), submenu);
+ }
+
+ void update_playbackstatus (MediaPlayer player) {
+ int index = find_player_section (player);
+ if (index != -1) {
+ update_player_section (player, index);
+ }
+ }
+
+ MenuItem create_slider_menu_item (string label, string action, double min, double max, double step, string min_icon_name, string max_icon_name, bool sync_action) {
+ var min_icon = new ThemedIcon.with_default_fallbacks (min_icon_name);
+ var max_icon = new ThemedIcon.with_default_fallbacks (max_icon_name);
+
+ var slider = new MenuItem (label, action);
+ slider.set_attribute ("x-ayatana-type", "s", "org.ayatana.unity.slider");
+ slider.set_attribute_value ("min-icon", min_icon.serialize ());
+ slider.set_attribute_value ("max-icon", max_icon.serialize ());
+ slider.set_attribute ("min-value", "d", min);
+ slider.set_attribute ("max-value", "d", max);
+ slider.set_attribute ("step", "d", step);
+ if (sync_action) {
+ slider.set_attribute ("x-ayatana-sync-action", "s", "indicator.volume-sync");
+ }
+
+ return slider;
+ }
+
+ public signal void last_player_updated (string player_id);
}
diff --git a/src/warn-notification.vala b/src/warn-notification.vala
index 17129aa..f5c8b0b 100644
--- a/src/warn-notification.vala
+++ b/src/warn-notification.vala
@@ -19,41 +19,41 @@
public class IndicatorSound.WarnNotification: Notification
{
- public enum Response {
- CANCEL,
- OK
- }
+ public enum Response {
+ CANCEL,
+ OK
+ }
- public signal void user_responded (Response response);
+ public signal void user_responded (Response response);
protected override Notify.Notification create_notification () {
- var n = new Notify.Notification (
- _("Volume"),
- _("High volume can damage your hearing."),
- "audio-volume-high");
- n.set_hint ("x-canonical-non-shaped-icon", "true");
- n.set_hint ("x-canonical-snap-decisions", "true");
- n.set_hint ("x-canonical-private-affirmative-tint", "true");
- n.closed.connect ((n) => {
- n.clear_actions ();
- });
- return n;
- }
+ var n = new Notify.Notification (
+ _("Volume"),
+ _("High volume can damage your hearing."),
+ "audio-volume-high");
+ n.set_hint ("x-canonical-non-shaped-icon", "true");
+ n.set_hint ("x-canonical-snap-decisions", "true");
+ n.set_hint ("x-canonical-private-affirmative-tint", "true");
+ n.closed.connect ((n) => {
+ n.clear_actions ();
+ });
+ return n;
+ }
- public bool show () {
+ public bool show () {
- if (!notify_server_supports ("actions"))
- return false;
+ if (!notify_server_supports ("actions"))
+ return false;
- _notification.clear_actions ();
- _notification.add_action ("ok", _("OK"), (n, a) => {
- user_responded (Response.OK);
- });
- _notification.add_action ("cancel", _("Cancel"), (n, a) => {
- user_responded (Response.CANCEL);
- });
- show_notification();
+ _notification.clear_actions ();
+ _notification.add_action ("ok", _("OK"), (n, a) => {
+ user_responded (Response.OK);
+ });
+ _notification.add_action ("cancel", _("Cancel"), (n, a) => {
+ user_responded (Response.CANCEL);
+ });
+ show_notification();
- return true;
- }
+ return true;
+ }
}