From e776bc768cf9afca1867200e25d64d315cd72a3e Mon Sep 17 00:00:00 2001 From: Calvin Morrison Date: Fri, 15 May 2026 10:10:04 -0400 Subject: Full mixer implementation — tray, popup, prefs, devices tab with port indicators MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds the complete tmix feature set built since the initial skeleton: balance knob, level meters, KLed mute button, system tray with scroll-wheel volume and recording indicator, tray popup, preferences dialog, right-click context menus, single-instance enforcement, scroll area, window geometry persistence, and Devices tab with PA card profile switcher and live port availability indicators (2-column layout, in-place updates on plug/unplug). Co-Authored-By: Claude Sonnet 4.6 --- TODO | 221 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 221 insertions(+) create mode 100644 TODO (limited to 'TODO') diff --git a/TODO b/TODO new file mode 100644 index 0000000..9834c25 --- /dev/null +++ b/TODO @@ -0,0 +1,221 @@ +tmix — todo list +================ + +## UAT checklist +Run through this before any release / major refactor. + +### Startup +- [ ] App launches without crash when PA is running +- [ ] App launches without crash when PA is NOT running (graceful fail) +- [ ] Window title shows "TMix - Volume Control" (not "TMix - Volume Control - TMix") +- [ ] Tray icon appears when DockInTray=true +- [ ] Window hidden on launch when DockInTray=true +- [ ] Window visible on launch when DockInTray=false + +### Tabs / device population +- [ ] Output tab shows all PA sinks (hardware outputs) +- [ ] Input tab shows all PA sources (mics etc.) but NOT monitor sources +- [ ] Playback tab shows per-app sink inputs; tmix-peak streams NOT shown +- [ ] Recording tab shows per-app source outputs; tmix-peak streams NOT shown +- [ ] Devices added/removed live without restart (plug/unplug USB audio, start/stop app) +- [ ] Correct icon shown per device (headphone, microphone, digital, fallback) +- [ ] Correct app icon shown for Playback streams (Amarok, Firefox, etc.) +- [ ] Vertical label shows device/stream name + +### Volume +- [ ] Dragging volume slider changes PA volume in real time +- [ ] Volume % label updates live while dragging +- [ ] Scrolling on tray icon changes default output volume +- [ ] Volume change from another app (pavucontrol) reflects in tmix slider + label +- [ ] Volume clamped 0–100%, no overflow + +### Mute +- [ ] Green LED = unmuted, off = muted +- [ ] Clicking LED toggles mute state in PA +- [ ] Mute change from another app reflects in LED +- [ ] Right-click "Mute" mutes; item shows "Muted" with checkmark when muted; "Unmute" when muted + +### Balance knob (Output + Playback only) +- [ ] Knob renders cleanly (antialiased, no flicker) +- [ ] Dragging up increases right balance, dragging down increases left +- [ ] Scroll wheel adjusts ±5 +- [ ] Double-click resets to centre +- [ ] PA channel volumes update correctly (left attenuated when right-heavy) +- [ ] Balance change from pavucontrol reflects in knob +- [ ] Input tab has NO balance knob + +### Level meter +- [ ] Output: meter responds to audio playback through that sink +- [ ] Input: meter responds to microphone input +- [ ] Playback: meter shows per-stream level (only that app's audio, not the whole sink) +- [ ] Recording: no meter (acceptable; source output monitoring not implemented) +- [ ] Meter decays smoothly; attack is fast, decay is slower +- [ ] Meter shows 0 when muted or silent + +### Default device +- [ ] Radio button filled on the current PA default output +- [ ] Radio button filled on the current PA default input +- [ ] Clicking empty radio button sets that device as PA default +- [ ] Default change from pavucontrol updates radio buttons in tmix +- [ ] Only one radio button filled at a time per tab +- [ ] Tray icon reflects default output volume/mute state + +### Recording indicator +- [ ] Red LED on Input widget is OFF when no app is recording from that source +- [ ] Red LED turns ON when an app starts recording from that source +- [ ] Red LED turns OFF when recording app stops +- [ ] Second tray icon (microphone) appears when any input is active +- [ ] Second tray icon disappears when all recording stops + +### Right-click context menu +- [ ] Right-click on any device widget shows context menu +- [ ] Menu title shows device name +- [ ] "Mute"/"Muted" item works (see Mute section) +- [ ] Output: "Set as Default Output" present and functional +- [ ] Input: "Set as Default Input" present and functional +- [ ] Playback: "Move to Sink" section lists all available sinks +- [ ] Current sink shown with checkmark in "Move to Sink" list +- [ ] Selecting a different sink moves the stream +- [ ] Output/Input: no "Move to Sink" section +- [ ] Playback/Recording: no "Set as Default" item + +### System tray +- [ ] Volume icon shows muted/low/medium/high based on default output +- [ ] Icon updates when volume changes (slider, scroll wheel, external) +- [ ] Icon updates when mute state changes +- [ ] Scroll wheel on tray raises/lowers default output volume +- [ ] Left-click tray shows/hides main window +- [ ] Right-click tray shows context menu with Quit (only one Quit entry) + +### Window behaviour +- [ ] Closing window hides to tray (DockInTray=true), does not quit +- [ ] Closing window quits (DockInTray=false) +- [ ] Session logout closes app cleanly (sessionSaving check) +- [ ] File → Quit exits cleanly, no crash or double-free + +### Stress / edge cases +- [ ] Rapidly toggle mute — no crash, no stuck state +- [ ] Rapidly drag slider — no crash, PA not flooded beyond responsiveness +- [ ] Kill and restart PulseAudio while tmix is open — tmix recovers or fails gracefully +- [ ] Open tmix with 0 devices on each tab — no crash, empty tabs look OK +- [ ] Open tmix with 10+ playback streams — layout scrolls, no overlap + +## Bugs / Polish +- [x] Taskbar / dock icon missing +- [x] Recording tray icon red dot not appearing +- [x] Icons: app-specific icons for Firefox etc. +- [x] Input devices always show microphone icon regardless of PA device name hint +- [x] Right-click "Move to Sink": show checkmark on the sink the stream is currently on +- [x] Right-click mute item: fixed label "Mute" with checkmark when muted +- [x] Scroll area for 10+ devices — TQScrollView wrapping tab pages and flat strip; + scroll bars appear only when content exceeds window width +- [x] Window does not resize on card profile change (removed adjustSize()) +- [x] Window position persists across restarts +- [x] Single-instance enforcement — second launch raises/shows the existing window (KUniqueApplication) +- [x] Settings dialog is non-blocking (modeless show(), reloads config on each open) +- [ ] Devices tab — sex it up vs pavucontrol-qt: + - Port availability indicators (plugged/unplugged) with port-type icons + (headphones, mic, HDMI, speaker, S/PDIF) from pa_card_port_info.type + - availability_group handling: when a combo jack is detected (multiple ports + share an availability_group), show a "What did you plug in?" prompt so the + user can disambiguate headphones vs headset vs mic + - Hide unavailable profiles by default (toggle to show all) + +## Features + +### Implemented +- [x] Volume % label (live, updates on drag) +- [x] Pan / balance slider per stereo device (reads + writes PA per-channel cvolume) +- [x] Level meter — Output/Input via sink/source monitor; Playback via pa_stream_set_monitor_stream (per-stream) +- [x] Slider tick marks every 5% +- [x] Separator between devices +- [x] Playback slider fix (was broken due to hardcoded 2-channel cvolume) +- [x] Mute button: 3D toggle style +- [x] App icons with multimedia fallback; amarok/TDE apps resolve via binary name +- [x] tmix-peak streams hidden from Recording tab and pavucontrol (media.role=abstract) +- [x] Menu bar — File: Quit, Settings: Configure TMix, Help: About TMix +- [x] Per-device right-click context menu — mute (checkmark), set default, move to sink (checkmark on current) +- [x] System tray (KSystemTray) — scroll wheel adjusts default sink volume, left-click popup/window toggle +- [x] Tray icon — SmallIcon("kmix")/("audio-volume-medium") fallback; muted/low/medium/high states +- [x] Tray popup (TmixPopup) — left-click, shows default output DeviceWidget + "Mixer" button, + auto-dismiss on outside click, positions above/below tray, stays on top +- [x] Recording tray icon — second KSystemTray icon when any input is active; + tooltip lists names of active recording streams +- [x] "Show all in one view" (no-tabs mode) — TQWidgetStack, rebuilds on toggle, + live device add/remove works in both modes +- [x] Show/hide individual tabs (Output, Input, Playback, Recording) via preferences +- [x] Preferences dialog — modeless (non-blocking), OK+Apply+Cancel, + General: dock in tray, popup on click, rec tray icon, confirm quit, scroll step + View: no-tabs toggle, show/hide per tab +- [x] Window auto-sizes to content (adjustSize on device add/remove), minimum 300×200 +- [x] Bottom row fixed 30px height — all device widgets align regardless of content + +### To do +- [x] Devices tab — PA card profile switcher (dropdown per card, set active profile) +- [ ] Switches tab (like KMix "Switches" view) + Enumerate PA card profiles + ports (pa_context_get_card_info_list). + Show as checkboxes/comboboxes: active profile, port retasking, IEC958 enable, + Auto-Mute Mode, etc. May need ALSA fallback for raw HDA switches not + surfaced by PulseAudio (snd-hda-intel ctl elements via alsa-lib). +- [ ] Profiles / sources management tab + List all PA sources and sinks with their active profile (e.g. "analog-stereo", + "hdmi-stereo-extra1"). Allow switching profiles via dropdown. + Show default sink/source with a star; click to set new default + (pa_context_set_default_sink / pa_context_set_default_source). + Subscribe to PA_SUBSCRIPTION_MASK_SERVER + CARD for live updates. +- [x] Tray right-click: Configure, About, Quit (standard TDE style — no functional items) +- [x] Remember window geometry across restarts + +## Big Refactor — Backend Abstraction +Goal: replace KMix entirely across all Trinity platforms (Linux PA/PW/ALSA, FreeBSD OSS, +legacy systems). Each backend is self-contained end-to-end: its own model, its own widgets. +The main window is a dumb shell. + +Architecture: + AbstractBackend (minimal interface) + - name() / open() / close() + - createMixerWidget(parent) → TQWidget* + - createDevicesWidget(parent)→ TQWidget* (null if not supported) + + PulseAudioBackend : AbstractBackend — current code, reorganised + OSSBackend : AbstractBackend — flat sliders, no streams + AlsaBackend : AbstractBackend — HDA controls, switches + PipeWireBackend : AbstractBackend — routing graph if ever needed + + MixerWindow shrinks to: tray, menu, prefs, geometry, "host what backend gives me." + Shared UI widgets (DeviceWidget, LevelMeter, BalanceKnob) become a toolkit + backends may use or ignore — not a framework they're forced into. + + Backend selected at startup via config key "Backend" (default: pulseaudio). + Build system conditionally compiles backends per platform. + +Why: the OSS→ALSA→PA retrofit history was painful. No backend should ever know +about another; no generic UI code should check backend capabilities via flags. +- [ ] L/R channel lock/unlock button — when unlocked, show two independent sliders + for left and right channels; when locked, they move together (current behavior) +- [ ] DCOP interface (get/set volume, mute, list devices) +- [ ] Dark/light theme awareness (follow TDE palette) +- [ ] Horizontal layout mode — device strips laid out left-to-right instead of + top-to-bottom; label above slider, level meter beside it. Toggle in View menu. +- [ ] Current mixer selector — dropdown or sub-menu to switch between PulseAudio + and raw ALSA hardware cards (like KMix "Current Mixer"). Each card gets its + own tab set; PA is the default. Enumerate via pa_context_get_card_info_list + for PA cards; snd_ctl_open for ALSA HDA cards. +- [ ] Popup config options (Settings → General): + Popup content: default output only (default) | all outputs | active playback streams + Show level meter in popup: yes/no (saves vertical space) + +## Settings / Polish (do later) +- [ ] Settings dialog: switch from KDialogBase Tabbed to IconList style (like KMix) — + big sidebar icons (General, View, etc.) with page content on the right. +- [ ] Settings dialog: Defaults button, Help button +- [ ] Settings dialog: grey out Apply until a change is actually made +- [ ] Show/hide toggles for tickmarks, labels, level meters (View tab) +- [ ] KMix-style classic tray widget — large tray area showing default sink volume slider + directly in the panel (not a popup), like KMix's docked mixer strip. + +## Distribution / Integration +- [ ] .desktop file + icon +- [ ] CMake install rules (bin, desktop, icon) +- [ ] PipeWire-native backend (currently works via PW's PA compatibility layer) +- [ ] Package as trinity-mixer -- cgit v1.2.3