diff options
| -rw-r--r-- | CMakeLists.txt | 12 | ||||
| -rw-r--r-- | TODO | 5 | ||||
| -rw-r--r-- | img/crystal/audio-volume-error.png | bin | 0 -> 1176 bytes | |||
| -rw-r--r-- | img/crystal/audio-volume-high.png | bin | 0 -> 1581 bytes | |||
| -rw-r--r-- | img/crystal/audio-volume-low.png | bin | 0 -> 1379 bytes | |||
| -rw-r--r-- | img/crystal/audio-volume-medium.png | bin | 0 -> 1423 bytes | |||
| -rw-r--r-- | img/crystal/audio-volume-muted.png | bin | 0 -> 809 bytes | |||
| -rw-r--r-- | img/mix_ac97.png | bin | 0 -> 407 bytes | |||
| -rw-r--r-- | img/mix_audio.png | bin | 0 -> 170 bytes | |||
| -rw-r--r-- | img/mix_bass.png | bin | 0 -> 174 bytes | |||
| -rw-r--r-- | img/mix_cd.png | bin | 0 -> 233 bytes | |||
| -rw-r--r-- | img/mix_digital.png | bin | 0 -> 200 bytes | |||
| -rw-r--r-- | img/mix_ext.png | bin | 0 -> 156 bytes | |||
| -rw-r--r-- | img/mix_headphone.png | bin | 0 -> 261 bytes | |||
| -rw-r--r-- | img/mix_microphone.png | bin | 0 -> 190 bytes | |||
| -rw-r--r-- | img/mix_microphone_recording.png | bin | 0 -> 5794 bytes | |||
| -rw-r--r-- | img/mix_midi.png | bin | 0 -> 174 bytes | |||
| -rw-r--r-- | img/mix_record.png | bin | 0 -> 957 bytes | |||
| -rw-r--r-- | img/mix_surround.png | bin | 0 -> 204 bytes | |||
| -rw-r--r-- | img/mix_unknown.png | bin | 0 -> 172 bytes | |||
| -rw-r--r-- | img/mix_video.png | bin | 0 -> 145 bytes | |||
| -rw-r--r-- | img/mix_volume.png | bin | 0 -> 176 bytes | |||
| -rw-r--r-- | img/mixer.png | bin | 0 -> 196 bytes | |||
| -rw-r--r-- | img/tmix-16.png | bin | 0 -> 685 bytes | |||
| -rw-r--r-- | img/tmix-32.png | bin | 0 -> 1194 bytes | |||
| -rw-r--r-- | img/tmix-48.png | bin | 0 -> 1798 bytes | |||
| -rw-r--r-- | img/tmix.png | bin | 0 -> 758 bytes | |||
| -rw-r--r-- | src/model/pulsedevice.cpp | 19 | ||||
| -rw-r--r-- | src/model/pulsedevice.h | 2 | ||||
| -rw-r--r-- | src/model/pulsemodel.cpp | 55 | ||||
| -rw-r--r-- | src/model/pulsemodel.h | 3 | ||||
| -rw-r--r-- | src/ui/tmixtray.cpp | 2 |
32 files changed, 76 insertions, 22 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 310c5ca..5035d19 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,10 +35,14 @@ install( DESTINATION ${XDG_APPS_INSTALL_DIR} ) -install( - FILES img/tmix.png - DESTINATION ${DATA_INSTALL_DIR}/icons/hicolor/22x22/apps -) +install( FILES img/tmix-16.png RENAME tmix.png + DESTINATION ${DATA_INSTALL_DIR}/icons/hicolor/16x16/apps ) +install( FILES img/tmix.png + DESTINATION ${DATA_INSTALL_DIR}/icons/hicolor/22x22/apps ) +install( FILES img/tmix-32.png RENAME tmix.png + DESTINATION ${DATA_INSTALL_DIR}/icons/hicolor/32x32/apps ) +install( FILES img/tmix-48.png RENAME tmix.png + DESTINATION ${DATA_INSTALL_DIR}/icons/hicolor/48x48/apps ) tde_add_executable( tmix AUTOMOC SOURCES @@ -7,7 +7,6 @@ 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 @@ -48,7 +47,7 @@ Run through this before any release / major refactor. - [ ] 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) +- [ ] 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 @@ -208,8 +207,6 @@ about another; no generic UI code should check backend capabilities via flags. - [ ] 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 diff --git a/img/crystal/audio-volume-error.png b/img/crystal/audio-volume-error.png Binary files differnew file mode 100644 index 0000000..05b2767 --- /dev/null +++ b/img/crystal/audio-volume-error.png diff --git a/img/crystal/audio-volume-high.png b/img/crystal/audio-volume-high.png Binary files differnew file mode 100644 index 0000000..2c091e6 --- /dev/null +++ b/img/crystal/audio-volume-high.png diff --git a/img/crystal/audio-volume-low.png b/img/crystal/audio-volume-low.png Binary files differnew file mode 100644 index 0000000..6d3a341 --- /dev/null +++ b/img/crystal/audio-volume-low.png diff --git a/img/crystal/audio-volume-medium.png b/img/crystal/audio-volume-medium.png Binary files differnew file mode 100644 index 0000000..8b85e0e --- /dev/null +++ b/img/crystal/audio-volume-medium.png diff --git a/img/crystal/audio-volume-muted.png b/img/crystal/audio-volume-muted.png Binary files differnew file mode 100644 index 0000000..4872861 --- /dev/null +++ b/img/crystal/audio-volume-muted.png diff --git a/img/mix_ac97.png b/img/mix_ac97.png Binary files differnew file mode 100644 index 0000000..a17d285 --- /dev/null +++ b/img/mix_ac97.png diff --git a/img/mix_audio.png b/img/mix_audio.png Binary files differnew file mode 100644 index 0000000..c6a10d2 --- /dev/null +++ b/img/mix_audio.png diff --git a/img/mix_bass.png b/img/mix_bass.png Binary files differnew file mode 100644 index 0000000..acfdee9 --- /dev/null +++ b/img/mix_bass.png diff --git a/img/mix_cd.png b/img/mix_cd.png Binary files differnew file mode 100644 index 0000000..7b5ca31 --- /dev/null +++ b/img/mix_cd.png diff --git a/img/mix_digital.png b/img/mix_digital.png Binary files differnew file mode 100644 index 0000000..ac8dd54 --- /dev/null +++ b/img/mix_digital.png diff --git a/img/mix_ext.png b/img/mix_ext.png Binary files differnew file mode 100644 index 0000000..885307f --- /dev/null +++ b/img/mix_ext.png diff --git a/img/mix_headphone.png b/img/mix_headphone.png Binary files differnew file mode 100644 index 0000000..f583cf1 --- /dev/null +++ b/img/mix_headphone.png diff --git a/img/mix_microphone.png b/img/mix_microphone.png Binary files differnew file mode 100644 index 0000000..9079b3e --- /dev/null +++ b/img/mix_microphone.png diff --git a/img/mix_microphone_recording.png b/img/mix_microphone_recording.png Binary files differnew file mode 100644 index 0000000..78763a3 --- /dev/null +++ b/img/mix_microphone_recording.png diff --git a/img/mix_midi.png b/img/mix_midi.png Binary files differnew file mode 100644 index 0000000..acba2cb --- /dev/null +++ b/img/mix_midi.png diff --git a/img/mix_record.png b/img/mix_record.png Binary files differnew file mode 100644 index 0000000..e92c3a3 --- /dev/null +++ b/img/mix_record.png diff --git a/img/mix_surround.png b/img/mix_surround.png Binary files differnew file mode 100644 index 0000000..8c335e5 --- /dev/null +++ b/img/mix_surround.png diff --git a/img/mix_unknown.png b/img/mix_unknown.png Binary files differnew file mode 100644 index 0000000..ee586e3 --- /dev/null +++ b/img/mix_unknown.png diff --git a/img/mix_video.png b/img/mix_video.png Binary files differnew file mode 100644 index 0000000..dd5b32e --- /dev/null +++ b/img/mix_video.png diff --git a/img/mix_volume.png b/img/mix_volume.png Binary files differnew file mode 100644 index 0000000..8d4b89d --- /dev/null +++ b/img/mix_volume.png diff --git a/img/mixer.png b/img/mixer.png Binary files differnew file mode 100644 index 0000000..cf5878d --- /dev/null +++ b/img/mixer.png diff --git a/img/tmix-16.png b/img/tmix-16.png Binary files differnew file mode 100644 index 0000000..80ea05a --- /dev/null +++ b/img/tmix-16.png diff --git a/img/tmix-32.png b/img/tmix-32.png Binary files differnew file mode 100644 index 0000000..aaaee39 --- /dev/null +++ b/img/tmix-32.png diff --git a/img/tmix-48.png b/img/tmix-48.png Binary files differnew file mode 100644 index 0000000..2c6beaa --- /dev/null +++ b/img/tmix-48.png diff --git a/img/tmix.png b/img/tmix.png Binary files differnew file mode 100644 index 0000000..48dc497 --- /dev/null +++ b/img/tmix.png diff --git a/src/model/pulsedevice.cpp b/src/model/pulsedevice.cpp index 8bdea54..8fb8d48 100644 --- a/src/model/pulsedevice.cpp +++ b/src/model/pulsedevice.cpp @@ -45,15 +45,20 @@ void PulseDevice::setPAContext( pa_context *ctx, pa_threaded_mainloop *mainloop startMonitoring(); } -void PulseDevice::detach() +void PulseDevice::detach( bool paAlreadyDead ) { - if ( m_monitorStream && m_mainloop ) { - pa_threaded_mainloop_lock( m_mainloop ); - pa_stream_set_read_callback( m_monitorStream, 0, 0 ); - pa_stream_disconnect( m_monitorStream ); - pa_stream_unref( m_monitorStream ); + if ( m_monitorStream ) { + if ( paAlreadyDead ) { + pa_stream_set_read_callback( m_monitorStream, 0, 0 ); + pa_stream_unref( m_monitorStream ); + } else if ( m_mainloop ) { + pa_threaded_mainloop_lock( m_mainloop ); + pa_stream_set_read_callback( m_monitorStream, 0, 0 ); + pa_stream_disconnect( m_monitorStream ); + pa_stream_unref( m_monitorStream ); + pa_threaded_mainloop_unlock( m_mainloop ); + } m_monitorStream = 0; - pa_threaded_mainloop_unlock( m_mainloop ); } m_context = 0; m_mainloop = 0; diff --git a/src/model/pulsedevice.h b/src/model/pulsedevice.h index e974508..27aca02 100644 --- a/src/model/pulsedevice.h +++ b/src/model/pulsedevice.h @@ -40,7 +40,7 @@ public: TQWidget *createWidget( TQWidget *parent ); void setPAContext( pa_context *ctx, pa_threaded_mainloop *mainloop ); - void detach(); // called by PulseModel before tearing down the mainloop + void detach( bool paAlreadyDead = false ); protected: void customEvent( TQCustomEvent *e ); diff --git a/src/model/pulsemodel.cpp b/src/model/pulsemodel.cpp index 640b918..49a17c2 100644 --- a/src/model/pulsemodel.cpp +++ b/src/model/pulsemodel.cpp @@ -2,11 +2,13 @@ #include "pulsedevice.h" #include <tqapplication.h> +#include <tqtimer.h> // Custom events posted from the PA thread to the main thread. static const int PA_EVENT = TQEvent::User + 1; static const int PA_SERVER_EVENT = TQEvent::User + 3; static const int PA_CARD_EVENT = TQEvent::User + 4; +static const int PA_DIED_EVENT = TQEvent::User + 5; struct PAServerEvent : public TQCustomEvent { TQString defaultSinkName; @@ -183,18 +185,27 @@ bool PulseModel::open() void PulseModel::close() { - // Detach monitor streams on all devices before tearing down the mainloop. TQPtrList<PulseDevice> *allLists[4] = { &m_sinks, &m_sources, &m_sinkInputs, &m_sourceOutputs }; + + bool alreadyDead = false; + if ( m_context ) { + pa_context_state_t state = pa_context_get_state( m_context ); + alreadyDead = ( state == PA_CONTEXT_FAILED || + state == PA_CONTEXT_TERMINATED ); + } + for ( int i = 0; i < 4; i++ ) for ( TQPtrListIterator<PulseDevice> it(*allLists[i]); *it; ++it ) - (*it)->detach(); + (*it)->detach( alreadyDead ); if ( m_context ) { - pa_threaded_mainloop_lock( m_mainloop ); - pa_context_disconnect( m_context ); + if ( !alreadyDead ) { + pa_threaded_mainloop_lock( m_mainloop ); + pa_context_disconnect( m_context ); + pa_threaded_mainloop_unlock( m_mainloop ); + } pa_context_unref( m_context ); m_context = 0; - pa_threaded_mainloop_unlock( m_mainloop ); } if ( m_mainloop ) { pa_threaded_mainloop_stop( m_mainloop ); @@ -247,6 +258,7 @@ void PulseModel::contextStateCb( pa_context *c, void *userdata ) break; case PA_CONTEXT_FAILED: case PA_CONTEXT_TERMINATED: + TQApplication::postEvent( self, new TQCustomEvent(PA_DIED_EVENT) ); break; default: break; @@ -437,8 +449,41 @@ void PulseModel::cardInfoCb( pa_context *, const pa_card_info *info, int eol, vo // ---- main thread event handler ---------------------------------------------- +void PulseModel::reconnect() +{ + open(); +} + void PulseModel::customEvent( TQCustomEvent *e ) { + if ( e->type() == PA_DIED_EVENT ) { + if ( !m_mainloop ) return; // already handling a previous die event + // Notify UI that all devices are gone, then tear down and retry. + TQPtrList<PulseDevice> *allLists[4] = { &m_sinks, &m_sources, &m_sinkInputs, &m_sourceOutputs }; + for ( int i = 0; i < 4; i++ ) { + TQPtrListIterator<PulseDevice> it( *allLists[i] ); + while ( *it ) { + PulseDevice *dev = *it; + ++it; + emit deviceRemoved( dev ); + } + } + // Zero out default-device pointers in connected UI before devices are deleted. + emit defaultOutputChanged( 0 ); + emit defaultInputChanged( 0 ); + // Sever all remaining signal connections on every device so that + // close() can delete them safely regardless of cross-device wiring. + for ( int i = 0; i < 4; i++ ) + for ( TQPtrListIterator<PulseDevice> it( *allLists[i] ); *it; ++it ) + disconnect( *it, 0, 0, 0 ); + m_sinksByName.clear(); + m_sourcesByName.clear(); + m_sourceOutputToSource.clear(); + m_cards.clear(); + close(); + TQTimer::singleShot( 2000, this, TQ_SLOT(reconnect()) ); + return; + } if ( e->type() == PA_CARD_EVENT ) { PACardEvent *ev = static_cast<PACardEvent *>(e); if ( ev->removed ) { diff --git a/src/model/pulsemodel.h b/src/model/pulsemodel.h index 52e379f..c1d4561 100644 --- a/src/model/pulsemodel.h +++ b/src/model/pulsemodel.h @@ -80,6 +80,9 @@ signals: void cardRemoved( uint32_t index ); void cardUpdated( uint32_t index ); +private slots: + void reconnect(); + private: static void contextStateCb( pa_context *c, void *userdata ); static void serverInfoCb( pa_context *c, const pa_server_info *info, void *userdata ); diff --git a/src/ui/tmixtray.cpp b/src/ui/tmixtray.cpp index 4048270..e452d71 100644 --- a/src/ui/tmixtray.cpp +++ b/src/ui/tmixtray.cpp @@ -43,7 +43,7 @@ TmixTray::TmixTray( TQWidget *parent ) setCaption( i18n("Volume Control") ); TQPixmap titleIcon = TDEGlobal::iconLoader()->loadIcon( - "kmix", TDEIcon::Small, 16, TDEIcon::DefaultState, 0, true ); + "tmix", TDEIcon::Small, 16, TDEIcon::DefaultState, 0, true ); if ( titleIcon.isNull() ) titleIcon = TDEGlobal::iconLoader()->loadIcon( "audio-volume-medium", TDEIcon::Small, 16, TDEIcon::DefaultState, 0, true ); |
