125 lines
5.1 KiB
Python
125 lines
5.1 KiB
Python
"""General Settings tab: system-wide defaults (default output/input device)
|
|
and this panel's own display settings, plus a read-only line confirming
|
|
what audio server pactl is actually talking to (pipewire-pulse vs a legacy
|
|
PulseAudio daemon) — the whole point of the "build for the future" ask."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import gi
|
|
|
|
gi.require_version("Gtk", "4.0")
|
|
from gi.repository import Gtk # noqa: E402
|
|
|
|
import config
|
|
|
|
|
|
class GeneralTab(Gtk.Box):
|
|
def __init__(self, backend, on_hologram_changed=None) -> None:
|
|
super().__init__(orientation=Gtk.Orientation.VERTICAL, spacing=16)
|
|
self.add_css_class("sb-tab-page")
|
|
self.add_css_class("sb-general")
|
|
self._backend = backend
|
|
self._on_hologram_changed = on_hologram_changed
|
|
self._sink_names: list[str] = []
|
|
self._source_names: list[str] = []
|
|
self._guard = False
|
|
|
|
self.append(self._field("Default Output Device", self._build_output_dropdown()))
|
|
self.append(self._field("Default Input Device", self._build_input_dropdown()))
|
|
|
|
if on_hologram_changed is not None:
|
|
self.append(self._build_hologram_row())
|
|
|
|
self._server_lbl = Gtk.Label(xalign=0.0)
|
|
self._server_lbl.add_css_class("sb-server-info")
|
|
self.append(self._server_lbl)
|
|
|
|
@staticmethod
|
|
def _field(title: str, widget: Gtk.Widget) -> Gtk.Widget:
|
|
col = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=4)
|
|
col.add_css_class("sb-general-field")
|
|
label = Gtk.Label(label=title, xalign=0.0)
|
|
label.add_css_class("sb-field-label")
|
|
col.append(label)
|
|
col.append(widget)
|
|
return col
|
|
|
|
def _build_output_dropdown(self) -> Gtk.DropDown:
|
|
self._output_dropdown = Gtk.DropDown()
|
|
self._output_dropdown.add_css_class("sb-device-dropdown")
|
|
self._output_dropdown.connect("notify::selected", self._on_output_selected)
|
|
return self._output_dropdown
|
|
|
|
def _build_input_dropdown(self) -> Gtk.DropDown:
|
|
self._input_dropdown = Gtk.DropDown()
|
|
self._input_dropdown.add_css_class("sb-device-dropdown")
|
|
self._input_dropdown.connect("notify::selected", self._on_input_selected)
|
|
return self._input_dropdown
|
|
|
|
def _build_hologram_row(self) -> Gtk.Widget:
|
|
row = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=12)
|
|
row.add_css_class("sb-general-field")
|
|
label = Gtk.Label(label="Hologram Effects", xalign=0.0, hexpand=True)
|
|
label.add_css_class("sb-field-label")
|
|
row.append(label)
|
|
switch = Gtk.Switch(valign=Gtk.Align.CENTER)
|
|
switch.set_active(config.hologram_enabled())
|
|
switch.connect("state-set", self._on_hologram_toggled)
|
|
row.append(switch)
|
|
return row
|
|
|
|
def _on_hologram_toggled(self, _switch: Gtk.Switch, value: bool) -> bool:
|
|
config.set_hologram_enabled(value)
|
|
if self._on_hologram_changed is not None:
|
|
self._on_hologram_changed(value)
|
|
return False
|
|
|
|
# -- data -----------------------------------------------------------------------
|
|
def refresh(self) -> None:
|
|
def got_server(info: dict) -> None:
|
|
name = info.get("server_name") or "unknown"
|
|
version = info.get("server_version") or ""
|
|
self._server_lbl.set_label(f"Audio server: {name} {version}".rstrip())
|
|
|
|
def got_sinks(sinks: list[dict]) -> None:
|
|
def got_sources(sources: list[dict]) -> None:
|
|
self._sync_dropdown(self._output_dropdown, sinks, info.get("default_sink", ""), "_sink_names")
|
|
self._sync_dropdown(self._input_dropdown, sources, info.get("default_source", ""), "_source_names")
|
|
self._backend.list_sources(got_sources)
|
|
self._backend.list_sinks(got_sinks)
|
|
self._backend.get_server_info(got_server)
|
|
|
|
def _sync_dropdown(self, dropdown: Gtk.DropDown, devices: list[dict],
|
|
default_name: str, cache_attr: str) -> None:
|
|
names = [d["name"] for d in devices]
|
|
if names != getattr(self, cache_attr):
|
|
setattr(self, cache_attr, names)
|
|
self._guard = True
|
|
dropdown.set_model(Gtk.StringList.new([d["description"] for d in devices]))
|
|
self._guard = False
|
|
idx = names.index(default_name) if default_name in names else None
|
|
if idx is not None and dropdown.get_selected() != idx:
|
|
self._guard = True
|
|
dropdown.set_selected(idx)
|
|
self._guard = False
|
|
|
|
def _on_output_selected(self, dropdown: Gtk.DropDown, _pspec) -> None:
|
|
if self._guard:
|
|
return
|
|
idx = dropdown.get_selected()
|
|
if 0 <= idx < len(self._sink_names):
|
|
self._backend.set_default_sink(self._sink_names[idx])
|
|
|
|
def _on_input_selected(self, dropdown: Gtk.DropDown, _pspec) -> None:
|
|
if self._guard:
|
|
return
|
|
idx = dropdown.get_selected()
|
|
if 0 <= idx < len(self._source_names):
|
|
self._backend.set_default_source(self._source_names[idx])
|
|
|
|
def activate(self) -> None:
|
|
self.refresh()
|
|
|
|
def deactivate(self) -> None:
|
|
pass
|