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)
- [ ] 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: meter shows source level (forwarded from parent source signal)
- [ ] 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, false modal param in KDialogBase ctor)
- [ ] 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)
- [x] Port switching in Devices tab — Output port / Input port dropdowns per card
      (pa_context_set_sink_port_by_index / set_source_port_by_index); only shown
      when a sink/source has 2+ ports. Active port updates in-place on PA events.
- [ ] 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.
- [ ] DCOP interface (get/set volume, mute, list devices)
- [ ] 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)

## 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
