Skip to content
28 changes: 22 additions & 6 deletions src/Indicator.vala
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ public class Sound.Indicator : Wingpanel.Indicator {
}

construct {
unowned PulseAudioManager pam;

var touchpad_settings = new GLib.Settings ("org.gnome.desktop.peripherals.touchpad");
touchpad_settings.bind ("natural-scroll", this, "natural-scroll-touchpad", SettingsBindFlags.DEFAULT);
var mouse_settings = new GLib.Settings ("org.gnome.desktop.peripherals.mouse");
Expand All @@ -75,12 +77,10 @@ public class Sound.Indicator : Wingpanel.Indicator {
volume_control.notify["volume"].connect (update_tooltip);
volume_control.notify["mute"].connect (update_tooltip);

output_device_manager = new Widgets.DeviceManagerWidget () {
is_input_manager = false
};
input_device_manager = new Widgets.DeviceManagerWidget () {
is_input_manager = true
};
pam = PulseAudioManager.get_default ();
output_device_manager = new Widgets.DeviceManagerWidget (false);
input_device_manager = new Widgets.DeviceManagerWidget (true);
pam.start ();

Notify.init ("wingpanel-indicator-sound");

Expand Down Expand Up @@ -126,6 +126,22 @@ public class Sound.Indicator : Wingpanel.Indicator {
if (notify_timeout_id > 0) {
Source.remove (notify_timeout_id);
}

unowned PulseAudioManager? pam = PulseAudioManager.get_active ();
if (pam != null)
pam.stop ();

output_device_manager.clear ();
output_device_manager.destroy ();

input_device_manager.clear ();
input_device_manager.destroy ();

output_device_manager = null;
input_device_manager = null;

if (pam != null)
pam.unref ();
}

private void set_max_volume () {
Expand Down
53 changes: 50 additions & 3 deletions src/Services/PulseAudioManager.vala
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,19 @@ public class Sound.PulseAudioManager : GLib.Object {
if (pam == null) {
pam = new PulseAudioManager ();
}
return pam;
}

public static unowned PulseAudioManager? get_active () {
return pam;
}

public signal void new_device (Device dev);
public signal void update_device (Device dev);
public signal void disconnected ();

private PulseAudio.Context context;
private PulseAudio.GLibMainLoop loop;
private static PulseAudio.GLibMainLoop loop;
private bool is_ready = false;
private uint reconnect_timer_id = 0U;
private Gee.HashMap<string, Device> input_devices;
Expand All @@ -56,7 +61,9 @@ public class Sound.PulseAudioManager : GLib.Object {
}

construct {
loop = new PulseAudio.GLibMainLoop ();
if (loop == null)
loop = new PulseAudio.GLibMainLoop ();

input_devices = new Gee.HashMap<string, Device> ();
output_devices = new Gee.HashMap<string, Device> ();

Expand All @@ -67,10 +74,39 @@ public class Sound.PulseAudioManager : GLib.Object {
}
}

~PulseAudioManager () {
if (reconnect_timer_id != 0U) {
Source.remove (reconnect_timer_id);
reconnect_timer_id = 0U;
}
pam = null;
}

public void start () {
reconnect_to_pulse.begin ();
}

public void stop () {
if (reconnect_timer_id != 0U) {
Source.remove (reconnect_timer_id);
reconnect_timer_id = 0U;
}

foreach (var device in input_devices.values) {
device.unref ();
}
input_devices.clear ();
default_input = null;

foreach (var device in output_devices.values) {
device.unref ();
}
output_devices.clear ();
default_output = null;

is_ready = false;
}

public async void set_default_device (Device device) {
debug ("\n");
debug ("set_default_device: %s", device.id);
Expand Down Expand Up @@ -245,14 +281,23 @@ public class Sound.PulseAudioManager : GLib.Object {
PulseAudio.Context.SubscriptionMask.CARD);
context.get_server_info (server_info_callback);
is_ready = true;
if (reconnect_timer_id != 0U) {
Source.remove (reconnect_timer_id);
reconnect_timer_id = 0U;
}
break;

case PulseAudio.Context.State.FAILED:
case PulseAudio.Context.State.TERMINATED:
disconnected ();
is_ready = false;
if (reconnect_timer_id == 0U) {
reconnect_timer_id = Timeout.add_seconds (2, reconnect_timeout);
}
break;

case PulseAudio.Context.State.TERMINATED:
stop ();
disconnected ();
break;

default:
Expand Down Expand Up @@ -563,6 +608,8 @@ public class Sound.PulseAudioManager : GLib.Object {
if (is_new) {
devices.set (id, device);
new_device (device);
} else {
update_device (device);
}
}

Expand Down
5 changes: 3 additions & 2 deletions src/Widgets/DeviceItem.vala
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,14 @@ public class DeviceItem : Gtk.ListBoxRow {
private Gtk.RadioButton radio_button;

public Gtk.ListBoxRow row { get; construct; }
public string device_id { get; construct; }
public string display_name { get; construct; }
public string icon_name { get; construct; }
public bool is_priority { get; set construct; }
public bool is_default { get; construct; }

public DeviceItem (string display_name, bool is_default, bool is_priority, string icon_name, Gtk.ListBoxRow? row) {
Object (display_name: display_name, is_default: is_default, is_priority: is_priority, icon_name: icon_name, row: row);
public DeviceItem (string device_id, string display_name, bool is_default, bool is_priority, string icon_name, Gtk.ListBoxRow? row) {
Object (device_id: device_id, display_name: display_name, is_default: is_default, is_priority: is_priority, icon_name: icon_name, row: row);
}

class construct {
Expand Down
56 changes: 46 additions & 10 deletions src/Widgets/DeviceManagerWidget.vala
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,24 @@
public class Sound.Widgets.DeviceManagerWidget : Gtk.Grid {
private Gtk.ListBox device_list;
private Gtk.ScrolledWindow scrolled_box;
public bool is_input_manager;
public bool is_input_manager { get; construct; }

private unowned PulseAudioManager pam;

public DeviceManagerWidget (bool is_input_manager) {
Object (is_input_manager: is_input_manager);
}

construct {
pam = PulseAudioManager.get_default ();
pam.new_device.connect (add_device);
pam.notify["default-output"].connect (default_output_changed);
pam.notify["default-input"].connect (default_input_changed);
pam.start ();
pam.update_device.connect (update_device);
pam.disconnected.connect (disconnected);
if (is_input_manager) {
pam.notify["default-input"].connect (default_changed);
} else {
pam.notify["default-output"].connect (default_changed);
}

device_list = new Gtk.ListBox () {
activate_on_single_click = true,
Expand All @@ -52,13 +60,37 @@ public class Sound.Widgets.DeviceManagerWidget : Gtk.Grid {
update_showable ();
}

public void clear () {
foreach (Gtk.Widget child in device_list.get_children ()) {
device_list.remove (child);
Comment thread
bluesabre marked this conversation as resolved.
child.destroy ();
}
}

private void disconnected () {
clear ();
}

private void update_device (Device device) {
if (device.input != is_input_manager) {
return;
}
foreach (unowned var child in device_list.get_children ()) {
if (device.id == ((DeviceItem) child).device_id) {
return;
}
}
add_device (device);
}

private void add_device (Device device) {
if (device.input != is_input_manager) {
return;
}

Gtk.ListBoxRow? row = device_list.get_row_at_index (0);
var device_item = new DeviceItem (device.display_name,
var device_item = new DeviceItem (device.id,
device.display_name,
device.is_default,
device.is_priority,
device.get_nice_icon (),
Expand All @@ -74,6 +106,7 @@ public class Sound.Widgets.DeviceManagerWidget : Gtk.Grid {
device_list.remove (device_item);
device_list.show_all ();
update_showable ();
device_item.destroy ();
});

device.defaulted.connect (() => {
Expand All @@ -82,6 +115,10 @@ public class Sound.Widgets.DeviceManagerWidget : Gtk.Grid {
update_showable ();
});

if (device.is_default) {
device_item.set_default ();
}

update_showable ();
}

Expand Down Expand Up @@ -137,11 +174,10 @@ public class Sound.Widgets.DeviceManagerWidget : Gtk.Grid {
}
}

private void default_output_changed () {
pam.default_output.defaulted ();
private void default_changed () {
unowned var output = is_input_manager ? pam.default_input : pam.default_output;
if (output != null)
output.defaulted ();
}

private void default_input_changed () {
pam.default_input.defaulted ();
}
}