feat: microphone muting

This commit is contained in:
2026-07-22 20:06:59 +02:00
parent d69107c624
commit ff200e3580
3 changed files with 86 additions and 1 deletions
+4 -1
View File
@@ -11,6 +11,7 @@ from sims.modules.notmuch import NotmuchWidget
from sims.modules.buddy import Buddy from sims.modules.buddy import Buddy
from sims.modules.org import OrgDropdown, OrgWidget from sims.modules.org import OrgDropdown, OrgWidget
from sims.modules.screenrec import ScreenrecWidget from sims.modules.screenrec import ScreenrecWidget
from sims.modules.microphone import MicrophoneWidget
from fabric.widgets.wayland import WaylandWindow as Window from fabric.widgets.wayland import WaylandWindow as Window
from fabric.system_tray.widgets import SystemTray from fabric.system_tray.widgets import SystemTray
from sims.widgets.fenster import FensterWorkspaces, FensterActiveWindow from sims.widgets.fenster import FensterWorkspaces, FensterActiveWindow
@@ -110,11 +111,13 @@ class StatusBar(Window):
if org_service is not None: if org_service is not None:
self.org = OrgWidget(service=org_service, dropdown=org_dropdown) self.org = OrgWidget(service=org_service, dropdown=org_dropdown)
self.microphone = MicrophoneWidget()
self.status_container = Box( self.status_container = Box(
name="widgets-container", name="widgets-container",
spacing=4, spacing=4,
orientation="h", orientation="h",
children=self.progress_bars_overlay, children=[self.microphone, self.progress_bars_overlay],
) )
end_container_children = [] end_container_children = []
+68
View File
@@ -0,0 +1,68 @@
from fabric.audio.service import Audio
from fabric.widgets.box import Box
from fabric.widgets.button import Button
from fabric.widgets.label import Label
MIC_ICON = "󰍬"
MIC_MUTED_ICON = "󰍭"
class MicrophoneWidget(Box):
"""Bar widget showing microphone state; click to toggle mute.
Mutes *all* input sources (not just the default one) so virtual
sources like EasyEffects and their underlying hardware mics are
silenced together.
"""
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.audio = Audio()
self.icon_label = Label(
name="microphone-icon",
label=MIC_ICON,
)
self.button = Button(
name="microphone-button",
child=self.icon_label,
on_clicked=self.on_clicked,
style="background: transparent; border: none; margin: 0; box-shadow: none;",
)
self.add(self.button)
# `changed` fires for any stream change (incl. mute state) and
# `microphone-changed` when the default source switches.
self.audio.connect("changed", self.update_icon)
self.audio.connect("microphone-changed", self.update_icon)
self.update_icon()
def on_clicked(self, *_):
mics = self.audio.microphones or []
if not mics and self.audio.microphone:
mics = [self.audio.microphone]
if not mics:
return
# if anything is live -> mute everything; else unmute everything
mute = self._any_unmuted(mics)
for mic in mics:
mic.muted = mute
self.update_icon()
def _any_unmuted(self, mics) -> bool:
return any(not mic.muted for mic in mics)
def update_icon(self, *_):
mics = self.audio.microphones or []
if not mics and self.audio.microphone:
mics = [self.audio.microphone]
if not mics:
self.set_visible(False)
return
self.set_visible(True)
if self._any_unmuted(mics):
self.icon_label.set_label(MIC_ICON)
self.icon_label.remove_style_class("muted")
else:
self.icon_label.set_label(MIC_MUTED_ICON)
self.icon_label.add_style_class("muted")
+14
View File
@@ -53,6 +53,20 @@
font-weight: bold; font-weight: bold;
} }
#microphone-icon {
color: var(--foreground);
font-size: 20px;
}
#microphone-button {
min-width: 28px;
padding: 0 6px;
}
#microphone-icon.muted {
color: var(--red);
}
#cpu-progress-bar, #cpu-progress-bar,
#ram-progress-bar, #ram-progress-bar,
#volume-progress-bar { #volume-progress-bar {