summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt12
-rw-r--r--TODO5
-rw-r--r--img/crystal/audio-volume-error.pngbin0 -> 1176 bytes
-rw-r--r--img/crystal/audio-volume-high.pngbin0 -> 1581 bytes
-rw-r--r--img/crystal/audio-volume-low.pngbin0 -> 1379 bytes
-rw-r--r--img/crystal/audio-volume-medium.pngbin0 -> 1423 bytes
-rw-r--r--img/crystal/audio-volume-muted.pngbin0 -> 809 bytes
-rw-r--r--img/mix_ac97.pngbin0 -> 407 bytes
-rw-r--r--img/mix_audio.pngbin0 -> 170 bytes
-rw-r--r--img/mix_bass.pngbin0 -> 174 bytes
-rw-r--r--img/mix_cd.pngbin0 -> 233 bytes
-rw-r--r--img/mix_digital.pngbin0 -> 200 bytes
-rw-r--r--img/mix_ext.pngbin0 -> 156 bytes
-rw-r--r--img/mix_headphone.pngbin0 -> 261 bytes
-rw-r--r--img/mix_microphone.pngbin0 -> 190 bytes
-rw-r--r--img/mix_microphone_recording.pngbin0 -> 5794 bytes
-rw-r--r--img/mix_midi.pngbin0 -> 174 bytes
-rw-r--r--img/mix_record.pngbin0 -> 957 bytes
-rw-r--r--img/mix_surround.pngbin0 -> 204 bytes
-rw-r--r--img/mix_unknown.pngbin0 -> 172 bytes
-rw-r--r--img/mix_video.pngbin0 -> 145 bytes
-rw-r--r--img/mix_volume.pngbin0 -> 176 bytes
-rw-r--r--img/mixer.pngbin0 -> 196 bytes
-rw-r--r--img/tmix-16.pngbin0 -> 685 bytes
-rw-r--r--img/tmix-32.pngbin0 -> 1194 bytes
-rw-r--r--img/tmix-48.pngbin0 -> 1798 bytes
-rw-r--r--img/tmix.pngbin0 -> 758 bytes
-rw-r--r--src/model/pulsedevice.cpp19
-rw-r--r--src/model/pulsedevice.h2
-rw-r--r--src/model/pulsemodel.cpp55
-rw-r--r--src/model/pulsemodel.h3
-rw-r--r--src/ui/tmixtray.cpp2
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
diff --git a/TODO b/TODO
index dd0e902..c53933e 100644
--- a/TODO
+++ b/TODO
@@ -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
new file mode 100644
index 0000000..05b2767
--- /dev/null
+++ b/img/crystal/audio-volume-error.png
Binary files differ
diff --git a/img/crystal/audio-volume-high.png b/img/crystal/audio-volume-high.png
new file mode 100644
index 0000000..2c091e6
--- /dev/null
+++ b/img/crystal/audio-volume-high.png
Binary files differ
diff --git a/img/crystal/audio-volume-low.png b/img/crystal/audio-volume-low.png
new file mode 100644
index 0000000..6d3a341
--- /dev/null
+++ b/img/crystal/audio-volume-low.png
Binary files differ
diff --git a/img/crystal/audio-volume-medium.png b/img/crystal/audio-volume-medium.png
new file mode 100644
index 0000000..8b85e0e
--- /dev/null
+++ b/img/crystal/audio-volume-medium.png
Binary files differ
diff --git a/img/crystal/audio-volume-muted.png b/img/crystal/audio-volume-muted.png
new file mode 100644
index 0000000..4872861
--- /dev/null
+++ b/img/crystal/audio-volume-muted.png
Binary files differ
diff --git a/img/mix_ac97.png b/img/mix_ac97.png
new file mode 100644
index 0000000..a17d285
--- /dev/null
+++ b/img/mix_ac97.png
Binary files differ
diff --git a/img/mix_audio.png b/img/mix_audio.png
new file mode 100644
index 0000000..c6a10d2
--- /dev/null
+++ b/img/mix_audio.png
Binary files differ
diff --git a/img/mix_bass.png b/img/mix_bass.png
new file mode 100644
index 0000000..acfdee9
--- /dev/null
+++ b/img/mix_bass.png
Binary files differ
diff --git a/img/mix_cd.png b/img/mix_cd.png
new file mode 100644
index 0000000..7b5ca31
--- /dev/null
+++ b/img/mix_cd.png
Binary files differ
diff --git a/img/mix_digital.png b/img/mix_digital.png
new file mode 100644
index 0000000..ac8dd54
--- /dev/null
+++ b/img/mix_digital.png
Binary files differ
diff --git a/img/mix_ext.png b/img/mix_ext.png
new file mode 100644
index 0000000..885307f
--- /dev/null
+++ b/img/mix_ext.png
Binary files differ
diff --git a/img/mix_headphone.png b/img/mix_headphone.png
new file mode 100644
index 0000000..f583cf1
--- /dev/null
+++ b/img/mix_headphone.png
Binary files differ
diff --git a/img/mix_microphone.png b/img/mix_microphone.png
new file mode 100644
index 0000000..9079b3e
--- /dev/null
+++ b/img/mix_microphone.png
Binary files differ
diff --git a/img/mix_microphone_recording.png b/img/mix_microphone_recording.png
new file mode 100644
index 0000000..78763a3
--- /dev/null
+++ b/img/mix_microphone_recording.png
Binary files differ
diff --git a/img/mix_midi.png b/img/mix_midi.png
new file mode 100644
index 0000000..acba2cb
--- /dev/null
+++ b/img/mix_midi.png
Binary files differ
diff --git a/img/mix_record.png b/img/mix_record.png
new file mode 100644
index 0000000..e92c3a3
--- /dev/null
+++ b/img/mix_record.png
Binary files differ
diff --git a/img/mix_surround.png b/img/mix_surround.png
new file mode 100644
index 0000000..8c335e5
--- /dev/null
+++ b/img/mix_surround.png
Binary files differ
diff --git a/img/mix_unknown.png b/img/mix_unknown.png
new file mode 100644
index 0000000..ee586e3
--- /dev/null
+++ b/img/mix_unknown.png
Binary files differ
diff --git a/img/mix_video.png b/img/mix_video.png
new file mode 100644
index 0000000..dd5b32e
--- /dev/null
+++ b/img/mix_video.png
Binary files differ
diff --git a/img/mix_volume.png b/img/mix_volume.png
new file mode 100644
index 0000000..8d4b89d
--- /dev/null
+++ b/img/mix_volume.png
Binary files differ
diff --git a/img/mixer.png b/img/mixer.png
new file mode 100644
index 0000000..cf5878d
--- /dev/null
+++ b/img/mixer.png
Binary files differ
diff --git a/img/tmix-16.png b/img/tmix-16.png
new file mode 100644
index 0000000..80ea05a
--- /dev/null
+++ b/img/tmix-16.png
Binary files differ
diff --git a/img/tmix-32.png b/img/tmix-32.png
new file mode 100644
index 0000000..aaaee39
--- /dev/null
+++ b/img/tmix-32.png
Binary files differ
diff --git a/img/tmix-48.png b/img/tmix-48.png
new file mode 100644
index 0000000..2c6beaa
--- /dev/null
+++ b/img/tmix-48.png
Binary files differ
diff --git a/img/tmix.png b/img/tmix.png
new file mode 100644
index 0000000..48dc497
--- /dev/null
+++ b/img/tmix.png
Binary files differ
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 );