# Python imports # Lib imports import gi gi.require_version('Gtk', '3.0') from gi.repository import Gtk from gi.repository import GLib # Application imports from utils.pulsectl import pulsectl from ..widgets.audio_sink import AudioSink class BaseContainer(Gtk.Box): def __init__(self): super(BaseContainer, self).__init__() self._scroll = None self._box = None self.pulse = None self.pulse_events = None self.sink_inputs = None self.pause_sink = False self._setup_styling() self._setup_signals() self._subscribe_to_events() self._load_widgets() self.show_all() def _setup_styling(self): self.set_orientation(Gtk.Orientation.VERTICAL) self.set_margin_top(10) self.set_margin_bottom(10) self.set_margin_left(10) self.set_margin_right(10) def _setup_signals(self): ... def _subscribe_to_events(self): event_system.subscribe("handle_new_sync_input", self._handle_new_sync_input) event_system.subscribe("handle_del_sync_input", self._handle_del_sync_input) event_system.subscribe("handle_cng_sync_input", self._handle_cng_sync_input) def _load_widgets(self): scroll = Gtk.ScrolledWindow() viewport = Gtk.Viewport() box = Gtk.Box() scroll.add(viewport) viewport.add(box) try: pulse = pulsectl.Pulse() self.pulse_events = pulsectl.Pulse('event-printer') si, sink_inputs, modules, clients, sink_list = pulse.server_info(), pulse.sink_input_list(), pulse.module_list(), pulse.client_list(), pulse.sink_list() logger.debug(f"\n\nServer Info\n{si}\n\nSink Inputs:") for sink in sink_list: self.add( AudioSink(pulse, sink) ) self.pulse = pulse self.sink_inputs = sink_inputs for sink_input in sink_inputs: box.add( AudioSink(pulse, sink_input) ) except Exception as e: logger.debug(f"{e}") self._box = box self._scroll = scroll.get_vadjustment() self._scroll.connect("changed", self._scroll_to_bottom) scroll.set_vexpand(True) scroll.set_overlay_scrolling(False) scroll.set_margin_top(20) scroll.set_margin_bottom(10) box.set_orientation(Gtk.Orientation.VERTICAL) self.add(scroll) self.set_pulse_event_listener() def _handle_new_sync_input(self, index): sink_input = self.pulse.sink_input_list()[-1] self._box.add( AudioSink(self.pulse, sink_input) ) def _handle_del_sync_input(self, index): for sink_input in self.sink_inputs: if index == sink_input.index: self.sink_inputs.remove(sink_input) for child in self._box.get_children(): if index == child.sink.index: child.destroy() def _handle_cng_sync_input(self, index): for child in self._box.get_children(): if index == child.sink.index: child.do_update() def _scroll_to_bottom(self, adjustment): self._scroll.set_value( adjustment.get_upper() ) @daemon_threaded def set_pulse_event_listener(self): try: self.pulse_events.event_mask_set('all') self.pulse_events.event_callback_set(self._sub_threaded_event) self.pulse_events.event_listen(timeout = 0) except Exception as e: logger.debug(f"{e}") def _sub_threaded_event(self, eve): logger.debug(f"Pulse event: {eve}") GLib.idle_add(self.handle_event, *(eve,)) def handle_event(self, eve): if eve.facility == "sink_input": if eve.t == "change": event_system.emit("handle_cng_sync_input", (eve.index,)) if eve.t == "new": event_system.emit("handle_new_sync_input", (eve.index,)) if eve.t == "remove": event_system.emit("handle_del_sync_input", (eve.index,))