[kdemultimedia] kmix crashes when pulseaudio exits (#804363)
Rex Dieter
rdieter at fedoraproject.org
Tue Apr 24 12:34:19 UTC 2012
commit 081a614cf2f586c07f5978764077699a8f93898f
Author: Rex Dieter <rdieter at fedoraproject.org>
Date: Tue Apr 24 07:35:03 2012 -0500
kmix crashes when pulseaudio exits (#804363)
- kmix is crashing after multiple volume changes (kde#290742)
kdemultimedia-4.8.2-kmix_backport.patch | 4445 +++++++++++++++++++++++++++++++
kdemultimedia.spec | 13 +-
2 files changed, 4457 insertions(+), 1 deletions(-)
---
diff --git a/kdemultimedia-4.8.2-kmix_backport.patch b/kdemultimedia-4.8.2-kmix_backport.patch
new file mode 100644
index 0000000..3d9d0d9
--- /dev/null
+++ b/kdemultimedia-4.8.2-kmix_backport.patch
@@ -0,0 +1,4445 @@
+Index: kmix.desktop
+===================================================================
+--- kmix.desktop (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ kmix.desktop (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -109,6 +109,7 @@
+ Name[hne]=के-मिक्स
+ Name[hr]=KMix
+ Name[hu]=KMix
++Name[id]=KMix
+ Name[is]=KMix
+ Name[it]=KMix
+ Name[ja]=KMix
+Index: ConfigureChecks.cmake
+===================================================================
+--- ConfigureChecks.cmake (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ ConfigureChecks.cmake (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -7,16 +7,8 @@
+ # definitions like _GNU_SOURCE that are needed on each platform.
+ set(CMAKE_REQUIRED_DEFINITIONS ${_KDE4_PLATFORM_DEFINITIONS})
+
+-macro_bool_to_01(CARBON_FOUND HAVE_CARBON)
+-
+-macro_bool_to_01(AKODE_FOUND HAVE_AKODE)
+-
+ macro_bool_to_01(OGGVORBIS_FOUND HAVE_VORBIS)
+
+-macro_bool_to_01(X11_XShm_FOUND HAVE_XSHMGETEVENTBASE)
+-
+-macro_bool_to_01(PULSEAUDIO_FOUND HAVE_PULSE)
+-
+ #now check for dlfcn.h using the cmake supplied CHECK_include_FILE() macro
+ # If definitions like -D_GNU_SOURCE are needed for these checks they
+ # should be added to _KDE4_PLATFORM_DEFINITIONS when it is originally
+@@ -29,20 +21,8 @@
+ set(CMAKE_REQUIRED_INCLUDES ${KDEWIN32_INCLUDES} )
+ endif (WIN32)
+
+-check_include_files(machine/soundcard.h HAVE_MACHINE_SOUNDCARD_H)
+-check_include_files(soundcard.h HAVE_SOUNDCARD_H)
+-check_include_files(sys/soundcard.h HAVE_SYS_SOUNDCARD_H)
+-check_include_files(sys/stat.h HAVE_SYS_STAT_H)
+-check_include_files(linux/cdrom.h HAVE_LINUX_CDROM_H)
+-check_include_files(linux/ucdrom.h HAVE_LINUX_UCDROM_H)
+ check_include_files(machine/endian.h HAVE_MACHINE_ENDIAN_H)
+-check_include_files(sys/audioio.h HAVE_SYS_AUDIOIO_H)
+-check_include_files(Alib.h HAVE_ALIB_H)
+-check_include_files(alloca.h HAVE_ALLOCA_H)
+ # Linux has <endian.h>, FreeBSD has <sys/endian.h> and Solaris has neither.
+ check_include_files(endian.h HAVE_ENDIAN_H)
+ check_include_files(sys/endian.h HAVE_SYS_ENDIAN_H)
+ check_include_files(unistd.h HAVE_UNISTD_H)
+-
+-check_type_size("long" SIZEOF_LONG)
+-
+Index: kmixd.desktop
+===================================================================
+--- kmixd.desktop (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ kmixd.desktop (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -20,6 +20,7 @@
+ Name[gl]=KMixD
+ Name[hr]=KMixD
+ Name[hu]=KMixD
++Name[id]=KMixD
+ Name[is]=KMixD
+ Name[it]=KMixD
+ Name[ja]=KMixD
+Index: gui/mdwslider.h
+===================================================================
+--- gui/mdwslider.h (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ gui/mdwslider.h (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -52,7 +52,7 @@
+ Q_OBJECT
+
+ public:
+- MDWSlider( MixDevice* md,
++ MDWSlider( shared_ptr<MixDevice> md,
+ bool includePlayback, bool includeCapture,
+ bool small, Qt::Orientation,
+ QWidget* parent, ViewBase* view, ProfControl *pctl);
+Index: gui/viewbase.cpp
+===================================================================
+--- gui/viewbase.cpp (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ gui/viewbase.cpp (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -49,7 +49,6 @@
+ setObjectName(id);
+ m_viewId = id;
+ _mixer = mixer;
+- _mixSet = new MixSet();
+
+ // This must be populated now otherwise bad things happen (circular dependancies etc
+ // This is due to the fact that setMixSet() calls isDynamic() which in turn needs a populated
+@@ -89,7 +88,6 @@
+ }
+
+ ViewBase::~ViewBase() {
+- delete _mixSet;
+ // Hint: The GUI profile will not be removed, as it is pooled and might be applied to a new View.
+ }
+
+@@ -103,7 +101,7 @@
+
+ bool ViewBase::isValid() const
+ {
+- return ( _mixSet->count() > 0 || isDynamic() );
++ return ( !_mixSet.isEmpty() || isDynamic() );
+ }
+
+ void ViewBase::setIcons (bool on) { KMixToolBox::setIcons (_mdws, on ); }
+@@ -119,25 +117,13 @@
+ */
+ void ViewBase::createDeviceWidgets()
+ {
+- // create devices
+- foreach ( MixDevice* md, *_mixSet )
++ foreach ( shared_ptr<MixDevice> md, _mixSet )
+ {
+ QWidget* mdw = add(md); // a) Let the View implementation do its work
+ _mdws.append(mdw); // b) Add it to the local list
+ }
+ // allow view to "polish" itself
+ constructionFinished();
+-
+-// Moved the following up one Level to KMixerWidget
+-// kDebug() << "CONNECT ViewBase count " << _mixers.size();
+-// foreach ( Mixer* mixer, _mixers )
+-// {
+-// kDebug(67100) << "CONNECT ViewBase controlschanged" << mixer->id();
+-// connect ( mixer, SIGNAL(controlChanged()), this, SLOT(refreshVolumeLevels()) );
+-// connect ( mixer, SIGNAL(controlsReconfigured(QString)), this, SLOT(controlsReconfigured(QString)) );
+-// }
+-
+-
+ }
+
+ /**
+@@ -214,9 +200,9 @@
+
+ if (isRelevantMixer)
+ {
+- kDebug(67100) << "ViewBase::controlsReconfigured() " << mixer_ID << " is being redrawn (mixset contains: " << _mixSet->count() << ")";
++ kDebug(67100) << "ViewBase::controlsReconfigured() " << mixer_ID << " is being redrawn (mixset contains: " << _mixSet.count() << ")";
+ setMixSet();
+- kDebug(67100) << "ViewBase::controlsReconfigured() " << mixer_ID << ": Recreating widgets (mixset contains: " << _mixSet->count() << ")";
++ kDebug(67100) << "ViewBase::controlsReconfigured() " << mixer_ID << ": Recreating widgets (mixset contains: " << _mixSet.count() << ")";
+ createDeviceWidgets();
+ }
+ }
+@@ -249,13 +235,13 @@
+ while (!_mdws.isEmpty())
+ delete _mdws.takeFirst();
+
+- _mixSet->clear(); // Clean up our _mixSet so we can reapply our GUIProfile
++ _mixSet.clear(); // Clean up our _mixSet so we can reapply our GUIProfile
+ }
+ _setMixSet();
+
+ _mixers.clear();
+ _mixers.insert(_mixer);
+- foreach ( MixDevice* md, *_mixSet )
++ foreach ( shared_ptr<MixDevice> md, _mixSet )
+ {
+ // kDebug() << "VVV Add to " << md->mixer()->id();
+ // MixDeviceWidget* mdw = qobject_cast<MixDeviceWidget*>(qw);
+@@ -321,7 +307,7 @@
+ Workaround: If found, write back correct group name.
+ */
+ MixDeviceWidget* mdw = (MixDeviceWidget*)qmdw;
+- MixDevice* md = mdw->mixDevice();
++ shared_ptr<MixDevice> md = mdw->mixDevice();
+
+ QString devgrp = QString("%1.%2.%3").arg(grp).arg(md->mixer()->id()).arg(md->id());
+ KConfigGroup devcg = config->group( devgrp );
+@@ -398,7 +384,7 @@
+ if ( qmdw->inherits("MixDeviceWidget") )
+ {
+ MixDeviceWidget* mdw = (MixDeviceWidget*)qmdw;
+- MixDevice* md = mdw->mixDevice();
++ shared_ptr<MixDevice> md = mdw->mixDevice();
+
+ //kDebug(67100) << " grp=" << grp.toAscii();
+ //kDebug(67100) << " mixer=" << view->id().toAscii();
+Index: gui/viewsliders.h
+===================================================================
+--- gui/viewsliders.h (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ gui/viewsliders.h (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -25,6 +25,7 @@
+ //class QFormLayout;
+ #include <QFrame>
+ #include <QHash>
++class QLabel;
+ class QWidget;
+
+ class Mixer;
+@@ -35,9 +36,9 @@
+ Q_OBJECT
+ public:
+ ViewSliders(QWidget* parent, const char* name, Mixer* mixer, ViewBase::ViewFlags vflags, GUIProfile *guiprof, KActionCollection *actColl);
+- ~ViewSliders();
++ virtual ~ViewSliders();
+
+- virtual QWidget* add(MixDevice *mdw);
++ virtual QWidget* add(shared_ptr<MixDevice>);
+ virtual void constructionFinished();
+ virtual void configurationUpdate();
+
+@@ -52,6 +53,7 @@
+ QLayout* _layoutSliders;
+ QLayout* _layoutEnum;
+ QHash<QString,QFrame*> _separators;
++ QLabel* emptyStreamHint;
+ };
+
+ #endif
+Index: gui/kmixerwidget.h
+===================================================================
+--- gui/kmixerwidget.h (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ gui/kmixerwidget.h (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -91,7 +91,6 @@
+
+ void createLayout(ViewBase::ViewFlags vflags);
+ bool possiblyAddView(ViewBase* vbase);
+- void createViewsByProfile(Mixer* mixer, GUIProfile *guiprof, ViewBase::ViewFlags vflags);
+ };
+
+ #endif
+Index: gui/dialogselectmaster.cpp
+===================================================================
+--- gui/dialogselectmaster.cpp (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ gui/dialogselectmaster.cpp (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -19,6 +19,8 @@
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
++#include "gui/dialogselectmaster.h"
++
+ #include <qbuttongroup.h>
+ #include <QLabel>
+ #include <qradiobutton.h>
+@@ -30,7 +32,6 @@
+ #include <kdebug.h>
+ #include <klocale.h>
+
+-#include "gui/dialogselectmaster.h"
+ #include "core/mixdevice.h"
+ #include "core/mixer.h"
+
+@@ -159,16 +160,18 @@
+ m_vboxForScrollView = new KVBox(); //m_scrollableChannelSelector->viewport()
+
+ QString masterKey = "----noMaster---"; // Use a non-matching name as default
+- MixDevice* master = mixer->getLocalMasterMD();
+- if ( master != 0 ) masterKey = master->id();
++ shared_ptr<MixDevice> master = mixer->getLocalMasterMD();
++ if ( master.get() != 0 )
++ masterKey = master->id();
+
+ const MixSet& mixset = mixer->getMixSet();
+ MixSet& mset = const_cast<MixSet&>(mixset);
+ for( int i=0; i< mset.count(); ++i )
+ {
+- MixDevice* md = mset[i];
++ shared_ptr<MixDevice> md = mset[i];
+ // Create a RadioButton for each MixDevice (excluding Enum's)
+- if ( md->playbackVolume().hasVolume() ) {
++ if ( md->playbackVolume().hasVolume() )
++ {
+ // kDebug(67100) << "DialogSelectMaster::createPage() mset append qrb";
+ QString mdName = md->readableName();
+ mdName.replace('&', "&&"); // Quoting the '&' needed, to prevent QRadioButton creating an accelerator
+Index: gui/mdwmoveaction.cpp
+===================================================================
+--- gui/mdwmoveaction.cpp (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ gui/mdwmoveaction.cpp (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -27,7 +27,7 @@
+ // Qt
+ #include <QString>
+
+-MDWMoveAction::MDWMoveAction(MixDevice* md, QObject *parent)
++MDWMoveAction::MDWMoveAction(shared_ptr<MixDevice> md, QObject *parent)
+ : KAction(parent), m_mixDevice(md)
+ {
+ Q_ASSERT(md);
+Index: gui/kmixtoolbox.cpp
+===================================================================
+--- gui/kmixtoolbox.cpp (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ gui/kmixtoolbox.cpp (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -19,6 +19,7 @@
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
++#include "gui/kmixtoolbox.h"
+
+ #include <QWidget>
+ #include <QString>
+@@ -35,7 +36,8 @@
+ #include "core/mixer.h"
+ #include "viewbase.h"
+
+-#include "gui/kmixtoolbox.h"
++// TODO KMixToolbox is rather superfluous today, as there is no "KMix Applet" any more, and it was probably always bad style.
++// I only have to think what to do with KMixToolBox::notification()
+
+ /***********************************************************************************
+ KMixToolbox contains several GUI relevant methods that are shared between the
+Index: gui/mdwenum.h
+===================================================================
+--- gui/mdwenum.h (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ gui/mdwenum.h (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -45,7 +45,7 @@
+ Q_OBJECT
+
+ public:
+- MDWEnum( MixDevice* md,
++ MDWEnum( shared_ptr<MixDevice> md,
+ Qt::Orientation orientation,
+ QWidget* parent, ViewBase* view, ProfControl* pctl);
+ ~MDWEnum();
+Index: gui/kmixprefdlg.h
+===================================================================
+--- gui/kmixprefdlg.h (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ gui/kmixprefdlg.h (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -26,6 +26,7 @@
+
+ class KMixPrefWidget;
+ class QCheckBox;
++class QFrame;
+ class QRadioButton;
+
+ class
+@@ -37,7 +38,7 @@
+
+ public:
+ KMixPrefDlg( QWidget *parent );
+- ~KMixPrefDlg();
++ virtual ~KMixPrefDlg();
+
+ signals:
+ void signalApplied( KMixPrefDlg *prefDlg );
+Index: gui/kmixdockwidget.h
+===================================================================
+--- gui/kmixdockwidget.h (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ gui/kmixdockwidget.h (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -25,7 +25,7 @@
+
+ class QString;
+ #include <QWidget>
+-
++class QWidgetAction;
+ #include <kstatusnotifieritem.h>
+
+ class KMixWindow;
+@@ -46,7 +46,7 @@
+
+ public:
+ explicit KMixDockWidget(KMixWindow *parent,bool volumePopup);
+- ~KMixDockWidget();
++ virtual ~KMixDockWidget();
+
+ void setErrorPixmap();
+ void ignoreNextEvent();
+Index: gui/ksmallslider.cpp
+===================================================================
+--- gui/ksmallslider.cpp (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ gui/ksmallslider.cpp (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -19,6 +19,8 @@
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
++#include "gui/ksmallslider.h"
++
+ // For INT_MAX
+ #include <limits.h>
+
+@@ -33,7 +35,6 @@
+ #include <QStyleOptionSlider>
+
+ #include "kglobalsettings.h"
+-#include "ksmallslider.h"
+ #include "core/mixer.h"
+
+ KSmallSlider::KSmallSlider( int minValue, int maxValue, int pageStep,
+Index: gui/mixdevicewidget.h
+===================================================================
+--- gui/mixdevicewidget.h (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ gui/mixdevicewidget.h (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -26,6 +26,7 @@
+ #define MIXDEVICEWIDGET_H
+
+ #include <QWidget>
++#include "core/mixdevice.h"
+ #include "core/volume.h"
+ #include <qpixmap.h>
+
+@@ -44,7 +45,7 @@
+ Q_OBJECT
+
+ public:
+- MixDeviceWidget( MixDevice* md,
++ MixDeviceWidget( shared_ptr<MixDevice> md,
+ bool small, Qt::Orientation orientation,
+ QWidget* parent, ViewBase*, ProfControl * );
+ virtual ~MixDeviceWidget();
+@@ -52,7 +53,7 @@
+ void addActionToPopup( KAction *action );
+
+ virtual bool isDisabled() const;
+- MixDevice* mixDevice() { return m_mixdevice; }
++ shared_ptr<MixDevice> mixDevice() { return m_mixdevice; }
+
+ virtual void setColors( QColor high, QColor low, QColor back );
+ virtual void setIcons( bool value );
+@@ -77,7 +78,7 @@
+
+ protected:
+
+- MixDevice* m_mixdevice;
++ shared_ptr<MixDevice> m_mixdevice;
+ KActionCollection* _mdwActions;
+ KActionCollection* _mdwPopupActions;
+ ViewBase* m_view;
+Index: gui/mdwslider.cpp
+===================================================================
+--- gui/mdwslider.cpp (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ gui/mdwslider.cpp (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -19,6 +19,8 @@
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
++#include "gui/mdwslider.h"
++
+ #include <klocale.h>
+ #include <kiconloader.h>
+ #include <kconfig.h>
+@@ -40,20 +42,19 @@
+ #include <qwmatrix.h>
+ #include <QBoxLayout>
+
++#include "core/mixer.h"
+ #include "gui/guiprofile.h"
+-#include "mdwslider.h"
+-#include "volumeslider.h"
+-#include "core/mixer.h"
+-#include "viewbase.h"
+-#include "ksmallslider.h"
+-#include "verticaltext.h"
+-#include "mdwmoveaction.h"
++#include "gui/volumeslider.h"
++#include "gui/viewbase.h"
++#include "gui/ksmallslider.h"
++#include "gui/verticaltext.h"
++#include "gui/mdwmoveaction.h"
+
+
+ VolumeSliderExtraData MDWSlider::DummVolumeSliderExtraData;
+ bool MDWSlider::debugMe = false;
+ /**
+- * MixDeviceWidget that represents a single mix device, inlcuding PopUp, muteLED, ...
++ * MixDeviceWidget that represents a single mix device, including PopUp, muteLED, ...
+ *
+ * Used in KMix main window and DockWidget and PanelApplet.
+ * It can be configured to include or exclude the captureLED and the muteLED.
+@@ -62,7 +63,7 @@
+ *
+ * Due to the many options, this is the most complicated MixDeviceWidget subclass.
+ */
+-MDWSlider::MDWSlider(MixDevice* md, bool showMuteLED, bool showCaptureLED,
++MDWSlider::MDWSlider(shared_ptr<MixDevice> md, bool showMuteLED, bool showCaptureLED,
+ bool small, Qt::Orientation orientation, QWidget* parent
+ , ViewBase* view
+ , ProfControl* par_ctl
+@@ -91,6 +92,13 @@
+ {
+ delete slider;
+ }
++
++ /*
++ static int destructorCalls = 1;
++ kDebug() << "Destroying id=" << this->mixDevice()->id() << "desctructorCalls=" << destructorCalls;
++ ++destructorCalls;
++ */
++
+ }
+
+ void MDWSlider::createActions()
+@@ -546,7 +554,7 @@
+ QWidget *subcontrolLabel;
+
+ QString subcontrolTranslation;
+- if ( type == 'c' ) subcontrolTranslation += i18n("Capture") + " ";
++ if ( type == 'c' ) subcontrolTranslation += i18n("Capture") + ' ';
+ subcontrolTranslation += Volume::ChannelNameReadable[vc.chid]; //Volume::getSubcontrolTranslation(chid);
+ subcontrolLabel = createLabel(this, subcontrolTranslation, volLayout, true);
+
+@@ -858,29 +866,19 @@
+
+ void MDWSlider::volumeChangeInternal( Volume& vol, QList<QAbstractSlider *>& ref_sliders )
+ {
+-
+- // --- Step 2: Change the volumes directly in the Volume object to reflect the Sliders ---
+ if ( isStereoLinked() )
+ {
+ QAbstractSlider* firstSlider = ref_sliders.first();
+- long firstVolume = firstSlider->value();
+- //kDebug(67100) << "firstVolume=" <<firstVolume;
+- vol.setAllVolumes(firstVolume);
+- } // stereoLinked()
+-
+- else {
+-
+- QAbstractSlider* firstSlider = ref_sliders.first();
+- long firstVolume = firstSlider->value();
+- //kDebug(67100) << "firstVolume=" <<firstVolume;
+-
+- for( int i=0; i<ref_sliders.count(); i++ ) {
++ vol.setAllVolumes(firstSlider->value());
++ }
++ else
++ {
++ for( int i=0; i<ref_sliders.count(); i++ )
++ {
+ QAbstractSlider *sliderWidget = ref_sliders[i];
+ vol.setVolume( extraData(sliderWidget).getChid() ,sliderWidget->value());
+ } // iterate over all sliders
+- } // !stereoLinked()
+-
+- // --- Step 3: Write back the new volumes to the HW ---
++ }
+ }
+
+
+@@ -888,13 +886,15 @@
+ This slot is called, when a user has clicked the recsrc button. Also it is called by any other
+ associated KAction like the context menu.
+ */
+-void MDWSlider::toggleRecsrc() {
++void MDWSlider::toggleRecsrc()
++{
+ setRecsrc( m_mixdevice->isRecSource() );
+ }
+
+ void MDWSlider::setRecsrc(bool value )
+ {
+- if ( m_mixdevice->captureVolume().hasSwitch() ) {
++ if ( m_mixdevice->captureVolume().hasSwitch() )
++ {
+ m_mixdevice->setRecSource( value );
+ m_mixdevice->mixer()->commitVolumeChange( m_mixdevice );
+ }
+@@ -905,7 +905,8 @@
+ This slot is called, when a user has clicked the mute button. Also it is called by any other
+ associated KAction like the context menu.
+ */
+-void MDWSlider::toggleMuted() {
++void MDWSlider::toggleMuted()
++{
+ setMuted( !m_mixdevice->isMuted() );
+ }
+
+@@ -1128,8 +1129,8 @@
+ _mdwMoveActions->addAction( QString("-"), a);
+
+ m_moveMenu->addAction( a );
+- for (int i = 0; i < ms->count(); ++i) {
+- MixDevice* md = (*ms)[i];
++ foreach (shared_ptr<MixDevice> md, *ms)
++ {
+ a = new MDWMoveAction(md, _mdwMoveActions);
+ _mdwMoveActions->addAction( QString("moveto") + md->id(), a);
+ connect(a, SIGNAL(moveRequest(QString)), SLOT(moveStream(QString)));
+Index: gui/viewdockareapopup.h
+===================================================================
+--- gui/viewdockareapopup.h (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ gui/viewdockareapopup.h (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -35,9 +35,9 @@
+ Q_OBJECT
+ public:
+ ViewDockAreaPopup(QWidget* parent, const char* name, Mixer* mixer, ViewBase::ViewFlags vflags, GUIProfile *guiprof, KMixWindow *dockW);
+- ~ViewDockAreaPopup();
++ virtual ~ViewDockAreaPopup();
+
+- virtual QWidget* add(MixDevice *mdw);
++ virtual QWidget* add(shared_ptr<MixDevice> md);
+ virtual void constructionFinished();
+ virtual void refreshVolumeLevels();
+ virtual void showContextMenu();
+Index: gui/viewsliders.cpp
+===================================================================
+--- gui/viewsliders.cpp (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ gui/viewsliders.cpp (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -32,19 +32,22 @@
+ #endif
+ #endif
+
++#include "gui/viewsliders.h"
++
+ // KMix
+-#include "viewsliders.h"
+-#include "gui/guiprofile.h"
+-#include "mdwenum.h"
+-#include "mdwslider.h"
+ #include "core/mixdevicecomposite.h"
+ #include "core/mixer.h"
+-#include "verticaltext.h"
++#include "gui/guiprofile.h"
++#include "gui/mdwenum.h"
++#include "gui/mdwslider.h"
++#include "gui/verticaltext.h"
+
+ // KDE
+ #include <kdebug.h>
++#include <KLocale>
+
+ // Qt
++#include <QLabel>
+ #include <QWidget>
+ #include <QVBoxLayout>
+ #include <QHBoxLayout>
+@@ -55,6 +58,7 @@
+ /**
+ * Generic View implementation. This can hold now all kinds of controls (not just Sliders, as
+ * the class name suggests).
++ * TODO change "const char*" parameter to QString
+ */
+ ViewSliders::ViewSliders(QWidget* parent, const char* name, Mixer* mixer, ViewBase::ViewFlags vflags, GUIProfile *guiprof, KActionCollection *actColl)
+ : ViewBase(parent, name, mixer, Qt::FramelessWindowHint, vflags, guiprof, actColl)
+@@ -80,6 +84,28 @@
+ _layoutMDW->setSpacing(0);
+ _layoutMDW->addItem( _layoutSliders );
+
++ QString driverName = _mixer->getDriverName();
++
++
++ // Hint: This text comparison is not a clean solution, but one that will work for quite a while.
++ // TODO cesken Revise this "text comparison" thingy when I change the View constructor to take an "id" and a "readableName"
++ QString viewName(name);
++ if (viewName.contains(".Capture_Streams."))
++ emptyStreamHint = new QLabel(i18n("Capture Streams"));
++ else if (viewName.contains(".Playback_Streams."))
++ emptyStreamHint = new QLabel(i18n("Playback Streams"));
++ else if (viewName.contains(".Capture_Devices."))
++ emptyStreamHint = new QLabel(i18n("Capture Devices"));
++ else if (viewName.contains(".Playback_Devices."))
++ emptyStreamHint = new QLabel(i18n("Playback Devices"));
++ else
++ emptyStreamHint = new QLabel(i18n("Playback Streams")); // Fallback. Assume Playback stream
++
++ emptyStreamHint->setAlignment(Qt::AlignCenter);
++ emptyStreamHint->setWordWrap( true );
++ emptyStreamHint->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
++ _layoutMDW->addWidget(emptyStreamHint);
++
+ setMixSet();
+ }
+
+@@ -90,13 +116,12 @@
+
+
+
+-QWidget* ViewSliders::add(MixDevice *md)
++QWidget* ViewSliders::add(shared_ptr<MixDevice> md)
++
+ {
+ MixDeviceWidget *mdw;
+ Qt::Orientation orientation = (_vflags & ViewBase::Vertical) ? Qt::Horizontal : Qt::Vertical;
+
+-
+-
+ if ( md->isEnum() ) {
+ mdw = new MDWEnum(
+ md, // MixDevice (parameter)
+@@ -121,6 +146,7 @@
+ _frm->setFrameStyle(QFrame::HLine | QFrame::Sunken);
+ _separators.insert(md->id(),_frm);
+ _layoutSliders->addWidget(_frm);
++
+ mdw = new MDWSlider(
+ md, // MixDevice (parameter)
+ true, // Show Mute LED
+@@ -161,7 +187,7 @@
+
+
+ #ifdef TEST_MIXDEVICE_COMPOSITE
+- QList<MixDevice*> mds; // For temporary test
++ QList<shared_ptr<MixDevice> > mds; // For temporary test
+ #endif
+
+ // This method iterates the controls from the Profile
+@@ -180,19 +206,18 @@
+ //kDebug(67100) << "ViewSliders::setMixSet(): Check GUIProfile id==" << control->id << "\n";
+ // The following for-loop could be simplified by using a std::find_if
+ for ( int i=0; i<mixset.count(); i++ ) {
+- MixDevice *md = mixset[i];
++ shared_ptr<MixDevice> md = mixset[i];
+
+ if ( md->id().contains(idRegexp) )
+ {
+ // Match found (by name)
+- if ( _mixSet->contains( md ) ) continue; // dup check
++ if ( _mixSet.contains( md ) ) continue; // dup check
+
+ // Now check whether subcontrols match
+ bool subcontrolPlaybackWanted = (control->useSubcontrolPlayback() && ( md->playbackVolume().hasVolume() || md->playbackVolume().hasSwitch()) );
+ bool subcontrolCaptureWanted = (control->useSubcontrolCapture() && ( md->captureVolume() .hasVolume() || md->captureVolume() .hasSwitch()) );
+ bool subcontrolEnumWanted = (control->useSubcontrolEnum() && md->isEnum());
+ bool subcontrolWanted = subcontrolPlaybackWanted | subcontrolCaptureWanted | subcontrolEnumWanted;
+- bool splitWanted = control->isSplit();
+
+ if ( !subcontrolWanted ) continue;
+
+@@ -207,7 +232,7 @@
+ else if ( control->getSwitchtype() == "Off" )
+ md->playbackVolume().setSwitchType(Volume::OffSwitch);
+ }
+- _mixSet->append(md);
++ _mixSet.append(md);
+
+ #ifdef TEST_MIXDEVICE_COMPOSITE
+ if ( md->id() == "Front:0" || md->id() == "Surround:0") { mds.append(md); } // For temporary test
+@@ -224,6 +249,10 @@
+ }
+ } // iteration over all controls from the Profile
+
++ emptyStreamHint->setVisible( _mixSet.isEmpty() && isDynamic() ); // show a hint why a tab is empty (dynamic controls!!!)
++ // visibleControls() == 0 could be used for the !isDynamic() case
++
++
+ #ifdef TEST_MIXDEVICE_COMPOSITE
+ // @todo: This is currently hardcoded, and instead must be read as usual from the Profile
+ MixDeviceComposite *mdc = new MixDeviceComposite(_mixer, "Composite_Test", mds, "A Composite Control #1", MixDevice::KMIX_COMPOSITE);
+@@ -241,6 +270,7 @@
+
+ void ViewSliders::constructionFinished() {
+ configurationUpdate();
++ // TODO Add a "show more" / "configure this view" button
+ }
+
+
+@@ -274,6 +304,7 @@
+ if ( thisControlIsVisible ) firstVisibleControlFound=true;
+ }
+ } // for all MDW's
++
+ _layoutMDW->activate();
+ }
+
+Index: gui/kmixerwidget.cpp
+===================================================================
+--- gui/kmixerwidget.cpp (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ gui/kmixerwidget.cpp (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -18,6 +18,7 @@
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
++#include "gui/kmixerwidget.h"
+
+ // Qt
+ #include <QLabel>
+@@ -39,12 +40,11 @@
+ // KMix
+ #include "apps/kmix.h"
+ #include "gui/guiprofile.h"
+-#include "gui/kmixerwidget.h"
+ #include "gui/kmixtoolbox.h"
+ #include "gui/mixdevicewidget.h"
++#include "gui/viewsliders.h"
+ #include "core/mixer.h"
+ #include "core/mixertoolbox.h"
+-#include "viewsliders.h"
+
+
+ /**
+@@ -104,61 +104,18 @@
+ * 2b) Create device widgets
+ * 2c) Add Views to Tab
+ ********************************************************************/
+- createViewsByProfile(_mixer, _guiprof, vflags);
++ ViewSliders* view = new ViewSliders( this, _guiprof->getId().toLatin1(), _mixer, vflags, _guiprof, _actionCollection );
++ possiblyAddView(view);
+ show();
+ // kDebug(67100) << "KMixerWidget::createLayout(): EXIT\n";
+ }
+
+
+ /**
+-* Creates the View based on the GUIProfile, for the Tab tabId
++ * Add the given view, if it is valid - it must have controls or at least have the chance to gain some (dynamic views)
++ * @param vbase
++ * @return true, if the view was added
+ */
+-void KMixerWidget::createViewsByProfile(Mixer* mixer, GUIProfile *guiprof, ViewBase::ViewFlags vflags)
+-{
+- ViewSliders* view = new ViewSliders( this, "", mixer, vflags, guiprof, _actionCollection );
+- bool added = possiblyAddView(view);
+- if ( added && view->visibleControls() == 0)
+- {
+- QString driverName = mixer->getDriverName();
+- QBoxLayout *lay = new QHBoxLayout(view);
+- //lay->setSizeConstraint(QLayout::SetNoConstraint);
+- lay->setAlignment(Qt::AlignCenter);
+- QLabel* lbl = new QLabel();
+- lbl->setAlignment(Qt::AlignCenter);
+- lbl->setWordWrap( true );
+- lbl->setText("Empty: " + driverName);
+- lay->addWidget(lbl);
+- //m_topLayout->addLayout(lay);
+- }
+-
+-#if 0
+- /*** How it works:
+- * A loop is done over all tabs.
+- * For each Tab a View (e.g. ViewSliders) is instanciated and added to the list of Views
+- */
+- QList<ProfTab*>::const_iterator itEnd = guiprof->tabs().end();
+- for ( QList<ProfTab*>::const_iterator it = guiprof->tabs().begin(); it != itEnd; ++it) {
+- ProfTab* profTab = *it;
+- if ( profTab->type() == "Sliders" ) {
+- if ( profTab->name() == 0 || profTab->name().isNull() )
+- {
+- kError() << "TAB NAME IS NULL";
+- profTab->name() = "Undefined";
+- }
+- kDebug() << ">>> TAB NAME = " << profTab->name();
+- QByteArray qba = profTab->name().toAscii();
+- ViewSliders* view = new ViewSliders( this, qba, mixer, vflags, guiprof, _actionCollection );
+- possiblyAddView(view);
+- break;
+- }
+- else {
+- kDebug(67100) << "KMixerWidget::createViewsByProfile(): Unknown Tab type '" << profTab->type() << "'\n";
+- }
+- } // search for correct tab
+-#endif
+-}
+-
+-
+ bool KMixerWidget::possiblyAddView(ViewBase* vbase)
+ {
+ if ( ! vbase->isValid() ) {
+@@ -216,11 +173,7 @@
+ */
+ ViewBase* KMixerWidget::currentView()
+ {
+- ViewBase* view = 0;
+- if ( _views.size() > 0 ) {
+- view = _views[0];
+- }
+- return view;
++ return _views.empty() ? 0 : _views[0];
+ }
+
+
+Index: gui/dialogaddview.cpp
+===================================================================
+--- gui/dialogaddview.cpp (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ gui/dialogaddview.cpp (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -19,6 +19,8 @@
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
++#include "gui/dialogaddview.h"
++
+ #include <qbuttongroup.h>
+ #include <QLabel>
+ #include <qradiobutton.h>
+@@ -30,7 +32,6 @@
+ #include <kdebug.h>
+ #include <klocale.h>
+
+-#include "gui/dialogaddview.h"
+ #include "core/mixdevice.h"
+ #include "core/mixer.h"
+
+Index: gui/guiprofile.cpp
+===================================================================
+--- gui/guiprofile.cpp (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ gui/guiprofile.cpp (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -118,9 +118,9 @@
+ fname += ".%1.%2";
+ fname = fname.arg(mixer->getBaseName()).arg(mixer->getCardInstance());
+ }
+- fname += "." + profileName;
++ fname += '.' + profileName;
+
+- fname.replace(" ","_");
++ fname.replace(' ','_');
+ return fname;
+ }
+
+@@ -133,10 +133,10 @@
+ QString fname;
+ fname += mixer->getBaseName();
+ if ( mixer->getCardInstance() > 1 ) {
+- fname += " " + mixer->getCardInstance();
++ fname += ' ' + mixer->getCardInstance();
+ }
+ if ( profileName != "default" ) {
+- fname += " " + profileName;
++ fname += ' ' + profileName;
+ }
+
+ return fname;
+@@ -322,7 +322,7 @@
+ bool ret = false;
+ QString fileName, fileNameFQ;
+ fileName = "profiles/" + getId() + ".xml";
+- fileName.replace(":", ".");
++ fileName.replace(':', '.');
+ fileNameFQ = KStandardDirs::locateLocal("appdata", fileName, true );
+
+ kDebug() << "Write profile:" << fileNameFQ ;
+@@ -424,9 +424,9 @@
+ QString xmlify(QString raw)
+ {
+ // kDebug() << "Before: " << raw;
+- raw = raw.replace("&", "&");
+- raw = raw.replace("<", "<");
+- raw = raw.replace(">", ">");
++ raw = raw.replace('&', "&");
++ raw = raw.replace('<', "<");
++ raw = raw.replace('>', ">");
+ raw = raw.replace("'", "'");
+ raw = raw.replace("\"", """);
+ // kDebug() << "After : " << raw;
+@@ -777,7 +777,7 @@
+ if ( !id.isNull() ) {
+ // We need at least an "id". We can set defaults for the rest, if undefined.
+ if ( subcontrols.isNull() || subcontrols.isEmpty() ) {
+- subcontrols = "*"; // for compatibility reasons, we interpret an empty string as match-all (aka "*")
++ subcontrols = '*'; // for compatibility reasons, we interpret an empty string as match-all (aka "*")
+ }
+ if ( name.isNull() ) {
+ // ignore. isNull() will be checked by all users.
+@@ -793,7 +793,7 @@
+ }
+
+ ProfControl *profControl = new ProfControl(id, subcontrols);
+- if ( show.isNull() ) { show = "*"; }
++ if ( show.isNull() ) { show = '*'; }
+
+ profControl->name = name;
+ profControl->show = show;
+Index: gui/viewbase.h
+===================================================================
+--- gui/viewbase.h (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ gui/viewbase.h (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -29,12 +29,14 @@
+ // KDE
+ #include <KActionCollection>
+ class KMenu;
+-class MixSet;
++
+ class Mixer;
+ class MixDevice;
+
+ // KMix
+ class GUIProfile;
++#include "core/mixdevice.h"
++#include "core/mixset.h"
+
+ /**
+ * The ViewBase is a virtual base class, to be used for subclassing the real Mixer Views.
+@@ -95,9 +97,8 @@
+
+ /**
+ * Creates a suitable representation for the given MixDevice.
+- * The default implementation creates a label
+ */
+- virtual QWidget* add(MixDevice *) = 0;
++ virtual QWidget* add(shared_ptr<MixDevice>) = 0;
+
+ /**
+ * Popup stuff
+@@ -130,7 +131,7 @@
+
+
+ protected:
+- MixSet *_mixSet;
++ MixSet _mixSet;
+ Mixer *_mixer;
+ QSet<Mixer*> _mixers; // this might deprecate _mixer in the future. Currently only in use by ViewDockAreaPopup
+ KMenu *_popMenu;
+Index: gui/kmixprefdlg.cpp
+===================================================================
+--- gui/kmixprefdlg.cpp (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ gui/kmixprefdlg.cpp (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -20,18 +20,17 @@
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
++#include "gui/kmixprefdlg.h"
++
+ #include <qbuttongroup.h>
+ #include <qwhatsthis.h>
+ #include <QCheckBox>
+ #include <QLabel>
+ #include <qradiobutton.h>
+
+-#include <klocale.h>
+-// For "kapp"
+ #include <kapplication.h>
++#include <klocale.h>
+
+-//#include "apps/kmix.h"
+-#include "gui/kmixprefdlg.h"
+ #include "gui/kmixerwidget.h"
+
+
+Index: gui/mdwenum.cpp
+===================================================================
+--- gui/mdwenum.cpp (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ gui/mdwenum.cpp (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -47,7 +47,7 @@
+ * Class that represents an Enum element (a select one-from-many selector)
+ * The orientation (horizontal, vertical) is ignored
+ */
+-MDWEnum::MDWEnum( MixDevice* md,
++MDWEnum::MDWEnum( shared_ptr<MixDevice> md,
+ Qt::Orientation orientation,
+ QWidget* parent, ViewBase* view, ProfControl* par_pctl) :
+ MixDeviceWidget(md, false, orientation, parent, view, par_pctl),
+Index: gui/kmixdockwidget.cpp
+===================================================================
+--- gui/kmixdockwidget.cpp (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ gui/kmixdockwidget.cpp (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -21,6 +21,8 @@
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
++#include "gui/kmixdockwidget.h"
++
+ #include <kaction.h>
+ #include <klocale.h>
+ #include <kapplication.h>
+@@ -46,7 +48,6 @@
+
+ #include "gui/dialogselectmaster.h"
+ #include "apps/kmix.h"
+-#include "gui/kmixdockwidget.h"
+ #include "core/mixer.h"
+ #include "gui/mixdevicewidget.h"
+ #include "core/mixertoolbox.h"
+@@ -77,7 +78,7 @@
+
+ if ( NO_MENU_ANYMORE )
+ {
+- connect(contextMenu(), SIGNAL(aboutToShow()), this, SLOT(activateMenuOrWindow(bool,QPoint)));
++ connect(contextMenu(), SIGNAL(aboutToShow()), this, SLOT(contextMenuAboutToShow()));
+ }
+ else
+ {
+@@ -85,10 +86,10 @@
+ connect(contextMenu(), SIGNAL(aboutToShow()), this, SLOT(contextMenuAboutToShow()));
+ }
+
+-#ifdef _GNU_SOURCE
+-// TODO minimizeRestore usage is currently a bit broken. It only works by chance
++#ifdef __GNUC__
+ #warning minimizeRestore usage is currently slightly broken in KMIx. This should be fixed before doing a release.
+ #endif
++ // TODO minimizeRestore usage is currently a bit broken. It only works by chance
+
+ if (_volumePopup) {
+ kDebug() << "Construct the ViewDockAreaPopup and actions";
+@@ -128,8 +129,9 @@
+ {
+ QMenu *menu = contextMenu();
+
+- MixDevice* md = Mixer::getGlobalMasterMD();
+- if ( md != 0 && md->playbackVolume().hasSwitch() ) {
++ shared_ptr<MixDevice> md = Mixer::getGlobalMasterMD();
++ if ( md.get() != 0 && md->playbackVolume().hasSwitch() )
++ {
+ // Put "Mute" selector in context menu
+ KToggleAction *action = actionCollection()->add<KToggleAction>( "dock_mute" );
+ action->setText( i18n( "M&ute" ) );
+@@ -212,11 +214,11 @@
+ void
+ KMixDockWidget::setVolumeTip()
+ {
+- MixDevice *md = Mixer::getGlobalMasterMD();
++ shared_ptr<MixDevice> md = Mixer::getGlobalMasterMD();
+ QString tip = "";
+ int newToolTipValue = 0;
+
+- if ( md == 0 )
++ if ( md.get() == 0 )
+ {
+ tip = i18n("Mixer cannot be found"); // !! text could be reworked
+ newToolTipValue = -2;
+@@ -225,14 +227,8 @@
+ {
+ // Playback volume will be used for the DockIcon if available.
+ // This heuristic is "good enough" for the DockIcon for now.
+- int val = 0;
+- Volume& vol = md->playbackVolume();
+- if (! vol.hasVolume() ) {
+- vol = md->captureVolume();
+- }
+- if ( vol.hasVolume() ) {
+- val = vol.getAvgVolumePercent(Volume::MALL);
+- }
++ Volume& vol = md->playbackVolume().hasVolume() ? md->playbackVolume() : md->captureVolume();
++ int val = vol.getAvgVolumePercent(Volume::MALL);
+
+ // create a new "virtual" value. With that we see "volume changes" as well as "muted changes"
+ newToolTipValue = val;
+@@ -256,34 +252,31 @@
+ void
+ KMixDockWidget::updatePixmap()
+ {
+- MixDevice *md = Mixer::getGlobalMasterMD();
++ shared_ptr<MixDevice> md = Mixer::getGlobalMasterMD();
+
+ char newPixmapType;
+ if ( md == 0 )
+ {
+ newPixmapType = 'e';
+ }
+- else if ( md->playbackVolume().hasSwitch() && md->isMuted() )
+- {
+- newPixmapType = 'm';
+- }
+ else
+ {
+- Volume& vol = md->playbackVolume();
+- if (! vol.hasVolume() ) {
+- vol = md->captureVolume();
+- }
+- int percentage = vol.getAvgVolumePercent(Volume::MALL);
++ Volume& vol = md->playbackVolume().hasVolume() ? md->playbackVolume() : md->captureVolume();
++ bool isInactive = vol.isCapture() ? !md->isRecSource() : md->isMuted();
++ if ( isInactive )
++ {
++ newPixmapType = 'm';
++ }
++ else
++ {
++ int percentage = vol.getAvgVolumePercent(Volume::MALL);
++ if ( percentage <= 0 ) newPixmapType = '0'; // Hint: also negative-values
++ else if ( percentage < 25 ) newPixmapType = '1';
++ else if ( percentage < 75 ) newPixmapType = '2';
++ else newPixmapType = '3';
++ }
++ }
+
+- // kDebug() << "TrayVol id=" << md->id() << " vol=" << vol.getAvgVolumePercent(Volume::MALL);
+-
+- if ( percentage <= 0 ) newPixmapType = '0'; // Hint: also negative-values
+- else if ( percentage < 25 ) newPixmapType = '1';
+- else if ( percentage < 75 ) newPixmapType = '2';
+- else newPixmapType = '3';
+- }
+-
+-
+ if ( newPixmapType != _oldPixmapType ) {
+ // Pixmap must be changed => do so
+ switch ( newPixmapType ) {
+@@ -381,18 +374,15 @@
+ }
+ }
+
+-// void
+-// KMixDockWidget::trayToolTipEvent(QHelpEvent *e ) {
+-// kDebug(67100) << "trayToolTipEvent" ;
+-// setVolumeTip();
+-// }
+
+ void
+ KMixDockWidget::trayWheelEvent(int delta,Qt::Orientation wheelOrientation)
+ {
+- MixDevice *md = Mixer::getGlobalMasterMD();
+- if ( md != 0 )
+- {
++ shared_ptr<MixDevice> md = Mixer::getGlobalMasterMD();
++ if ( md.get() == 0 )
++ return;
++
++
+ Volume &vol = ( md->playbackVolume().hasVolume() ) ? md->playbackVolume() : md->captureVolume();
+ int inc = vol.volumeSpan() / Mixer::VOLUME_STEP_DIVISOR;
+
+@@ -403,10 +393,15 @@
+
+ long int cv = inc * (delta / 120 );
+ // kDebug() << "twe: " << cv << " : " << vol;
+- if ( cv > 0 && md->isMuted())
++ bool isInactive = vol.isCapture() ? !md->isRecSource() : md->isMuted();
++ kDebug() << "Operating on capture=" << vol.isCapture() << ", isInactive=" << isInactive;
++ if ( cv > 0 && isInactive)
+ { // increasing from muted state: unmute and start with a low volume level
+- md->setMuted(false);
+- vol.setAllVolumes(cv);
++ if ( vol.isCapture())
++ md->setRecSource(true);
++ else
++ md->setMuted(false);
++ vol.setAllVolumes(cv);
+ }
+ else
+ vol.changeAllVolumes(cv);
+@@ -421,15 +416,15 @@
+
+ md->mixer()->commitVolumeChange(md);
+ setVolumeTip();
+- }
+ }
+
+
+ void
+ KMixDockWidget::dockMute()
+ {
+- MixDevice *md = Mixer::getGlobalMasterMD();
+- if ( md ) {
++ shared_ptr<MixDevice> md = Mixer::getGlobalMasterMD();
++ if ( md )
++ {
+ md->toggleMute();
+ md->mixer()->commitVolumeChange( md );
+ }
+@@ -460,13 +455,15 @@
+ */
+
+ // Enable/Disable "Muted" menu item
+- MixDevice* md = Mixer::getGlobalMasterMD();
++ shared_ptr<MixDevice> md = Mixer::getGlobalMasterMD();
+ KToggleAction *dockMuteAction = static_cast<KToggleAction*>(actionCollection()->action("dock_mute"));
+ //kDebug(67100) << "---> md=" << md << "dockMuteAction=" << dockMuteAction << "isMuted=" << md->isMuted();
+ if ( md != 0 && dockMuteAction != 0 ) {
+- bool hasSwitch = md->playbackVolume().hasSwitch();
++ Volume& vol = md->playbackVolume().hasVolume() ? md->playbackVolume() : md->captureVolume();
++ bool isInactive = vol.isCapture() ? md->isMuted() : !md->isRecSource();
++ bool hasSwitch = vol.hasSwitch();
+ dockMuteAction->setEnabled( hasSwitch );
+- dockMuteAction->setChecked( hasSwitch && md->isMuted() );
++ dockMuteAction->setChecked( hasSwitch && !isInactive );
+ }
+ _contextMenuWasOpen = true;
+ }
+Index: gui/mixdevicewidget.cpp
+===================================================================
+--- gui/mixdevicewidget.cpp (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ gui/mixdevicewidget.cpp (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -19,6 +19,9 @@
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
++#include "gui/mixdevicewidget.h"
++
++#include <kactioncollection.h>
+ #include <klocale.h>
+ #include <kiconloader.h>
+ #include <kconfig.h>
+@@ -33,10 +36,7 @@
+ #include <qpixmap.h>
+ #include <qwmatrix.h>
+
+-#include <kactioncollection.h>
+-
+ #include "core/mixer.h"
+-#include "gui/mixdevicewidget.h"
+ #include "core/mixertoolbox.h"
+ #include "viewbase.h"
+ #include "ksmallslider.h"
+@@ -51,7 +51,7 @@
+ * SHOULD honor these values - those who do not might not be suitable for placing in
+ * the panel applet or any other smallish settings.
+ */
+-MixDeviceWidget::MixDeviceWidget(MixDevice* md,
++MixDeviceWidget::MixDeviceWidget(shared_ptr<MixDevice> md,
+ bool small, Qt::Orientation orientation,
+ QWidget* parent, ViewBase* view, ProfControl* par_pctl) :
+ QWidget( parent ), m_mixdevice( md ), m_view( view ), _pctl(par_pctl),
+Index: gui/mdwmoveaction.h
+===================================================================
+--- gui/mdwmoveaction.h (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ gui/mdwmoveaction.h (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -23,14 +23,14 @@
+
+ #include <KAction>
+
+-class MixDevice;
++#include "core/mixdevice.h"
+
+ class MDWMoveAction : public KAction
+ {
+ Q_OBJECT
+
+ public:
+- MDWMoveAction(MixDevice* md, QObject *parent);
++ MDWMoveAction(shared_ptr<MixDevice> md, QObject *parent);
+ ~MDWMoveAction();
+
+ signals:
+@@ -40,7 +40,7 @@
+ void triggered(bool checked);
+
+ private:
+- MixDevice *m_mixDevice;
++ shared_ptr<MixDevice> m_mixDevice;
+ };
+
+ #endif
+Index: gui/dialogviewconfiguration.cpp
+===================================================================
+--- gui/dialogviewconfiguration.cpp (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ gui/dialogviewconfiguration.cpp (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -19,6 +19,8 @@
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
++#include "dialogviewconfiguration.h"
++
+ #include <algorithm>
+
+ #include <QCheckBox>
+@@ -33,7 +35,6 @@
+ #include <klocale.h>
+ #include <kvbox.h>
+
+-#include "dialogviewconfiguration.h"
+ #include "gui/guiprofile.h"
+ #include "gui/mixdevicewidget.h"
+ #include "core/mixdevice.h"
+@@ -254,7 +255,7 @@
+ QWidget *qw = mdws[i];
+ if ( qw->inherits("MixDeviceWidget") ) {
+ MixDeviceWidget *mdw = static_cast<MixDeviceWidget*>(qw);
+- MixDevice *md = mdw->mixDevice();
++ shared_ptr<MixDevice> md = mdw->mixDevice();
+ QString mdName = md->readableName();
+
+ int splitted = -1;
+@@ -380,7 +381,7 @@
+ if ( ctlId.contains(idRegexp) ) {
+ // found. Create a copy
+ ProfControl* newCtl = new ProfControl(*control);
+- newCtl->id = "^" + ctlId + "$"; // Replace the (possible generic) regexp by the actual ID
++ newCtl->id = '^' + ctlId + '$'; // Replace the (possible generic) regexp by the actual ID
+ // We have made this an an actual control. As it is derived (from e.g. ".*") it is NOT mandatory.
+ newCtl->setMandatory(false);
+ if ( isActiveView ) {
+Index: gui/viewdockareapopup.cpp
+===================================================================
+--- gui/viewdockareapopup.cpp (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ gui/viewdockareapopup.cpp (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -77,43 +77,41 @@
+
+ void ViewDockAreaPopup::_setMixSet()
+ {
+- // kDebug(67100) << "ViewDockAreaPopup::setMixSet()\n";
++ // kDebug(67100) << "ViewDockAreaPopup::setMixSet()\n";
+
+- // -- remove controls
+- if ( _mixer->isDynamic() ) {
+- // Our _layoutMDW now should only contain spacer widgets from the QSpacerItem's in add() below.
+- // We need to trash those too otherwise all sliders gradually migrate away from the edge :p
+- QLayoutItem *li;
+- while ( ( li = _layoutMDW->takeAt(0) ) )
+- delete li;
+- }
++ // -- remove controls
++ if ( _mixer->isDynamic() ) {
++ // Our _layoutMDW now should only contain spacer widgets from the QSpacerItem's in add() below.
++ // We need to trash those too otherwise all sliders gradually migrate away from the edge :p
++ QLayoutItem *li;
++ while ( ( li = _layoutMDW->takeAt(0) ) )
++ delete li;
++ }
+
+- MixDevice *dockMD = Mixer::getGlobalMasterMD();
+- if ( dockMD == 0 ) {
+- // If we have no dock device yet, we will take the first available mixer device
+- if ( _mixer->size() > 0) {
+- dockMD = (*_mixer)[0];
+- }
+- }
+- if ( dockMD != 0 ) {
+- _mixSet->append(dockMD);
+- }
+-
+- Mixer* mixer2;
+- foreach ( mixer2 , Mixer::mixers() )
+- {
+- MixDevice *md;
+- foreach ( md, mixer2->getMixSet() )
+- {
+- if (md->isApplicationStream())
+- {
+- _mixSet->append(md);
+- kDebug(67100) << "Add to tray popup: " << md->id();
+- }
+- }
++ shared_ptr<MixDevice>dockMD = Mixer::getGlobalMasterMD();
++ if ( dockMD == 0 ) {
++ // If we have no dock device yet, we will take the first available mixer device
++ if ( _mixer->size() > 0) {
++ dockMD = (*_mixer)[0];
++ }
++ }
++ if ( dockMD != 0 ) {
++ _mixSet.append(dockMD);
++ }
++
++ foreach ( Mixer* mixer2 , Mixer::mixers() )
++ {
++ foreach ( shared_ptr<MixDevice> md, mixer2->getMixSet() )
++ {
++ if (md->isApplicationStream())
++ {
++ _mixSet.append(md);
++ kDebug(67100) << "Add to tray popup: " << md->id();
++ }
++ }
++ }
++
+ }
+-
+-}
+
+
+ void ViewDockAreaPopup::controlsReconfigured( const QString& mixer_ID )
+@@ -124,15 +122,15 @@
+ }
+
+
+-QWidget* ViewDockAreaPopup::add(MixDevice *md)
++QWidget* ViewDockAreaPopup::add(shared_ptr<MixDevice> md)
+ {
+ QString dummyMatchAll("*");
+- QString matchAllPlaybackAndTheCswitch("pvolume,pswitch,cswitch");
++ QString matchAllPlaybackAndTheCswitch("pvolume,cvolume,pswitch,cswitch");
+ ProfControl *pctl = new ProfControl( dummyMatchAll, matchAllPlaybackAndTheCswitch);
+ MixDeviceWidget *mdw = new MDWSlider(
+ md, // only 1 device.
+ true, // Show Mute LED
+- false, // Show Record LED
++ true, // Show Record LED
+ false, // Small
+ _dock->toplevelOrientation(), // Direction: only 1 device, so doesn't matter
+ this, // parent
+Index: kmix_autostart.desktop
+===================================================================
+--- kmix_autostart.desktop (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ kmix_autostart.desktop (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -114,6 +114,7 @@
+ Name[hne]=के-मिक्स
+ Name[hr]=KMix
+ Name[hu]=KMix
++Name[id]=KMix
+ Name[is]=KMix
+ Name[it]=KMix
+ Name[ja]=KMix
+Index: core/mixdevicecomposite.cpp
+===================================================================
+--- core/mixdevicecomposite.cpp (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ core/mixdevicecomposite.cpp (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -25,7 +25,7 @@
+
+ const long MixDeviceComposite::VolMax = 10000;
+
+-MixDeviceComposite::MixDeviceComposite( Mixer* mixer, const QString& id, QList<MixDevice*>& mds, const QString& name, ChannelType type ) :
++MixDeviceComposite::MixDeviceComposite( Mixer* mixer, const QString& id, QList<shared_ptr<MixDevice> >& mds, const QString& name, ChannelType type ) :
+ MixDevice( mixer, id, name, type ) // this will use doNotRestore == true
+ {
+ setArtificial(true);
+@@ -33,9 +33,9 @@
+ _compositePlaybackVolume->addVolumeChannel(Volume::LEFT);
+ _compositePlaybackVolume->addVolumeChannel(Volume::RIGHT);
+
+- QListIterator<MixDevice*> it(mds);
++ QListIterator<shared_ptr<MixDevice> > it(mds);
+ while ( it.hasNext()) {
+- MixDevice* md = it.next();
++ shared_ptr<MixDevice> md = it.next();
+ _mds.append(md);
+ }
+ }
+@@ -75,11 +75,12 @@
+
+ long MixDeviceComposite::calculateVolume(Volume::VolumeType vt)
+ {
+- QListIterator<MixDevice*> it(_mds);
++ QListIterator<shared_ptr<MixDevice> > it(_mds);
+ long volSum = 0;
+ int volCount = 0;
+- while ( it.hasNext()) {
+- MixDevice* md = it.next();
++ while ( it.hasNext())
++ {
++ shared_ptr<MixDevice> md = it.next();
+
+ Volume& vol = ( vt == Volume::CaptureVT ) ? md->captureVolume() : md->playbackVolume();
+ if (vol.hasVolume() && (vol.maxVolume() != 0) ) {
+@@ -100,9 +101,9 @@
+ bool MixDeviceComposite::isMuted()
+ {
+ bool isMuted = false;
+- QListIterator<MixDevice*> it(_mds);
++ QListIterator<shared_ptr<MixDevice> > it(_mds);
+ while ( it.hasNext()) {
+- MixDevice* md = it.next();
++ shared_ptr<MixDevice> md = it.next();
+ isMuted |= md->isMuted();
+ if ( isMuted ) break; // Enough. It can't get more true :-)
+ }
+@@ -113,9 +114,9 @@
+
+ void MixDeviceComposite::setMuted(bool value)
+ {
+- QListIterator<MixDevice*> it(_mds);
++ QListIterator<shared_ptr<MixDevice> > it(_mds);
+ while ( it.hasNext()) {
+- MixDevice* md = it.next();
++ shared_ptr<MixDevice> md = it.next();
+ md->setMuted(value);
+ }
+ }
+@@ -123,9 +124,9 @@
+ bool MixDeviceComposite::isRecSource()
+ {
+ bool isRecSource = false;
+- QListIterator<MixDevice*> it(_mds);
++ QListIterator<shared_ptr<MixDevice> > it(_mds);
+ while ( it.hasNext()) {
+- MixDevice* md = it.next();
++ shared_ptr<MixDevice> md = it.next();
+ isRecSource |= md->isRecSource();
+ if ( isRecSource ) break; // Enough. It can't get more true :-)
+ }
+@@ -135,9 +136,9 @@
+
+ void MixDeviceComposite::setRecSource(bool value)
+ {
+- QListIterator<MixDevice*> it(_mds);
++ QListIterator<shared_ptr<MixDevice> > it(_mds);
+ while ( it.hasNext()) {
+- MixDevice* md = it.next();
++ shared_ptr<MixDevice> md = it.next();
+ md->setRecSource(value);
+ }
+ }
+@@ -146,9 +147,9 @@
+ bool MixDeviceComposite::isEnum()
+ {
+ bool isEnum = true;
+- QListIterator<MixDevice*> it(_mds);
++ QListIterator<shared_ptr<MixDevice> > it(_mds);
+ while ( it.hasNext()) {
+- MixDevice* md = it.next();
++ shared_ptr<MixDevice> md = it.next();
+ isEnum &= md->isEnum();
+ if ( ! isEnum ) break; // Enough. It can't get more false :-)
+ }
+Index: core/MasterControl.h
+===================================================================
+--- core/MasterControl.h (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ core/MasterControl.h (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -10,6 +10,11 @@
+
+ #include <QString>
+
++// std::shared_ptr
++#include <memory>
++#include <tr1/memory>
++using namespace ::std::tr1;
++
+ class MasterControl
+ {
+ public:
+Index: core/mixdevicecomposite.h
+===================================================================
+--- core/mixdevicecomposite.h (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ core/mixdevicecomposite.h (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -74,7 +74,7 @@
+ * @par name is the readable name. This one is presented to the user in the GUI
+ * @par type The control type. It is only used to find an appropriate icon
+ */
+- MixDeviceComposite( Mixer* mixer, const QString& id, QList<MixDevice*>& mds, const QString& name, ChannelType type );
++ MixDeviceComposite( Mixer* mixer, const QString& id, QList<shared_ptr<MixDevice> >& mds, const QString& name, ChannelType type );
+ // MixDevice( Mixer* mixer, const QString& id, const QString& name, const QString& iconName = "", bool doNotRestore = false, MixSet* moveDestinationMixSet = 0 );
+ ~MixDeviceComposite();
+
+@@ -99,7 +99,7 @@
+ long calculateVolume(Volume::VolumeType vt);
+
+ Mixer *_mixer;
+- QList<MixDevice*> _mds;
++ QList<shared_ptr<MixDevice> > _mds;
+
+ static const long VolMax;
+
+Index: core/volume.cpp
+===================================================================
+--- core/volume.cpp (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ core/volume.cpp (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -19,12 +19,13 @@
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
++#include "core/volume.h"
++
+ // for operator<<()
+ #include <iostream>
+
+ #include <kdebug.h>
+
+-#include "core/volume.h"
+
+
+ int Volume::_channelMaskEnum[9] =
+Index: core/mixset.cpp
+===================================================================
+--- core/mixset.cpp (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ core/mixset.cpp (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -33,6 +33,10 @@
+ #include <QString>
+
+
++MixSet::~MixSet()
++{
++ clear();
++}
+
+ void MixSet::read( KConfig *config, const QString& grp )
+ {
+@@ -40,9 +44,8 @@
+ KConfigGroup group = config->group(grp);
+ m_name = group.readEntry( "name", m_name );
+
+- for(int i=0; i < count() ; i++ )
++ foreach ( shared_ptr<MixDevice> md, *this)
+ {
+- MixDevice *md = operator[](i);
+ md->read( config, grp );
+ }
+ }
+@@ -53,9 +56,8 @@
+ KConfigGroup conf = config->group(grp);
+ conf.writeEntry( "name", m_name );
+
+- for(int i=0; i < count() ; i++ )
++ foreach ( shared_ptr<MixDevice> md, *this)
+ {
+- MixDevice *md = operator[](i);
+ md->write( config, grp );
+ }
+ }
+@@ -65,23 +67,26 @@
+ m_name = name;
+ }
+
+-MixDevice* MixSet::get(QString id)
++shared_ptr<MixDevice> MixSet::get(QString id)
+ {
+- MixDevice* md = 0;
+- for(int i=0; i < count() ; i++ )
+- {
+- md = operator[](i);
+- if ( md->id() == id )
+- break;
+- }
+- return md;
++ shared_ptr<MixDevice> mdRet;
++
++ foreach ( shared_ptr<MixDevice> md, *this)
++ {
++ if ( md->id() == id )
++ {
++ mdRet = md;
++ break;
++ }
++ }
++ return mdRet;
+ }
+
+ void MixSet::removeById(QString id)
+ {
+ for (int i=0; i < count() ; i++ )
+ {
+- MixDevice* md = operator[](i);
++ shared_ptr<MixDevice> md = operator[](i);
+ if ( md->id() == id )
+ {
+ removeAt(i);
+Index: core/mixdevice.cpp
+===================================================================
+--- core/mixdevice.cpp (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ core/mixdevice.cpp (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -19,16 +19,18 @@
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
++#include "core/mixdevice.h"
++
+ #include <qregexp.h>
+
+ #include <kdebug.h>
+ #include <klocale.h>
+
+-#include "core/mixdevice.h"
++#include "core/ControlPool.h"
+ #include "core/mixer.h"
++#include "dbus/dbuscontrolwrapper.h"
+ #include "gui/guiprofile.h"
+ #include "core/volume.h"
+-#include "dbus/dbuscontrolwrapper.h"
+
+ static const QString channelTypeToIconName( MixDevice::ChannelType type )
+ {
+@@ -113,6 +115,7 @@
+ {
+ _artificial = false;
+ _applicationStream = false;
++ _dbusControlWrapper = 0; // will be set in addToPool()
+ _mixer = mixer;
+ _id = id;
+ mediaPlayControl = false;
+@@ -128,14 +131,31 @@
+ _iconName = iconName;
+ _moveDestinationMixSet = moveDestinationMixSet;
+ if ( _id.contains(' ') ) {
+- // The key is used in the config file. It MUST NOT contain spaces
++ // The key is used in the config file. IdbusControlWrappert MUST NOT contain spaces
+ kError(67100) << "MixDevice::setId(\"" << id << "\") . Invalid key - it must not contain spaces" << endl;
+ _id.replace(' ', '_');
+ }
+ kDebug(67100) << "MixDevice::init() _id=" << _id;
+- new DBusControlWrapper( this, dbusPath() );
+ }
+
++shared_ptr<MixDevice> MixDevice::addToPool()
++{
++ const QString& fullyQualifiedId = getFullyQualifiedId();
++ kDebug() << "MixDevice::init() id=" << fullyQualifiedId;
++
++ shared_ptr<MixDevice> thisSharedPtr(this);
++ //shared_ptr<MixDevice> thisSharedPtr = ControlPool::instance()->add(fullyQualifiedId, this);
++ _dbusControlWrapper = new DBusControlWrapper( thisSharedPtr, dbusPath() );
++ return thisSharedPtr;
++}
++
++
++QString MixDevice::getFullyQualifiedId()
++{
++ QString fqId = QString("%1@%2").arg(_id).arg(_mixer->id());
++ return fqId;
++}
++
+ void MixDevice::addPlaybackVolume(Volume &playbackVol)
+ {
+ // Hint: "_playbackVolume" gets COPIED from "playbackVol", because the copy-constructor actually copies the volume levels.
+@@ -164,6 +184,7 @@
+
+ MixDevice::~MixDevice() {
+ _enumValues.clear(); // The QString's inside will be auto-deleted, as they get unref'ed
++ delete _dbusControlWrapper;
+ }
+
+ Volume& MixDevice::playbackVolume()
+Index: core/mixset.h
+===================================================================
+--- core/mixset.h (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ core/mixset.h (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -25,16 +25,18 @@
+
+ #include "core/mixdevice.h"
+
+-class MixSet : public QList <MixDevice *>
++class MixSet : public QList <shared_ptr<MixDevice> >
+ {
+ public:
++ ~MixSet();
++
+ void read( KConfig *config, const QString& grp );
+ void write( KConfig *config, const QString& grp );
+
+ QString name() { return m_name; }
+ void setName( const QString &name );
+
+- MixDevice* get(QString id);
++ shared_ptr<MixDevice> get(QString id);
+
+ void removeById(QString id);
+
+Index: core/mixdevice.h
+===================================================================
+--- core/mixdevice.h (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ core/mixdevice.h (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -21,11 +21,17 @@
+ #ifndef MixDevice_h
+ #define MixDevice_h
+
++// std::shared_ptr
++#include <memory>
++#include <tr1/memory>
++using namespace ::std::tr1;
++
+ //KMix
+ class Mixer;
+ class MixSet;
+ class ProfControl;
+ #include "core/volume.h"
++class DBusControlWrapper;
+
+ // KDE
+ #include <kconfig.h>
+@@ -96,7 +102,10 @@
+ enum SwitchType { OnOff, Mute, Capture, Activator };
+
+ /**
+- * Constructor:
++ * Constructor for a MixDevice.
++ * After having constructed a MixDevice, you <b>must</b> add it to the ControlPool
++ * by calling addToPool(). You may then <b>not</b> delete this object.
++ *
+ * @par mixer The mixer this control belongs to
+ * @par id Defines the ID, e.g. used in looking up the keys in kmixrc. Also it is used heavily inside KMix as unique key.
+ * It is advised to set a nice name, like 'PCM:2', which would mean
+@@ -112,6 +121,8 @@
+ MixDevice( Mixer* mixer, const QString& id, const QString& name, const QString& iconName = "", MixSet* moveDestinationMixSet = 0 );
+ ~MixDevice();
+
++ shared_ptr<MixDevice> addToPool();
++
+ const QString& iconName() const { return _iconName; }
+
+ void addPlaybackVolume(Volume &playbackVol);
+@@ -141,6 +152,7 @@
+ */
+
+ const QString& id() const;
++ QString getFullyQualifiedId();
+
+ /**
+ * Returns the DBus path for this MixDevice
+@@ -216,6 +228,8 @@
+ int _enumCurrentId;
+ QList<QString> _enumValues; // A MixDevice, that is an ENUM, has these _enumValues
+
++ DBusControlWrapper *_dbusControlWrapper;
++
+ // A virtual control. It will not be saved/restored and/or doesn't get shortcuts
+ // Actually we discriminate those "virtual" controls in artificial controls and dynamic controls:
+ // Type Shortcut Restore
+Index: core/kmixdevicemanager.cpp
+===================================================================
+--- core/kmixdevicemanager.cpp (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ core/kmixdevicemanager.cpp (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -141,7 +141,7 @@
+ dev = devExpr.cap(1); // Get device number from device name (e.g "/dev/mixer1" or "/dev/sound/mixer2")
+ }
+ else {
+- dev = "0"; // "/dev/mixer" or "/dev/sound/mixer"
++ dev = '0'; // "/dev/mixer" or "/dev/sound/mixer"
+ }
+ emit plugged("OSS", udi, dev);
+ }
+Index: core/mixer.cpp
+===================================================================
+--- core/mixer.cpp (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ core/mixer.cpp (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -20,13 +20,13 @@
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
++#include "core/mixer.h"
+
+ #include <klocale.h>
+ #include <kconfig.h>
+ #include <kglobal.h>
+ #include <kdebug.h>
+
+-#include "core/mixer.h"
+ #include "backends/mixer_backend.h"
+ #include "backends/kmix-backends.cpp"
+ #include "core/volume.h"
+@@ -130,16 +130,16 @@
+ * %3, the mixer number, is a number: it does not contain colons.
+ */
+ QString mixerName = getBaseName();
+- mixerName.replace(":","_");
++ mixerName.replace(':','_');
+ QString primaryKeyOfMixer = QString("%1::%2:%3")
+ .arg(getDriverName())
+ .arg(mixerName)
+ .arg(_cardInstance);
+ // The following 3 replaces are for not messing up the config file
+- primaryKeyOfMixer.replace("]","_");
+- primaryKeyOfMixer.replace("[","_"); // not strictly necessary, but lets play safe
+- primaryKeyOfMixer.replace(" ","_");
+- primaryKeyOfMixer.replace("=","_");
++ primaryKeyOfMixer.replace(']','_');
++ primaryKeyOfMixer.replace('[','_'); // not strictly necessary, but lets play safe
++ primaryKeyOfMixer.replace(' ','_');
++ primaryKeyOfMixer.replace('=','_');
+ _id = primaryKeyOfMixer;
+ }
+
+@@ -170,10 +170,12 @@
+ _mixerBackend->m_mixDevices.read( config, grp );
+
+ // set new settings
+- //QListIterator<MixDevice*> it( _mixerBackend->m_mixDevices );
+ for(int i=0; i<_mixerBackend->m_mixDevices.count() ; i++ )
+ {
+- MixDevice *md = _mixerBackend->m_mixDevices[i];
++ shared_ptr<MixDevice> md = _mixerBackend->m_mixDevices[i];
++ if ( md.get() == 0 )
++ continue;
++
+ _mixerBackend->writeVolumeToHW( md->id(), md );
+ if ( md->isEnum() ) _mixerBackend->setEnumIdHW( md->id(), md->enumId() );
+ }
+@@ -188,15 +190,18 @@
+ */
+ bool Mixer::openIfValid() {
+ bool ok = _mixerBackend->openIfValid();
+- if ( ok ) {
+- recreateId(); // Fallback call. Actually recreateId() is supposed to be called later again, via setCardInstance()
+- MixDevice* recommendedMaster = _mixerBackend->recommendedMaster();
+- if ( recommendedMaster != 0 ) {
++ if ( ok )
++ {
++ recreateId(); // TODO NOW : We actually cannot postpone it to here, due to ControlPool. Move to Mixer !!!. Actually recreateId() is supposed to be called later again, via setCardInstance()
++ shared_ptr<MixDevice> recommendedMaster = _mixerBackend->recommendedMaster();
++ if ( recommendedMaster.get() != 0 )
++ {
+ QString recommendedMasterStr = recommendedMaster->id();
+ setLocalMasterMD( recommendedMasterStr );
+ kDebug() << "Mixer::open() detected master: " << recommendedMaster->id();
+ }
+- else {
++ else
++ {
+ if ( !m_dynamic )
+ kError(67100) << "Mixer::open() no master detected." << endl;
+ QString noMaster = "---no-master-detected---";
+@@ -229,14 +234,13 @@
+ return _mixerBackend->m_mixDevices.count();
+ }
+
+-MixDevice* Mixer::operator[](int num)
++shared_ptr<MixDevice> Mixer::operator[](int num)
+ {
+- MixDevice* md = _mixerBackend->m_mixDevices.at( num );
+- Q_ASSERT( md );
+- return md;
++ shared_ptr<MixDevice> md = _mixerBackend->m_mixDevices.at( num );
++ return md;
+ }
+
+-MixSet Mixer::getMixSet()
++MixSet& Mixer::getMixSet()
+ {
+ return _mixerBackend->m_mixDevices;
+ }
+@@ -285,8 +289,9 @@
+
+ m_balance = balance;
+
+- MixDevice* master = getLocalMasterMD();
+- if ( master == 0 ) {
++ shared_ptr<MixDevice> master = getLocalMasterMD();
++ if ( master.get() == 0 )
++ {
+ // no master device available => return
+ return;
+ }
+@@ -427,39 +432,41 @@
+ }
+
+
+-MixDevice* Mixer::getGlobalMasterMD()
++shared_ptr<MixDevice> Mixer::getGlobalMasterMD()
+ {
+ return getGlobalMasterMD(true);
+ }
+
+
+-MixDevice* Mixer::getGlobalMasterMD(bool fallbackAllowed)
++shared_ptr<MixDevice> Mixer::getGlobalMasterMD(bool fallbackAllowed)
+ {
+- MixDevice* md = 0;
+- Mixer *mixer;
+- if ( fallbackAllowed)
+- mixer = Mixer::getGlobalMasterMixer();
+- else
+- mixer = Mixer::getGlobalMasterMixerNoFalback();
+- if ( mixer != 0 ) {
+- for(int i=0; i < mixer->_mixerBackend->m_mixDevices.count() ; i++ )
+- {
+- md = mixer->_mixerBackend->m_mixDevices[i];
+- if ( md->id() == _globalMasterCurrent.getControl() ) {
+- //kDebug() << "Mixer::masterCardDevice() found " << _globalMasterCardDevice;
+- break;
+- }
+- }
+- }
+- if ( ! md )
+- kDebug() << "Mixer::masterCardDevice() returns 0 (no globalMaster)";
+- return md;
++ shared_ptr<MixDevice> mdRet;
++ Mixer *mixer = fallbackAllowed ?
++ Mixer::getGlobalMasterMixer() : Mixer::getGlobalMasterMixerNoFalback();
++
++ if ( mixer == 0 )
++ return mdRet;
++
++ foreach (shared_ptr<MixDevice> md, mixer->_mixerBackend->m_mixDevices )
++ {
++ if ( md.get() == 0 )
++ continue; // invalid
++ if ( md->id() == _globalMasterCurrent.getControl() )
++ {
++ mdRet = md;
++ break; // found
++ }
++ }
++ if ( mdRet.get() == 0 )
++ kDebug() << "Mixer::masterCardDevice() returns 0 (no globalMaster)";
++
++ return mdRet;
+ }
+
+
+
+
+-MixDevice* Mixer::getLocalMasterMD()
++shared_ptr<MixDevice> Mixer::getLocalMasterMD()
+ {
+ return find( _masterDevicePK );
+ }
+@@ -470,25 +477,32 @@
+ }
+
+
+-MixDevice* Mixer::find(const QString& mixdeviceID)
++shared_ptr<MixDevice> Mixer::find(const QString& mixdeviceID)
+ {
+- MixDevice *md = 0;
+- for(int i=0; i<_mixerBackend->m_mixDevices.count() ; i++ )
+- {
+- md = _mixerBackend->m_mixDevices[i];
+- if( mixdeviceID == md->id() ) {
+- break;
+- }
+- }
+- return md;
++
++ shared_ptr<MixDevice> mdRet;
++
++ foreach (shared_ptr<MixDevice> md, _mixerBackend->m_mixDevices )
++ {
++ if ( md.get() == 0 )
++ continue; // invalid
++ if ( md->id() == mixdeviceID )
++ {
++ mdRet = md;
++ break; // found
++ }
++ }
++
++ return mdRet;
+ }
+
+
+-MixDevice* Mixer::getMixdeviceById( const QString& mixdeviceID )
++shared_ptr<MixDevice> Mixer::getMixdeviceById( const QString& mixdeviceID )
+ {
+- MixDevice* md = 0;
++ shared_ptr<MixDevice> md;
+ int num = _mixerBackend->id2num(mixdeviceID);
+- if ( num!=-1 && num < (int)size() ) {
++ if ( num!=-1 && num < (int)size() )
++ {
+ md = (*this)[num];
+ }
+ return md;
+@@ -502,7 +516,8 @@
+ - It is fast (no copying of Volume objects required)
+ - It is easy to understand ( read - modify - commit )
+ */
+-void Mixer::commitVolumeChange( MixDevice* md ) {
++void Mixer::commitVolumeChange( shared_ptr<MixDevice> md )
++{
+ _mixerBackend->writeVolumeToHW(md->id(), md );
+ if (md->isEnum()) _mixerBackend->setEnumIdHW(md->id(), md->enumId() );
+ if ( md->captureVolume().hasSwitch() ) {
+@@ -533,8 +548,9 @@
+ void Mixer::increaseOrDecreaseVolume( const QString& mixdeviceID, bool decrease )
+ {
+
+- MixDevice *md= getMixdeviceById( mixdeviceID );
+- if (md != 0) {
++ shared_ptr<MixDevice> md= getMixdeviceById( mixdeviceID );
++ if (md.get() != 0)
++ {
+ Volume& volP=md->playbackVolume();
+ if ( volP.hasVolume() ) {
+ long volSpan = volP.volumeSpan();
+Index: core/mixer.h
+===================================================================
+--- core/mixer.h (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ core/mixer.h (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -65,7 +65,7 @@
+ static int numDrivers();
+ QString getDriverName();
+
+- MixDevice* find(const QString& devPK);
++ shared_ptr<MixDevice> find(const QString& devPK);
+ static Mixer* findMixer( const QString& mixer_id);
+
+ void volumeSave( KConfig *config );
+@@ -75,12 +75,12 @@
+ unsigned int size() const;
+
+ /// Returns a pointer to the mix device with the given number
+- MixDevice* operator[](int val_i_num);
++ shared_ptr<MixDevice> operator[](int val_i_num);
+
+ /// Returns a pointer to the mix device whose type matches the value
+ /// given by the parameter and the array MixerDevNames given in
+ /// mixer_oss.cpp (0 is Volume, 4 is PCM, etc.)
+- MixDevice *getMixdeviceById( const QString& deviceID );
++ shared_ptr<MixDevice> getMixdeviceById( const QString& deviceID );
+
+ /// Open/grab the mixer for further intraction
+ bool openIfValid();
+@@ -148,8 +148,8 @@
+ At the moment it is only used for selecting the Mixer to use in KMix's DockIcon.
+ ******************************************/
+ static void setGlobalMaster(QString ref_card, QString ref_control, bool preferred);
+- static MixDevice* getGlobalMasterMD();
+- static MixDevice* getGlobalMasterMD(bool fallbackAllowed);
++ static shared_ptr<MixDevice> getGlobalMasterMD();
++ static shared_ptr<MixDevice> getGlobalMasterMD(bool fallbackAllowed);
+ static Mixer* getGlobalMasterMixer();
+ static Mixer* getGlobalMasterMixerNoFalback();
+ static MasterControl& getGlobalMasterPreferred();
+@@ -157,11 +157,11 @@
+ /******************************************
+ The recommended master of this Mixer.
+ ******************************************/
+- MixDevice* getLocalMasterMD();
++ shared_ptr<MixDevice> getLocalMasterMD();
+ void setLocalMasterMD(QString&);
+
+ /// get the actual MixSet
+- MixSet getMixSet();
++ MixSet& getMixSet();
+
+ static float VOLUME_STEP_DIVISOR; // The divisor for defining volume control steps (for mouse-wheel, DBUS and Normal step for Sliders )
+ static float VOLUME_PAGESTEP_DIVISOR; // The divisor for defining volume control steps (page-step for sliders)
+@@ -181,7 +181,7 @@
+ virtual int mediaNext(QString id) { return _mixerBackend->mediaNext(id); };
+
+
+- void commitVolumeChange( MixDevice* md );
++ void commitVolumeChange( shared_ptr<MixDevice> md );
+
+ public slots:
+ void readSetFromHWforceUpdate() const;
+Index: core/version.h
+===================================================================
+--- core/version.h (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ core/version.h (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -20,6 +20,6 @@
+ */
+
+ #ifndef APP_VERSION
+-#define APP_VERSION "4"
++#define APP_VERSION "4.1"
+ #define KMIX_CONFIG_VERSION 3
+ #endif // APP_VERSION
+Index: core/mixertoolbox.cpp
+===================================================================
+--- core/mixertoolbox.cpp (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ core/mixertoolbox.cpp (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -19,6 +19,7 @@
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
++#include "core/mixer.h"
+
+ #include <QDir>
+ #include <QWidget>
+@@ -30,7 +31,6 @@
+
+ #include "core/kmixdevicemanager.h"
+ #include "core/mixdevice.h"
+-#include "core/mixer.h"
+
+ #include "core/mixertoolbox.h"
+
+@@ -195,7 +195,7 @@
+ // not one defined in the kmixrc.
+ // So lets just set the first card as master card.
+ if ( Mixer::mixers().count() > 0 ) {
+- MixDevice* master = Mixer::mixers().first()->getLocalMasterMD();
++ shared_ptr<MixDevice> master = Mixer::mixers().first()->getLocalMasterMD();
+ if ( master != 0 ) {
+ QString controlId = master->id();
+ Mixer::setGlobalMaster( Mixer::mixers().first()->id(), controlId, true);
+@@ -205,7 +205,7 @@
+ else {
+ // setGlobalMaster was already set after reading the configuration.
+ // So we must make the local master consistent
+- MixDevice* md = Mixer::getGlobalMasterMD();
++ shared_ptr<MixDevice> md = Mixer::getGlobalMasterMD();
+ QString mdID = md->id();
+ md->mixer()->setLocalMasterMD(mdID);
+ }
+Index: dbus/dbuscontrolwrapper.cpp
+===================================================================
+--- dbus/dbuscontrolwrapper.cpp (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ dbus/dbuscontrolwrapper.cpp (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -24,11 +24,10 @@
+ #include "core/mixer.h"
+ #include "core/volume.h"
+
+-#include <QDebug>
+-
+-DBusControlWrapper::DBusControlWrapper(MixDevice* parent, QString path)
+- : QObject(parent)
+- , m_dbusPath(path)
++DBusControlWrapper::DBusControlWrapper(shared_ptr<MixDevice> parent, const QString& path)
++ : QObject(0)
++// TODO cesken I might need to look into memory leak issues here, as it was required to remove the MixDevice from being parent()
++// I am not about leaking m_md, but the whole DBusControlWrapper instance
+ {
+ m_md = parent;
+ new ControlAdaptor( this );
+@@ -56,17 +55,6 @@
+
+ void DBusControlWrapper::setVolume(int percentage)
+ {
+- // @todo Is hardcoded to PlaybackVolume
+- // @todo This will not work, if minVolume != 0 !!!
+- // e.g.: minVolume=5 or minVolume=-10
+- // The solution is to check two cases:
+- // volume < 0 => use minVolume for volumeRange
+- // volume > 0 => use maxVolume for volumeRange
+- // If chosen volumeRange==0 => return 0
+- // As this is potentially used often (Sliders, ...), it
+- // should be implemented in the Volume class.
+- // For now we go with "maxVolume()", like in the rest of KMix.
+- // - esken
+ Volume& volP = m_md->playbackVolume();
+ Volume& volC = m_md->captureVolume();
+ volP.setAllVolumes( volP.minVolume() + ((percentage * volP.volumeSpan()) / 100) );
+@@ -76,7 +64,8 @@
+
+ int DBusControlWrapper::volume()
+ {
+- return m_md->playbackVolume().getAvgVolumePercent(Volume::MALL);
++ Volume &useVolume = (m_md->playbackVolume().count() != 0) ? m_md->playbackVolume() : m_md->captureVolume();
++ return useVolume.getAvgVolumePercent(Volume::MALL);
+ }
+
+ void DBusControlWrapper::increaseVolume()
+@@ -91,30 +80,27 @@
+
+ long DBusControlWrapper::absoluteVolumeMin()
+ {
+- // @todo Is hardcoded do playbackVolume
+- return m_md->playbackVolume().minVolume();
++ Volume &useVolume = (m_md->playbackVolume().count() != 0) ? m_md->playbackVolume() : m_md->captureVolume();
++ return useVolume.minVolume();
+ }
+
+ long DBusControlWrapper::absoluteVolumeMax()
+ {
+- // @todo Is hardcoded do playbackVolume
+- return m_md->playbackVolume().maxVolume();
++ Volume &useVolume = (m_md->playbackVolume().count() != 0) ? m_md->playbackVolume() : m_md->captureVolume();
++ return useVolume.maxVolume();
+ }
+
+ void DBusControlWrapper::setAbsoluteVolume(long absoluteVolume)
+ {
+- Volume& volP = m_md->playbackVolume();
+- Volume& volC = m_md->captureVolume();
+- volP.setAllVolumes( absoluteVolume );
+- volC.setAllVolumes( absoluteVolume );
++ m_md->playbackVolume().setAllVolumes( absoluteVolume );
++ m_md->captureVolume().setAllVolumes( absoluteVolume );
+ m_md->mixer()->commitVolumeChange( m_md );
+ }
+
+ long DBusControlWrapper::absoluteVolume()
+ {
+- // @todo hardcoded
+- Volume& vol = m_md->playbackVolume();
+- qreal avgVol= vol.getAvgVolume( Volume::MMAIN );
++ Volume &useVolume = (m_md->playbackVolume().count() != 0) ? m_md->playbackVolume() : m_md->captureVolume();
++ qreal avgVol= useVolume.getAvgVolume( Volume::MALL );
+ long avgVolRounded = avgVol <0 ? avgVol-.5 : avgVol+.5;
+ return avgVolRounded;
+ }
+@@ -133,7 +119,7 @@
+
+ bool DBusControlWrapper::canMute()
+ {
+- return m_md->playbackVolume().hasSwitch();
++ return m_md->playbackVolume().hasSwitch();
+ }
+
+ bool DBusControlWrapper::isMuted()
+@@ -148,8 +134,11 @@
+
+ void DBusControlWrapper::setRecordSource(bool on)
+ {
+- MixDevice* md = m_md->mixer()->getMixdeviceById(m_md->id());
+- if ( md != 0 )
+- md->setRecSource(on);
++ m_md->setRecSource(on);
+ m_md->mixer()->commitVolumeChange( m_md );
+ }
++
++bool DBusControlWrapper::hasCaptureSwitch()
++{
++ return m_md->captureVolume().hasSwitch();
++}
+Index: dbus/dbusmixerwrapper.cpp
+===================================================================
+--- dbus/dbusmixerwrapper.cpp (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ dbus/dbusmixerwrapper.cpp (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -19,14 +19,15 @@
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
++#include "dbusmixerwrapper.h"
++
+ #include <QStringList>
+
+-#include "dbusmixerwrapper.h"
+ #include "core/mixdevice.h"
+ #include "core/volume.h"
+ #include "mixeradaptor.h"
+
+-DBusMixerWrapper::DBusMixerWrapper(Mixer* parent, QString path)
++DBusMixerWrapper::DBusMixerWrapper(Mixer* parent, const QString& path)
+ : QObject(parent)
+ , m_dbusPath(path)
+ {
+@@ -51,7 +52,7 @@
+ QStringList DBusMixerWrapper::controls()
+ {
+ QStringList result;
+- foreach ( MixDevice* md, m_mixer->getMixSet() )
++ foreach ( shared_ptr<MixDevice> md, m_mixer->getMixSet() )
+ {
+ result.append( md->dbusPath() );
+ }
+@@ -60,7 +61,7 @@
+
+ QString DBusMixerWrapper::masterControl()
+ {
+- MixDevice* md = m_mixer->getLocalMasterMD();
++ shared_ptr<MixDevice> md = m_mixer->getLocalMasterMD();
+ // XXX: Since empty object path is invalid, using "/"
+ return md ? md->dbusPath() : QString("/");
+ }
+Index: dbus/dbuscontrolwrapper.h
+===================================================================
+--- dbus/dbuscontrolwrapper.h (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ dbus/dbuscontrolwrapper.h (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -38,17 +38,18 @@
+ Q_PROPERTY(bool mute READ isMuted WRITE setMute)
+ Q_PROPERTY(bool recordSource READ isRecordSource WRITE setRecordSource)
+ Q_PROPERTY(bool canMute READ canMute)
++ Q_PROPERTY(bool hasCaptureSwitch READ hasCaptureSwitch)
+
+ public:
+- DBusControlWrapper(MixDevice* parent, QString path);
++ DBusControlWrapper(shared_ptr<MixDevice> parent, const QString& path);
+ ~DBusControlWrapper();
+
+ void increaseVolume();
+ void decreaseVolume();
+ void toggleMute();
+ private:
+- MixDevice *m_md;
+- QString m_dbusPath;
++ shared_ptr<MixDevice> m_md;
++
+ QString id();
+ QString readableName();
+ QString iconName();
+@@ -61,10 +62,11 @@
+ long absoluteVolumeMax();
+ long absoluteVolume();
+
+- bool canMute();
++ bool canMute();
+ void setMute(bool muted);
+ bool isMuted();
+
++ bool hasCaptureSwitch();
+ void setRecordSource(bool on);
+ bool isRecordSource();
+ };
+Index: dbus/dbusmixerwrapper.h
+===================================================================
+--- dbus/dbusmixerwrapper.h (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ dbus/dbusmixerwrapper.h (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -19,8 +19,8 @@
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+-#ifndef DBUS_MIXER_WRAPPER_H
+-#define DBUS_MIXER_WRAPPER_H
++#ifndef DBUSMIXERWRAPPER_H
++#define DBUSMIXERWRAPPER_H
+
+ #include <QObject>
+ #include <QStringList>
+@@ -40,7 +40,7 @@
+ Q_PROPERTY(QStringList controls READ controls)
+
+ public:
+- DBusMixerWrapper(Mixer* parent, QString path);
++ DBusMixerWrapper(Mixer* parent, const QString& path);
+ ~DBusMixerWrapper();
+ QString driverName();
+
+@@ -62,4 +62,4 @@
+ void slotControlsReconfigured();
+ };
+
+-#endif /* DBUS_MIXER_WRAPPER_H */
++#endif /* DBUSMIXERWRAPPER_H */
+Index: dbus/dbusmixsetwrapper.cpp
+===================================================================
+--- dbus/dbusmixsetwrapper.cpp (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ dbus/dbusmixsetwrapper.cpp (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -18,11 +18,12 @@
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
++#include "dbusmixsetwrapper.h"
++
+ #include "core/mixdevice.h"
+-#include "dbusmixsetwrapper.h"
+ #include "mixsetadaptor.h"
+
+-DBusMixSetWrapper::DBusMixSetWrapper(QObject* parent, QString path)
++DBusMixSetWrapper::DBusMixSetWrapper(QObject* parent, const QString& path)
+ : QObject(parent)
+ , m_dbusPath( path )
+ {
+@@ -55,7 +56,7 @@
+
+ QString DBusMixSetWrapper::currentMasterControl() const
+ {
+- MixDevice* masterControl = Mixer::getGlobalMasterMD();
++ shared_ptr<MixDevice> masterControl = Mixer::getGlobalMasterMD();
+ return masterControl ? masterControl->id() : QString();
+ }
+
+Index: dbus/dbusmixsetwrapper.h
+===================================================================
+--- dbus/dbusmixsetwrapper.h (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ dbus/dbusmixsetwrapper.h (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -18,8 +18,8 @@
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+-#ifndef DBUS_KMIX_WRAPPER_H
+-#define DBUS_KMIX_WRAPPER_H
++#ifndef DBUSMIXSETWRAPPER_H
++#define DBUSMIXSETWRAPPER_H
+
+ #include <QStringList>
+ #include "core/mixer.h"
+@@ -33,7 +33,7 @@
+ Q_PROPERTY(QString preferredMasterMixer READ preferredMasterMixer)
+ Q_PROPERTY(QString preferredMasterControl READ preferredMasterControl)
+ public:
+- DBusMixSetWrapper(QObject* parent, QString path);
++ DBusMixSetWrapper(QObject* parent, const QString& path);
+ ~DBusMixSetWrapper();
+ public slots:
+ QStringList mixers() const;
+@@ -55,4 +55,4 @@
+
+ };
+
+-#endif /* DBUS_KMIX_WRAPPER_H */
++#endif /* DBUSMIXSETWRAPPER_H */
+Index: dbus/org.kde.kmix.control.xml
+===================================================================
+--- dbus/org.kde.kmix.control.xml (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ dbus/org.kde.kmix.control.xml (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -4,10 +4,11 @@
+ <interface name="org.kde.KMix.Control">
+ <property access="read" name="id" type="s"/>
+ <property access="read" name="readableName" type="s"/>
+- <property access="read" name="iconName" type="s"/>
++ <property access="read" name="iconName" type="s"/>
+ <property access="readwrite" name="mute" type="b"/>
+ <property access="read" name="canMute" type="b"/>
+ <property access="readwrite" name="recordSource" type="b"/>
++ <property access="read" name="hasCaptureSwitch" type="b"/>
+ <property access="readwrite" name="volume" type="i"/>
+ <property access="readwrite" name="absoluteVolume" type="i"/>
+ <property access="read" name="absoluteVolumeMin" type="i"/>
+Index: TestCases
+===================================================================
+--- TestCases (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ TestCases (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -14,6 +14,7 @@
+ 11: kmixctrl --restore (with existing .kmixctrlrc) must restore volumes
+ 12: kmixctrl --restore (without existing .kmixctrlrc) must NOT change volumes
+ 13: "Switch-only" controls are available and work (e.g: IEC958': Capabilities: pswitch pswitch-joined cswitch cswitch-joined)
++14: Rapid stream creation/deletion works properly (KMix shows and hides the controls, no crash). for i in 1 2 3 4 5 6 7 8 9 10; do paplay /Multimedia/Kennedy_berliner.ogg& done
+
+
+
+Index: tests/dialogtest.cpp
+===================================================================
+--- tests/dialogtest.cpp (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ tests/dialogtest.cpp (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -1,3 +1,5 @@
++#include <dialogtest.h>
++
+ #include <QCheckBox>
+ #include <QLabel>
+ #include <QScrollArea>
+@@ -8,9 +10,7 @@
+ #include <kcmdlineargs.h>
+ #include <kglobal.h>
+
+-#include <dialogtest.h>
+
+-
+ extern "C" KDE_EXPORT int kdemain(int argc, char *argv[])
+ {
+ KAboutData aboutData( "dialogtest", 0, ki18n("dialogtest"),
+Index: tests/CMakeLists.txt
+===================================================================
+--- tests/CMakeLists.txt (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ tests/CMakeLists.txt (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -30,9 +30,9 @@
+ target_link_libraries(profiletest ${ASOUND_LIBRARY})
+ endif (HAVE_LIBASOUND2)
+
+-if (HAVE_PULSE)
++if (PULSEAUDIO_FOUND)
+ target_link_libraries(profiletest ${PULSEAUDIO_LIBRARY} ${PULSEAUDIO_MAINLOOP_LIBRARY} ${GLIB2_LIBRARIES})
+-endif (HAVE_PULSE)
++endif (PULSEAUDIO_FOUND)
+
+ ########### next target ###############
+ set(dialogtest_KDEINIT_SRCS dialogtest.cpp )
+Index: apps/kmix.cpp
+===================================================================
+--- apps/kmix.cpp (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ apps/kmix.cpp (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -883,13 +883,13 @@
+ }
+ MixerToolBox::instance()->removeMixer(mixer);
+ // Check whether the Global Master disappeared, and select a new one if necessary
+- MixDevice* md = Mixer::getGlobalMasterMD();
+- if ( globalMasterMixerDestroyed || md == 0 ) {
++ shared_ptr<MixDevice> md = Mixer::getGlobalMasterMD();
++ if ( globalMasterMixerDestroyed || md.get() == 0 ) {
+ // We don't know what the global master should be now.
+ // So lets play stupid, and just select the recommended master of the first device
+ if ( Mixer::mixers().count() > 0 ) {
+- MixDevice *master = ((Mixer::mixers())[0])->getLocalMasterMD();
+- if ( md != 0 ) {
++ shared_ptr<MixDevice> master = ((Mixer::mixers())[0])->getLocalMasterMD();
++ if ( master.get() != 0 ) {
+ QString localMaster = master->id();
+ Mixer::setGlobalMaster( ((Mixer::mixers())[0])->id(), localMaster, false);
+
+@@ -1036,9 +1036,12 @@
+ void KMixWindow::increaseOrDecreaseVolume(bool increase)
+ {
+ Mixer* mixer = Mixer::getGlobalMasterMixer(); // only needed for the awkward construct below
+- if ( mixer == 0 ) return; // e.g. when no soundcard is available
+- MixDevice *md = Mixer::getGlobalMasterMD();
+- if ( md == 0 ) return; // shouldn't happen, but lets play safe
++ if ( mixer == 0 )
++ return; // e.g. when no soundcard is available
++ shared_ptr<MixDevice> md = Mixer::getGlobalMasterMD();
++ if ( md.get() == 0 )
++ return; // shouldn't happen, but lets play safe
++
+ md->setMuted(false);
+ if (increase)
+ mixer->increaseVolume(md->id()); // this is awkward. Better move the increaseVolume impl to the Volume class.
+@@ -1061,9 +1064,11 @@
+ void KMixWindow::showVolumeDisplay()
+ {
+ Mixer* mixer = Mixer::getGlobalMasterMixer();
+- if ( mixer == 0 ) return; // e.g. when no soundcard is available
+- MixDevice *md = Mixer::getGlobalMasterMD();
+- if ( md == 0 ) return; // shouldn't happen, but lets play safe
++ if ( mixer == 0 )
++ return; // e.g. when no soundcard is available
++ shared_ptr<MixDevice> md = Mixer::getGlobalMasterMD();
++ if ( md.get() == 0 )
++ return; // shouldn't happen, but lets play safe
+ // Current volume
+ Volume& vol = md->playbackVolume();
+
+@@ -1082,9 +1087,11 @@
+ void KMixWindow::slotMute()
+ {
+ Mixer* mixer = Mixer::getGlobalMasterMixer();
+- if ( mixer == 0 ) return; // e.g. when no soundcard is available
+- MixDevice *md = Mixer::getGlobalMasterMD();
+- if ( md == 0 ) return; // shouldn't happen, but lets play safe
++ if ( mixer == 0 )
++ return; // e.g. when no soundcard is available
++ shared_ptr<MixDevice> md = Mixer::getGlobalMasterMD();
++ if ( md.get() == 0 )
++ return; // shouldn't happen, but lets play safe
+ md->toggleMute();
+ mixer->commitVolumeChange( md );
+ showVolumeDisplay();
+@@ -1191,7 +1198,7 @@
+ msg += startErrorMessage;
+ msg += "\n(";
+ msg += args.join( QLatin1String( " " ));
+- msg += ")";
++ msg += ')';
+ errorPopup(msg);
+ }
+
+Index: apps/kmixd.cpp
+===================================================================
+--- apps/kmixd.cpp (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ apps/kmixd.cpp (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -20,6 +20,8 @@
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
++#include "kmixd.h"
++
+ #include <kaboutdata.h>
+ #include <kcmdlineargs.h>
+
+@@ -27,9 +29,7 @@
+ #include <klocale.h>
+ #include <kconfig.h>
+ #include <kaction.h>
+-//#include <kapplication.h>
+ #include <kstandardaction.h>
+-//#include <kmenu.h>
+ #include <kdebug.h>
+ #include <kxmlguifactory.h>
+ #include <kglobal.h>
+@@ -40,20 +40,10 @@
+ #include <kpluginloader.h>
+
+ // KMix
+-//#include "gui/guiprofile.h"
+ #include "core/mixertoolbox.h"
+-#include "kmixd.h"
+ #include "core/kmixdevicemanager.h"
+-//#include "gui/kmixerwidget.h"
+-//#include "gui/kmixprefdlg.h"
+-//#include "gui/kmixdockwidget.h"
+-//#include "gui/kmixtoolbox.h"
+ #include "core/version.h"
+-//#include "gui/viewdockareapopup.h"
+-//#include "gui/dialogselectmaster.h"
+
+-//#include "gui/osdwidget.h"
+-
+ K_PLUGIN_FACTORY(KMixDFactory,
+ registerPlugin<KMixD>();
+ )
+@@ -167,7 +157,7 @@
+ if ( mixerMasterCard != 0 ) {
+ config.writeEntry( "MasterMixer", mixerMasterCard->id() );
+ }
+- MixDevice* mdMaster = Mixer::getGlobalMasterMD();
++ shared_ptr<MixDevice> mdMaster = Mixer::getGlobalMasterMD();
+ if ( mdMaster != 0 ) {
+ config.writeEntry( "MasterMixerDevice", mdMaster->id() );
+ }
+@@ -299,13 +289,13 @@
+
+ MixerToolBox::instance()->removeMixer(mixer);
+ // Check whether the Global Master disappeared, and select a new one if necessary
+- MixDevice* md = Mixer::getGlobalMasterMD();
+- if ( globalMasterMixerDestroyed || md == 0 ) {
++ shared_ptr<MixDevice> md = Mixer::getGlobalMasterMD();
++ if ( globalMasterMixerDestroyed || md.get() == 0 ) {
+ // We don't know what the global master should be now.
+ // So lets play stupid, and just select the recommended master of the first device
+ if ( Mixer::mixers().count() > 0 ) {
+- MixDevice *master = ((Mixer::mixers())[0])->getLocalMasterMD();
+- if ( md != 0 ) {
++ shared_ptr<MixDevice> master = ((Mixer::mixers())[0])->getLocalMasterMD();
++ if ( master.get() != 0 ) {
+ QString localMaster = master->id();
+ Mixer::setGlobalMaster( ((Mixer::mixers())[0])->id(), localMaster, false);
+
+Index: config.h.cmake
+===================================================================
+--- config.h.cmake (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ config.h.cmake (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -1,39 +1,9 @@
+ /* config.h. Generated by cmake from config.h.cmake */
+ /* Don't add anything new here!!! Use per-directory generated files. */
+
+-/* Define to 1 if you have the <Alib.h> header file. */
+-#cmakedefine HAVE_ALIB_H 1
+-
+-/* Define to 1 if you have the <alloca.h> header file. */
+-#cmakedefine HAVE_ALLOCA_H 1
+-
+-/* define to 1 if you have PulseAudio headers */
+-#cmakedefine HAVE_PULSE 1
+-
+ /* Define if you ogg/vorbis installed */
+ #cmakedefine HAVE_VORBIS ${OGGVORBIS_VERSION}
+
+-/* Define to 1 if you have the <linux/cdrom.h> header file. */
+-#cmakedefine HAVE_LINUX_CDROM_H 1
+-
+-/* Define to 1 if you have the <linux/ucdrom.h> header file. */
+-#cmakedefine HAVE_LINUX_UCDROM_H 1
+-
+-/* Define to 1 if you have the <machine/soundcard.h> header file. */
+-#cmakedefine HAVE_MACHINE_SOUNDCARD_H 1
+-
+-/* Define to 1 if you have the <soundcard.h> header file. */
+-#cmakedefine HAVE_SOUNDCARD_H 1
+-
+-/* Define to 1 if you have the <sys/audioio.h> header file. */
+-#cmakedefine HAVE_SYS_AUDIOIO_H 1
+-
+-/* Define to 1 if you have the <sys/soundcard.h> header file. */
+-#cmakedefine HAVE_SYS_SOUNDCARD_H 1
+-
+-/* Define to 1 if you have the <sys/stat.h> header file. */
+-#cmakedefine HAVE_SYS_STAT_H 1
+-
+ /* Define to 1 if you have the <machine/endian.h> header file. */
+ #cmakedefine HAVE_MACHINE_ENDIAN_H 1
+
+@@ -43,14 +13,5 @@
+ /* Define to 1 if you have the <sys/endian.h> header file. */
+ #cmakedefine HAVE_ENDIAN_H 1
+
+-/* Define if you have XShmGetEventBase in <X11/extensions/XShm.h */
+-#cmakedefine HAVE_XSHMGETEVENTBASE 1
+-
+-/* The size of a `long', as computed by sizeof. */
+-#define SIZEOF_LONG ${SIZEOF_LONG}
+-
+-/* Compatibility with older version of xine */
+-/* #undef _x_ao_new_port */
+-
+ /* Define to 1 if you have the <unistd.h> header file. */
+ #cmakedefine HAVE_UNISTD_H 1
+Index: backends/mixer_hpux.cpp
+===================================================================
+--- backends/mixer_hpux.cpp (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ backends/mixer_hpux.cpp (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -1,243 +0,0 @@
+-/*
+- * KMix -- KDE's full featured mini mixer
+- *
+- *
+- * Copyright (C) 1996-2000 Christian Esken <esken at kde.org>
+- * HP/UX-Port: Copyright (C) 1999 by Helge Deller <deller at gmx.de>
+- *
+- * This program is free software; you can redistribute it and/or
+- * modify it under the terms of the GNU Library General Public
+- * License as published by the Free Software Foundation; either
+- * version 2 of the License, or (at your option) any later version.
+- *
+- * This program is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- * Library General Public License for more details.
+- *
+- * You should have received a copy of the GNU Library General Public
+- * License along with this program; if not, write to the Free
+- * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+- */
+-
+-#include "mixer_hpux.h"
+-
+-#error "The HP/UX port is not maintained anymore, an no official part of KMix / KDE at this point of time! Please contact the current KMix maintainer if you would like to maintain the port."
+-
+-#define HPUX_ERROR_OFFSET 1024
+-
+-#define myGain AUnityGain /* AUnityGain or AZeroGain */
+-
+-#define GAIN_OUT_DIFF ((long) ((int)aMaxOutputGain(audio) - (int)aMinOutputGain(audio)))
+-#define GAIN_OUT_MIN ((long) aMinOutputGain(audio))
+-#define GAIN_IN_DIFF ((long) ((int)aMaxInputGain(audio) - (int)aMinInputGain(audio)))
+-#define GAIN_IN_MIN ((long) aMinOutputGain(audio))
+-
+-/* standard */
+-#define ID_PCM 4
+-
+-/* AInputSrcType: */ /*OSS:*/
+-#define ID_IN_MICROPHONE 7 /* AISTMonoMicrophone */
+-#define ID_IN_AUX 6 /* AISTLeftAuxiliary, AISTRightAuxiliary */
+-
+-/* AOutputDstType: */
+-#define ID_OUT_INT_SPEAKER 0 /* AODTMonoIntSpeaker */
+-
+-/* not yet implemented:
+- AODTLeftJack, AODTRightJack,
+- AODTLeftLineOut, AODTRightLineOut,
+- AODTLeftHeadphone, AODTRightHeadphone
+-
+-const char* MixerDevNames[32]={"Volume" , "Bass" , "Treble" , "Synth" , "Pcm" , \
+- "Speaker" , "Line" , "Microphone", "CD" , "Mix" , \
+- "Pcm2" , "RecMon" , "IGain" , "OGain" , "Line1", \
+- "Line2" , "Line3" , "Digital1" , "Digital2", "Digital3", \
+- "PhoneIn" , "PhoneOut", "Video" , "Radio" , "Monitor", \
+- "3D-depth", "3D-center", "unknown" , "unknown" , "unknown", \
+- "unknown" , "unused" };
+-*/
+-
+-
+-
+-Mixer_HPUX::Mixer_HPUX(int devnum) : Mixer_Backend(devnum)
+-{
+- char ServerName[10];
+- ServerName[0] = 0;
+- audio = AOpenAudio(ServerName,NULL);
+-}
+-
+-Mixer_HPUX::~Mixer_HPUX()
+-{
+- if (audio) {
+- ACloseAudio(audio,0);
+- audio = 0;
+- }
+-}
+-
+-
+-int Mixer_HPUX::open()
+-{
+- if (audio==0) {
+- return Mixer::ERR_OPEN;
+- }
+- else
+- {
+- /* Mixer is open. Now define properties */
+- stereodevs = devmask = (1<<ID_PCM); /* activate pcm */
+- recmask = 0;
+-
+- /* check Input devices... */
+- if (AInputSources(audio) & AMonoMicrophoneMask) {
+- devmask |= (1<<ID_IN_MICROPHONE);
+- recmask |= (1<<ID_IN_MICROPHONE);
+- }
+- if (AInputSources(audio) & (ALeftAuxiliaryMask|ARightAuxiliaryMask)) {
+- devmask |= (1<<ID_IN_AUX);
+- recmask |= (1<<ID_IN_AUX);
+- stereodevs |= (1<<ID_IN_AUX);
+- }
+-
+- /* check Output devices... */
+- if (AOutputDestinations(audio) & AMonoIntSpeakerMask) {
+- devmask |= (1<<ID_OUT_INT_SPEAKER);
+- stereodevs |= (1<<ID_OUT_INT_SPEAKER);
+- }
+-
+-/* implement later:
+- ----------------
+- if (AOutputDestinations(audio) & AMonoLineOutMask) devmask |= 64; // Line
+- if (AOutputDestinations(audio) & AMonoJackMask) devmask |= (1<<14); // Line1
+- if (AOutputDestinations(audio) & AMonoHeadphoneMask) devmask |= (1<<15); // Line2
+-*/
+-
+- MaxVolume = 255;
+-
+- long error = 0;
+- ASetSystemPlayGain(audio, myGain, &error);
+- if (error) errorText(error + HPUX_ERROR_OFFSET);
+- ASetSystemRecordGain(audio, myGain, &error);
+- if (error) errorText(error + HPUX_ERROR_OFFSET);
+-
+- i_recsrc = 0;
+- m_isOpen = true;
+-
+- m_mixerName = "HP Mixer"; /* AAudioString(audio); */
+- return 0;
+- }
+-}
+-
+-int Mixer_HPUX::close()
+-{
+- _pollingTimer->stop();
+- m_isOpen = false;
+- m_mixDevices.clear();
+- return 0;
+-}
+-
+-int Mixer_HPUX::readVolumeFromHW( int devnum, Volume &vol, Volume & )
+-{
+- long Gain;
+- long error = 0;
+- int vl,vr;
+-
+- switch (devnum) {
+- case ID_OUT_INT_SPEAKER: /* AODTMonoIntSpeaker */
+- AGetSystemChannelGain(audio, ASGTPlay, ACTMono, &Gain, &error );
+- vl = vr = (Gain-GAIN_OUT_MIN)*255 / GAIN_OUT_DIFF;
+- vol.setVolume( Volume::LEFT, vl);
+- vol.setVolume( Volume::RIGHT, vr);
+-printf("READ - Devnum: %d, Left: %d, Right: %d\n", devnum, vl, vr );
+- break;
+-
+- case ID_IN_AUX: /* AISTLeftAuxiliary, AISTRightAuxiliary */
+- case ID_IN_MICROPHONE: /* AISTMonoMicrophone */
+- AGetSystemChannelGain(audio, ASGTRecord, ACTMono, &Gain, &error );
+- vl = vr = (Gain-GAIN_IN_MIN)*255 / GAIN_IN_DIFF;
+- vol.setVolume( Volume::LEFT, vl);
+- vol.setVolume( Volume::RIGHT, vr);
+- break;
+-
+- default:
+- error = Mixer::ERR_READ - HPUX_ERROR_OFFSET;
+- break;
+- };
+-
+- return (error ? (error+HPUX_ERROR_OFFSET) : 0);
+-}
+-
+-/*
+- ASystemGainType = ASGTPlay, ASGTRecord, ASGTMonitor
+- AChType = ACTMono, ACTLeft, ACTRight
+-*/
+-
+-int Mixer_HPUX::writeVolumeToHW( int devnum, Volume& vol, Volume & )
+-{
+- long Gain;
+- long error = 0;
+- int vl = vol.getVolume(Volume::LEFT);
+- int vr = vol.getVolume(Volume::RIGHT);
+-
+- switch (devnum) {
+- case ID_OUT_INT_SPEAKER: /* AODTMonoIntSpeaker */
+-printf("WRITE - Devnum: %d, Left: %d, Right: %d\n", devnum, vl, vr);
+- Gain = vl; // only left Volume
+- Gain = (Gain*GAIN_OUT_DIFF) / 255 - GAIN_OUT_MIN;
+- ASetSystemChannelGain(audio, ASGTPlay, ACTMono, (AGainDB) Gain, &error );
+- break;
+-
+- case ID_IN_MICROPHONE: /* AISTMonoMicrophone */
+- Gain = vl; // only left Volume
+- Gain = (Gain*GAIN_IN_DIFF) / 255 - GAIN_IN_MIN;
+- ASetSystemChannelGain(audio, ASGTRecord, ACTMono, (AGainDB) Gain, &error );
+- break;
+-
+- case ID_IN_AUX: /* AISTLeftAuxiliary, AISTRightAuxiliary */
+- Gain = (vl*GAIN_IN_DIFF) / 255 - GAIN_IN_MIN;
+- ASetSystemChannelGain(audio, ASGTRecord, ACTLeft, (AGainDB) Gain, &error );
+- Gain = (vr*GAIN_IN_DIFF) / 255 - GAIN_IN_MIN;
+- ASetSystemChannelGain(audio, ASGTRecord, ACTRight, (AGainDB) Gain, &error );
+- break;
+-
+- default:
+- error = Mixer::ERR_READ - HPUX_ERROR_OFFSET;
+- break;
+- };
+- return (error ? (error+HPUX_ERROR_OFFSET) : 0);
+-}
+-
+-
+-QString Mixer_HPUX::errorText(int mixer_error)
+-{
+- QString l_s_errmsg;
+- if (mixer_error >= HPUX_ERROR_OFFSET) {
+- char errorstr[200];
+- AGetErrorText(audio, (AError) (mixer_error-HPUX_ERROR_OFFSET),
+- errorstr, sizeof(errorstr));
+- printf("kmix: %s: %s\n",mixerName().data(), errorstr);
+- l_s_errmsg = errorstr;
+- } else
+- switch (mixer_error)
+- {
+- case Mixer::ERR_OPEN:
+- // should use i18n...
+- l_s_errmsg = "kmix: HP-UX Alib-Mixer cannot be found.\n" \
+- "Please check that you have:\n" \
+- " 1. Installed the libAlib package and\n" \
+- " 2. started the Aserver program from the /opt/audio/bin directory\n";
+- break;
+- default:
+- l_s_errmsg = Mixer_Backend::errorText(mixer_error);
+- break;
+- }
+- return l_s_errmsg;
+-}
+-
+-QString HPUX_getDriverName() {
+- return "HPUX";
+-}
+-
+-QString Mixer_HPUX::getDriverName()
+-{
+- return "HPUX";
+-}
+-
+Index: backends/mixer_hpux.h
+===================================================================
+--- backends/mixer_hpux.h (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ backends/mixer_hpux.h (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -1,56 +0,0 @@
+-//-*-C++-*-
+-/*
+- * KMix -- KDE's full featured mini mixer
+- *
+- * Copyright Christian Esken <esken at kde.org>
+- * Copyright (C) 1999 by Helge Deller <deller at gmx.de>
+- *
+- * This program is free software; you can redistribute it and/or
+- * modify it under the terms of the GNU Library General Public
+- * License as published by the Free Software Foundation; either
+- * version 2 of the License, or (at your option) any later version.
+- *
+- * This program is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- * Library General Public License for more details.
+- *
+- * You should have received a copy of the GNU Library General Public
+- * License along with this program; if not, write to the Free
+- * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+- */
+-#ifndef MIXER_HPUX_H
+-#define MIXER_HPUX_H
+-
+-#define DEFAULT_MIXER "HP-UX Mixer"
+-#ifdef HAVE_ALIB_H
+-#include <Alib.h>
+-#define HPUX_MIXER
+-#endif
+-
+-#include "mixer_backend.h"
+-
+-class Mixer_HPUX : public Mixer_Backend
+-{
+-public:
+- Mixer_HPUX(int devnum=0);
+- virtual ~Mixer_HPUX();
+-
+- virtual QString errorText(int mixer_error);
+-
+- virtual int readVolumeFromHW( int devnum, Volume &vol, Volume& );
+- virtual int writeVolumeToHW ( int devnum, Volume &vol, Volume& );
+-
+- virtual QString getDriverName();
+-
+-protected:
+- virtual int open();
+- virtual int close();
+-
+- Audio *audio;
+- unsigned int stereodevs,devmask, recmask, MaxVolume, i_recsrc;
+-
+-
+-};
+-
+-#endif
+Index: backends/mixer_backend.h
+===================================================================
+--- backends/mixer_backend.h (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ backends/mixer_backend.h (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -74,9 +74,9 @@
+ void readSetFromHWforceUpdate() const;
+
+ /// Volume Read
+- virtual int readVolumeFromHW( const QString& id, MixDevice * ) = 0;
++ virtual int readVolumeFromHW( const QString& id, shared_ptr<MixDevice> ) = 0;
+ /// Volume Write
+- virtual int writeVolumeToHW( const QString& id, MixDevice * ) = 0;
++ virtual int writeVolumeToHW( const QString& id, shared_ptr<MixDevice> ) = 0;
+
+ /// Enums
+ virtual void setEnumIdHW(const QString& id, unsigned int);
+@@ -91,7 +91,7 @@
+ /// Overwrite in the backend if the backend can see changes without polling
+ virtual bool needsPolling() { return true; }
+
+- MixDevice* recommendedMaster();
++ shared_ptr<MixDevice> recommendedMaster();
+
+ /** Return a translated error text for the given error number.
+ * Subclasses can override this method to produce platform
+@@ -121,13 +121,13 @@
+
+ /******************************************************************************************
+ * Please don't access the next vars from the Mixer class (even though Mixer is a friend).
+- * There are proper accesor methods for them.
++ * There are proper access methods for them.
+ ******************************************************************************************/
+ bool m_isOpen;
+ // The MixDevice that would qualify best as MasterDevice (according to the taste of the Backend developer)
+- MixDevice* m_recommendedMaster;
++ shared_ptr<MixDevice> m_recommendedMaster;
+ // The Mixer is stored her only for one reason: The backend creates the MixDevice's, and it has shown
+- // that it is helpful if the MixDevice's know their correspondig Mixer. KMix lived 10 years without that,
++ // that it is helpful if the MixDevice's know their corresponding Mixer. KMix lived 10 years without that,
+ // but just believe me. It's *really* better, for example, you can put controls of different soundcards in
+ // one View. That is very cool! Also the MDW doesn't need to store the Mixer any longer (MDW is a GUI element,
+ // so that was 'wrong' anyhow
+Index: backends/mixer_oss4.h
+===================================================================
+--- backends/mixer_oss4.h (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ backends/mixer_oss4.h (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -9,15 +9,15 @@
+ class Mixer_OSS4 : public Mixer_Backend
+ {
+ public:
+- Mixer_OSS4(Mixer* mixer, int device = -1);
++ Mixer_OSS4(Mixer* mixer, int device);
+ virtual ~Mixer_OSS4();
+
+ virtual QString errorText(int mixer_error);
+ virtual QString getDriverName();
+ virtual bool CheckCapture(oss_mixext *ext);
+ virtual bool prepareUpdateFromHW();
+- virtual int readVolumeFromHW(const QString& id, MixDevice *md);
+- virtual int writeVolumeToHW(const QString& id, MixDevice *md );
++ virtual int readVolumeFromHW(const QString& id, shared_ptr<MixDevice> md);
++ virtual int writeVolumeToHW(const QString& id, shared_ptr<MixDevice> md );
+ virtual void setEnumIdHW(const QString& id, unsigned int idx);
+ virtual unsigned int enumIdHW(const QString& id);
+
+Index: backends/mixer_pulse.h
+===================================================================
+--- backends/mixer_pulse.h (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ backends/mixer_pulse.h (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -49,8 +49,8 @@
+ Mixer_PULSE(Mixer *mixer, int devnum);
+ virtual ~Mixer_PULSE();
+
+- virtual int readVolumeFromHW( const QString& id, MixDevice *md );
+- virtual int writeVolumeToHW ( const QString& id, MixDevice *md );
++ virtual int readVolumeFromHW( const QString& id, shared_ptr<MixDevice> );
++ virtual int writeVolumeToHW ( const QString& id, shared_ptr<MixDevice> );
+
+ virtual bool moveStream( const QString& id, const QString& destId );
+
+@@ -73,8 +73,8 @@
+ private:
+ void addDevice(devinfo& dev, bool = false);
+ bool connectToDaemon();
+-
+- public slots:
++ void emitControlsReconfigured();
++public:
+ void reinit();
+
+ };
+Index: backends/mixer_oss.cpp
+===================================================================
+--- backends/mixer_oss.cpp (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ backends/mixer_oss.cpp (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -148,8 +148,7 @@
+
+ QString id;
+ id.setNum(idx);
+- MixDevice* md =
+- new MixDevice(
++ MixDevice* md = new MixDevice(
+ _mixer,
+ id,
+ i18n(MixerDevNames[idx]),
+@@ -163,7 +162,7 @@
+ md->addCaptureVolume(captureVol);
+ }
+
+- m_mixDevices.append( md );
++ m_mixDevices.append( md->addToPool() );
+ }
+ idx++;
+ }
+@@ -315,7 +314,7 @@
+ {
+ for(int i=0; i< m_mixDevices.count() ; i++ )
+ {
+- MixDevice *md = m_mixDevices[i];
++ shared_ptr<MixDevice> md = m_mixDevices[i];
+ bool isRecsrc = ( (recsrcMask & ( 1<<devnum)) != 0 );
+ md->setRecSource(isRecsrc);
+ } // for all controls
+@@ -328,7 +327,7 @@
+
+
+
+-int Mixer_OSS::readVolumeFromHW( const QString& id, MixDevice* md )
++int Mixer_OSS::readVolumeFromHW( const QString& id, shared_ptr<MixDevice> md )
+ {
+ int ret = 0;
+
+@@ -429,7 +428,7 @@
+
+
+
+-int Mixer_OSS::writeVolumeToHW( const QString& id, MixDevice *md)
++int Mixer_OSS::writeVolumeToHW( const QString& id, shared_ptr<MixDevice> md)
+ {
+ int volume;
+ int devnum = id2num(id);
+Index: backends/mixer_sun.cpp
+===================================================================
+--- backends/mixer_sun.cpp (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ backends/mixer_sun.cpp (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -20,6 +20,8 @@
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
++#include "mixer_sun.h"
++
+ #include <sys/types.h>
+ #include <sys/stat.h>
+ #include <fcntl.h>
+@@ -29,7 +31,6 @@
+ #include <unistd.h>
+ #include <stdlib.h>
+
+-#include "mixer_sun.h"
+ #include "core/mixer.h"
+ #include <sys/soundcard.h>
+ #include <QTimer>
+@@ -202,7 +203,7 @@
+ Volume captureVol( 100, 1, true, true );
+ md->addCaptureVolume(captureVol);
+ }
+- m_mixDevices.append( md );
++ m_mixDevices.append( md->addToPool() );
+ }
+
+ m_mixerName = "SUN Audio Mixer";
+@@ -251,7 +252,7 @@
+ // FUNCTION : Mixer::readVolumeFromHW
+ // DESCRIPTION : Read the audio information from the driver.
+ //======================================================================
+-int Mixer_SUN::readVolumeFromHW( const QString& id, MixDevice *md )
++int Mixer_SUN::readVolumeFromHW( const QString& id, shared_ptr<MixDevice> md )
+ {
+ audio_info_t audioinfo;
+ int devnum = id2num(id);
+@@ -313,7 +314,7 @@
+ // FUNCTION : Mixer::writeVolumeToHW
+ // DESCRIPTION : Write the specified audio settings to the hardware.
+ //======================================================================
+-int Mixer_SUN::writeVolumeToHW( const QString& id, MixDevice *md )
++int Mixer_SUN::writeVolumeToHW( const QString& id, shared_ptr<MixDevice> md )
+ {
+ uint_t gain;
+ uchar_t balance;
+Index: backends/mixer_alsa9.cpp
+===================================================================
+--- backends/mixer_alsa9.cpp (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ backends/mixer_alsa9.cpp (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -65,11 +65,13 @@
+ m_fds = 0;
+ // m_sns = 0;
+ _handle = 0;
++ ctl_handle = 0;
+ _initialUpdate = true;
+ }
+
+ Mixer_ALSA::~Mixer_ALSA()
+ {
++ qDebug() << "Running Mixer_ALSA destructor";
+ close();
+ }
+
+@@ -158,7 +160,7 @@
+ QString mdID("%1:%2");
+ mdID = mdID.arg(snd_mixer_selem_id_get_name ( sid ) )
+ .arg(snd_mixer_selem_id_get_index( sid ) );
+- mdID.replace(" ","_"); // Any key/ID we use, must not uses spaces (rule)
++ mdID.replace(' ','_'); // Any key/ID we use, must not uses spaces (rule)
+
+ MixDevice::ChannelType ct = (MixDevice::ChannelType)identify( sid );
+
+@@ -186,7 +188,7 @@
+ // Add a number to the control name, like "PCM 2", when the index is > 0
+ QString idxString;
+ idxString.setNum(1+controlInstanceIndex);
+- readableName += " ";
++ readableName += ' ';
+ readableName += idxString;
+ }
+
+@@ -208,12 +210,13 @@
+ idx++;
+
+
+- MixDevice* md = new MixDevice(_mixer, finalMixdeviceID, readableName, ct );
++ MixDevice* mdNew = new MixDevice(_mixer, finalMixdeviceID, readableName, ct );
+
+- if ( volPlay != 0 ) md->addPlaybackVolume(*volPlay);
+- if ( volCapture != 0 ) md->addCaptureVolume (*volCapture);
+- if ( !enumList.isEmpty() ) md->addEnums(enumList);
+-
++ if ( volPlay != 0 ) mdNew->addPlaybackVolume(*volPlay);
++ if ( volCapture != 0 ) mdNew->addCaptureVolume (*volCapture);
++ if ( !enumList.isEmpty() ) mdNew->addEnums(enumList);
++
++ shared_ptr<MixDevice> md = mdNew->addToPool();
+ m_mixDevices.append( md );
+
+ qDeleteAll(enumList); // clear temporary list
+@@ -274,7 +277,6 @@
+ int Mixer_ALSA::openAlsaDevice(const QString& devName)
+ {
+ int err;
+- snd_ctl_t *ctl_handle;
+
+ QString probeMessage;
+ probeMessage += "Trying ALSA Device '" + devName + "': ";
+@@ -482,6 +484,13 @@
+ {
+ int ret=0;
+ m_isOpen = false;
++
++ if ( ctl_handle != 0)
++ {
++ //snd_ctl_close( ctl_handle );
++ ctl_handle = 0;
++ }
++
+ if ( _handle != 0 )
+ {
+ //kDebug() << "IN Mixer_ALSA::close()";
+@@ -696,7 +705,7 @@
+
+
+ int
+-Mixer_ALSA::readVolumeFromHW( const QString& id, MixDevice *md )
++Mixer_ALSA::readVolumeFromHW( const QString& id, shared_ptr<MixDevice> md )
+ {
+ Volume& volumePlayback = md->playbackVolume();
+ Volume& volumeCapture = md->captureVolume();
+@@ -776,9 +785,8 @@
+ // Refresh the capture switch information of *all* controls of this card.
+ // Doing it for all is necessary, because enabling one record source often
+ // automatically disables another record source (due to the hardware design)
+- for(int i=0; i< m_mixDevices.count() ; i++ )
++ foreach ( shared_ptr<MixDevice> md, m_mixDevices )
+ {
+- MixDevice *md = m_mixDevices[i];
+ bool isRecsrc = isRecsrcHW( md->id() );
+ // kDebug() << "Mixer::setRecordSource(): isRecsrcHW(" << md->id() << ") =" << isRecsrc;
+ md->setRecSource( isRecsrc );
+@@ -790,7 +798,7 @@
+ }
+
+ int
+-Mixer_ALSA::writeVolumeToHW( const QString& id, MixDevice *md )
++Mixer_ALSA::writeVolumeToHW( const QString& id, shared_ptr<MixDevice> md )
+ {
+ Volume& volumePlayback = md->playbackVolume();
+ Volume& volumeCapture = md->captureVolume();
+Index: backends/mixer_oss.h
+===================================================================
+--- backends/mixer_oss.h (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ backends/mixer_oss.h (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -33,8 +33,8 @@
+ virtual ~Mixer_OSS();
+
+ virtual QString errorText(int mixer_error);
+- virtual int readVolumeFromHW( const QString& id, MixDevice *md );
+- virtual int writeVolumeToHW ( const QString& id, MixDevice *md );
++ virtual int readVolumeFromHW( const QString& id, shared_ptr<MixDevice> );
++ virtual int writeVolumeToHW ( const QString& id, shared_ptr<MixDevice> );
+
+ virtual QString getDriverName();
+
+Index: backends/mixer_sun.h
+===================================================================
+--- backends/mixer_sun.h (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ backends/mixer_sun.h (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -34,8 +34,8 @@
+ virtual ~Mixer_SUN();
+
+ virtual QString errorText(int mixer_error);
+- virtual int readVolumeFromHW( const QString& id, MixDevice *md );
+- virtual int writeVolumeToHW ( const QString& id, MixDevice *md );
++ virtual int readVolumeFromHW( const QString& id, shared_ptr<MixDevice> );
++ virtual int writeVolumeToHW ( const QString& id, shared_ptr<MixDevice> );
+
+ virtual QString getDriverName();
+
+Index: backends/kmix-backends.cpp
+===================================================================
+--- backends/kmix-backends.cpp (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ backends/kmix-backends.cpp (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -46,13 +46,7 @@
+ #endif
+
+ #if defined(hpux)
+-# if defined(HAVE_ALIB_H)
+-# define HPUX_MIXER
+-# else
+-#ifdef __GNUC__
+-# warning ** YOU NEED to have libAlib installed to use the HP-UX-Mixer **
+-#endif
+-# endif // HAVE_ALIB_H
++#error "The HP/UX port is not maintained anymore, an no official part of KMix / KDE at this point of time! Please contact the current KMix maintainer if you would like to maintain the port."
+ #endif // hpux
+
+ // PORTING: add #ifdef PLATFORM , commands , #endif, add your new mixer below
+@@ -82,14 +76,7 @@
+ #include "backends/mixer_oss4.cpp"
+ #endif
+
+-#if defined(HPUX_MIXER)
+-#include "backends/mixer_hpux.cpp"
+-#endif
+
+-
+-
+-
+-
+ typedef Mixer_Backend *getMixerFunc( Mixer* mixer, int device );
+ typedef QString getDriverNameFunc( );
+
+@@ -137,10 +124,6 @@
+ // Possibly encapsualte by #ifdef HAVE_DBUS
+ { MPRIS2_getMixer, MPRIS2_getDriverName },
+
+-#if defined(HPUX_MIXER)
+- { HPUX_getMixer, HPUX_getDriverName },
+-#endif
+-
+ { 0, 0 }
+ };
+
+Index: backends/mixer_mpris2.cpp
+===================================================================
+--- backends/mixer_mpris2.cpp (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ backends/mixer_mpris2.cpp (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -22,26 +22,21 @@
+ #include "mixer_mpris2.h"
+ #include "core/mixer.h"
+
+-//#include <QtCore/QCoreApplication>
+ #include <QDebug>
+ #include <QStringList>
+ #include <QDBusReply>
+-
+-
+ #include <QString>
+
++#include <KLocale>
++
+ // Set the QDBUS_DEBUG env variable for debugging Qt DBUS calls.
+
+ Mixer_Backend* MPRIS2_getMixer(Mixer *mixer, int device )
+ {
+-
+- Mixer_Backend *l_mixer;
+-
+- l_mixer = new Mixer_MPRIS2(mixer, device );
+- return l_mixer;
++ return new Mixer_MPRIS2(mixer, device );
+ }
+
+-Mixer_MPRIS2::Mixer_MPRIS2(Mixer *mixer, int device) : Mixer_Backend(mixer, device )
++Mixer_MPRIS2::Mixer_MPRIS2(Mixer *mixer, int device) : Mixer_Backend(mixer, device )
+ {
+ }
+
+@@ -51,6 +46,7 @@
+ if ( m_devnum != 0 )
+ return Mixer::ERR_OPEN;
+
++ m_mixerName = i18n("Playback Streams");
+ _mixer->setDynamic();
+ addAllRunningPlayersAndInitHotplug();
+ return 0;
+@@ -58,7 +54,9 @@
+
+ int Mixer_MPRIS2::close()
+ {
+- return 0;
++ m_isOpen = false;
++ m_mixDevices.clear();
++ return 0;
+ }
+
+ int Mixer_MPRIS2::mediaPlay(QString id)
+@@ -98,7 +96,7 @@
+ }
+
+
+-int Mixer_MPRIS2::readVolumeFromHW( const QString& id, MixDevice * md)
++int Mixer_MPRIS2::readVolumeFromHW( const QString& id, shared_ptr<MixDevice> md)
+ {
+
+ int volInt = 0;
+@@ -134,7 +132,7 @@
+ return 0;
+ }
+
+-int Mixer_MPRIS2::writeVolumeToHW( const QString& id, MixDevice *md )
++int Mixer_MPRIS2::writeVolumeToHW( const QString& id, shared_ptr<MixDevice> md )
+ {
+
+ qDebug() << "Shall send updated volume to MPRIS Player for " << id;
+@@ -276,18 +274,19 @@
+ ct = MixDevice::APPLICATION_XMM2;
+ }
+
+- MixDevice* md = new MixDevice(_mixer, id, readableName, ct);
++ MixDevice* mdNew = new MixDevice(_mixer, id, readableName, ct);
+ // MPRIS2 doesn't support an actual mute switch. Mute is defined as volume = 0.0
+ // Thus we won't add the playback switch
+ Volume* vol = new Volume( 100, 0, false, false);
+ vol->addVolumeChannel(VolumeChannel(Volume::LEFT)); // MPRIS is only one control ("Mono")
+- md->addMediaPlayControl();
+- md->addMediaNextControl();
+- md->addMediaPrevControl();
+- md->setApplicationStream(true);
+- md->addPlaybackVolume(*vol);
+- m_mixDevices.append( md );
++ mdNew->addMediaPlayControl();
++ mdNew->addMediaNextControl();
++ mdNew->addMediaPrevControl();
++ mdNew->setApplicationStream(true);
++ mdNew->addPlaybackVolume(*vol);
+
++ m_mixDevices.append( mdNew->addToPool() );
++
+ // conn.connect("", QString("/org/mpris/MediaPlayer2"), "org.freedesktop.DBus.Properties", "PropertiesChanged", mad, SLOT(volumeChangedIncoming(QString,QList<QVariant>)) );
+ conn.connect(busDestination, QString("/org/mpris/MediaPlayer2"), "org.freedesktop.DBus.Properties", "PropertiesChanged", mad, SLOT(volumeChangedIncoming(QString,QVariantMap,QStringList)) );
+ connect(mad, SIGNAL(volumeChanged(MPrisAppdata*,double)), this, SLOT(volumeChanged(MPrisAppdata*,double)) );
+@@ -353,12 +352,12 @@
+ /**
+ * This slot is a simple proxy that enriches the DBUS signal with our data, which especially contains the id of the MixDevice.
+ */
+-void MPrisAppdata::volumeChangedIncoming(QString ifc,QVariantMap msg ,QStringList sl)
++void MPrisAppdata::volumeChangedIncoming(QString /*ifc*/,QVariantMap msg ,QStringList /*sl*/)
+ {
+ QMap<QString, QVariant>::iterator v = msg.find("Volume");
+ if (v != msg.end() )
+ {
+- kDebug(67100) << "volumeChanged incoming: !!!!!!!!!" ;
++// kDebug(67100) << "volumeChanged incoming: !!!!!!!!!" ;
+ double volDouble = v.value().toDouble();
+ emit volumeChanged( this, volDouble);
+ }
+@@ -378,7 +377,7 @@
+ {
+ int volInt = newVolume *100;
+ kDebug(67100) << "volumeChanged: " << mad->id << ": " << volInt;
+- MixDevice * md = m_mixDevices.get(mad->id);
++ shared_ptr<MixDevice> md = m_mixDevices.get(mad->id);
+ Volume& vol = md->playbackVolume();
+ vol.setVolume( Volume::LEFT, volInt);
+ md->setMuted(volInt == 0);
+Index: backends/mixer_mpris2.h
+===================================================================
+--- backends/mixer_mpris2.h (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ backends/mixer_mpris2.h (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -54,15 +54,15 @@
+ {
+ Q_OBJECT
+ public:
+- explicit Mixer_MPRIS2(Mixer *mixer, int device = -1 );
++ Mixer_MPRIS2(Mixer *mixer, int device);
+ virtual ~Mixer_MPRIS2();
+ void addMprisControl(QDBusConnection& conn, QString arg1);
+ QString getDriverName();
+
+ virtual int open();
+ virtual int close();
+- virtual int readVolumeFromHW( const QString& id, MixDevice * );
+- virtual int writeVolumeToHW( const QString& id, MixDevice * );
++ virtual int readVolumeFromHW( const QString& id, shared_ptr<MixDevice> );
++ virtual int writeVolumeToHW( const QString& id, shared_ptr<MixDevice> );
+ virtual void setEnumIdHW(const QString& id, unsigned int);
+ virtual unsigned int enumIdHW(const QString& id);
+ virtual bool moveStream( const QString& id, const QString& destId );
+Index: backends/mixer_alsa.h
+===================================================================
+--- backends/mixer_alsa.h (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ backends/mixer_alsa.h (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -42,8 +42,8 @@
+ explicit Mixer_ALSA(Mixer *mixer, int device = -1 );
+ ~Mixer_ALSA();
+
+- virtual int readVolumeFromHW( const QString& id, MixDevice *md );
+- virtual int writeVolumeToHW ( const QString& id, MixDevice *md );
++ virtual int readVolumeFromHW( const QString& id, shared_ptr<MixDevice> md );
++ virtual int writeVolumeToHW ( const QString& id, shared_ptr<MixDevice> md );
+ virtual void setEnumIdHW( const QString& id, unsigned int);
+ virtual unsigned int enumIdHW(const QString& id);
+ virtual bool prepareUpdateFromHW();
+@@ -78,6 +78,8 @@
+
+ bool _initialUpdate;
+ snd_mixer_t *_handle;
++ snd_ctl_t *ctl_handle;
++
+ QString devName;
+ struct pollfd *m_fds;
+ QList<QSocketNotifier*> m_sns;
+Index: backends/mixer_backend.cpp
+===================================================================
+--- backends/mixer_backend.cpp (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ backends/mixer_backend.cpp (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -18,9 +18,10 @@
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
++#include "mixer_backend.h"
++
+ #include <klocale.h>
+
+-#include "mixer_backend.h"
+ // for the "ERR_" declartions, #include mixer.h
+ #include "core/mixer.h"
+ #include <QTimer>
+@@ -32,19 +33,21 @@
+ #include "mixer_backend_i18n.cpp"
+
+ Mixer_Backend::Mixer_Backend(Mixer *mixer, int device) :
+-m_devnum (device) , m_isOpen(false), m_recommendedMaster(0), _mixer(mixer), _pollingTimer(0)
++m_devnum (device) , m_isOpen(false), m_recommendedMaster(), _mixer(mixer), _pollingTimer(0)
+
+ {
+ // In all cases create a QTimer. We will use it once as a singleShot(), even if something smart
+ // like ::select() is possible (as in ALSA).
+ _pollingTimer = new QTimer(); // will be started on open() and stopped on close()
+ connect( _pollingTimer, SIGNAL(timeout()), this, SLOT(readSetFromHW()), Qt::QueuedConnection);
++
+ }
+
+ Mixer_Backend::~Mixer_Backend()
+ {
++ qDebug() << "Running Mixer_Backend destructor";
+ delete _pollingTimer;
+- qDeleteAll(m_mixDevices);
++ //qDeleteAll(m_mixDevices); // TODO cesken Leak check the removed qDeleteAll()
+ m_mixDevices.clear();
+ }
+
+@@ -117,10 +120,8 @@
+
+ int ret = Mixer::OK_UNCHANGED;
+
+- int mdCount = m_mixDevices.count();
+- for(int i=0; i<mdCount ; ++i )
++ foreach (shared_ptr<MixDevice> md, m_mixDevices )
+ {
+- MixDevice *md = m_mixDevices[i];
+ int retLoop = readVolumeFromHW( md->id(), md );
+ if (md->isEnum() ) {
+ /*
+@@ -160,6 +161,7 @@
+ // This code path is entered on Mixer::OK_UNCHANGED and ERROR
+ if ( !_fastPollingEndsAt.isNull() )
+ {
++ // Fast polling is currently active
+ if( _fastPollingEndsAt < QTime::currentTime () )
+ {
+ kDebug() << "End fast polling";
+@@ -176,20 +178,29 @@
+ * first device in the device list. Backends can override this (i.e. the ALSA Backend does so).
+ * The users preference is NOT returned by this method - see the Mixer class for that.
+ */
+-MixDevice* Mixer_Backend::recommendedMaster() {
+- if ( m_recommendedMaster != 0 ) {
+- return m_recommendedMaster; // Backend has set a recommended master. Thats fine.
+- } // recommendation from Backend
+- else if ( m_mixDevices.count() > 0 ) {
+- return m_mixDevices.at(0); // Backend has NOT set a recommended master. Evil backend => lets help out.
+- } //first device (if exists)
+- else {
+- if ( !_mixer->isDynamic()) {
+- // This should never ever happen, as KMix doe NOT accept soundcards without controls
++shared_ptr<MixDevice> Mixer_Backend::recommendedMaster()
++{
++ if ( m_recommendedMaster != 0 )
++ {
++ // Backend has set a recommended master. Thats fine. Using it.
++ return m_recommendedMaster;
++ }
++ else if ( ! m_mixDevices.isEmpty() )
++ {
++ // Backend has NOT set a recommended master. Evil backend
++ // => lets help out, using the first device (if exists)
++ return m_mixDevices.at(0);
++ }
++ else
++ {
++ if ( !_mixer->isDynamic())
++ // This should never ever happen, as KMix does NOT accept soundcards without controls
+ kError(67100) << "Mixer_Backend::recommendedMaster(): returning invalid master. This is a bug in KMix. Please file a bug report stating how you produced this." << endl;
+- }
+- return (MixDevice*)0;
+ }
++
++ // If we reach this code path, then obiously m_recommendedMaster == 0 (see above)
++ return m_recommendedMaster;
++
+ }
+
+ /**
+Index: backends/mixer_oss4.cpp
+===================================================================
+--- backends/mixer_oss4.cpp (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ backends/mixer_oss4.cpp (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -21,6 +21,9 @@
+
+ //OSS4 mixer backend for KMix by Yoper Team released under GPL v2 or later
+
++/* We're getting soundcard.h via mixer_oss4.h */
++#include "mixer_oss4.h"
++
+ #include <fcntl.h>
+ #include <errno.h>
+ #include <unistd.h>
+@@ -28,8 +31,6 @@
+ #include <sys/types.h>
+ #include <sys/stat.h>
+
+-/* We're getting soundcard.h via mixer_oss4.h */
+-#include "mixer_oss4.h"
+ #include <klocale.h>
+ #include <QLinkedList>
+ #include <QRegExp>
+@@ -53,7 +54,7 @@
+ bool Mixer_OSS4::CheckCapture(oss_mixext *ext)
+ {
+ QString name = ext->extname;
+- if ( ext->flags & MIXF_RECVOL || name.split(".").contains("in") )
++ if ( ext->flags & MIXF_RECVOL || name.split('.').contains("in") )
+ {
+ return true;
+ }
+@@ -214,7 +215,7 @@
+ bool masterChosen = false;
+ bool masterHeuristicAvailable = false;
+ bool saveAsMasterHeuristc = false;
+- MixDevice *masterHeuristic = NULL;
++ shared_ptr<MixDevice> masterHeuristic;
+
+ oss_mixext ext;
+ ext.dev = m_devnum;
+@@ -360,7 +361,7 @@
+ masterChosen = true;
+ }
+
+- m_mixDevices.append(md);
++ m_mixDevices.append(md->addToPool());
+ }
+ else if ( ext.type == MIXT_HEXVALUE )
+ {
+@@ -388,7 +389,7 @@
+ masterChosen = true;
+ }
+
+- m_mixDevices.append(md);
++ m_mixDevices.append(md->addToPool());
+ }
+ else if ( ext.type == MIXT_ONOFF
+ #ifdef MIXT_MUTE
+@@ -418,7 +419,7 @@
+ md->addPlaybackVolume(vol);
+ }
+
+- m_mixDevices.append(md);
++ m_mixDevices.append(md->addToPool());
+ }
+ else if ( ext.type == MIXT_ENUM )
+ {
+@@ -452,7 +453,7 @@
+ }
+ md->addEnums(enumValuesRef);
+
+- m_mixDevices.append(md);
++ m_mixDevices.append(md->addToPool());
+ }
+ }
+
+@@ -526,7 +527,7 @@
+ return true;
+ }
+
+-int Mixer_OSS4::readVolumeFromHW(const QString& id, MixDevice *md)
++int Mixer_OSS4::readVolumeFromHW(const QString& id, shared_ptr<MixDevice> md)
+ {
+ oss_mixext extinfo;
+ oss_mixer_value mv;
+@@ -592,7 +593,7 @@
+ return 0;
+ }
+
+-int Mixer_OSS4::writeVolumeToHW(const QString& id, MixDevice *md)
++int Mixer_OSS4::writeVolumeToHW(const QString& id, shared_ptr<MixDevice> md)
+ {
+ int volume = 0;
+
+Index: backends/mixer_pulse.cpp
+===================================================================
+--- backends/mixer_pulse.cpp (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ backends/mixer_pulse.cpp (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -19,17 +19,21 @@
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
++#include "mixer_pulse.h"
++
+ #include <cstdlib>
+ #include <QtCore/QAbstractEventDispatcher>
+ #include <QTimer>
+
+ #include <klocale.h>
+
+-#include "mixer_pulse.h"
+ #include "core/mixer.h"
+
+ #include <pulse/glib-mainloop.h>
+ #include <pulse/ext-stream-restore.h>
++#if defined(HAVE_CANBERRA)
++# include <canberra.h>
++#endif
+
+ #define HAVE_SOURCE_OUTPUT_VOLUMES PA_CHECK_VERSION(1,0,0)
+
+@@ -47,6 +51,10 @@
+ static enum { UNKNOWN, ACTIVE, INACTIVE } s_pulseActive = UNKNOWN;
+ static int s_outstandingRequests = 0;
+
++#if defined(HAVE_CANBERRA)
++static ca_context *s_ccontext = NULL;
++#endif
++
+ QMap<int,Mixer_PULSE*> s_mixers;
+
+ typedef QMap<int,devinfo> devmap;
+@@ -129,11 +137,11 @@
+ dev.chanMask = (Volume::ChannelMask)( dev.chanMask | Volume::MWOOFER);
+ dev.chanIDs[i] = Volume::WOOFER;
+ break;
+- case PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER:
++ case PA_CHANNEL_POSITION_SIDE_LEFT:
+ dev.chanMask = (Volume::ChannelMask)( dev.chanMask | Volume::MREARSIDELEFT);
+ dev.chanIDs[i] = Volume::REARSIDELEFT;
+ break;
+- case PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER:
++ case PA_CHANNEL_POSITION_SIDE_RIGHT:
+ dev.chanMask = (Volume::ChannelMask)( dev.chanMask | Volume::MREARSIDERIGHT);
+ dev.chanIDs[i] = Volume::REARSIDERIGHT;
+ break;
+@@ -751,6 +759,18 @@
+ return get_widget_map(type);
+ }
+
++void Mixer_PULSE::emitControlsReconfigured()
++{
++ // Do not emit directly to ensure all connected slots are executed
++ // in their own event loop.
++ kDebug() << "PULSE emitControlsReconfigured: mixerId=" << _mixer->id();
++// emit controlsReconfigured(_mixer->id());
++ QMetaObject::invokeMethod(this,
++ "controlsReconfigured",
++ Qt::QueuedConnection,
++ Q_ARG(QString, _mixer->id()));
++}
++
+ void Mixer_PULSE::addWidget(int index)
+ {
+ devmap* map = get_widget_map(m_devnum, index);
+@@ -760,12 +780,7 @@
+ return;
+ }
+ addDevice((*map)[index]);
+- // Do not emit directly to ensure all connected slots are executed
+- // in their own event loop.
+- QMetaObject::invokeMethod(this,
+- "controlsReconfigured",
+- Qt::QueuedConnection,
+- Q_ARG(QString, _mixer->id()));
++ emitControlsReconfigured();
+ }
+
+ void Mixer_PULSE::removeWidget(int index)
+@@ -787,14 +802,9 @@
+ {
+ if ((*iter)->id() == id)
+ {
+- delete *iter;
++// delete *iter; // TODO cesken LET-THIS-CHECK Delete should not be required after migration to shared_ptr
+ m_mixDevices.erase(iter);
+- // Do not emit directly to ensure all connected slots are executed
+- // in their own event loop.
+- QMetaObject::invokeMethod(this,
+- "controlsReconfigured",
+- Qt::QueuedConnection,
+- Q_ARG(QString, _mixer->id()));
++ emitControlsReconfigured();
+ return;
+ }
+ }
+@@ -809,18 +819,16 @@
+ if (KMIXPA_APP_PLAYBACK == m_devnum)
+ outputRoles.clear();
+
+- MixSet::iterator iter;
+- for (iter = m_mixDevices.begin(); iter != m_mixDevices.end(); ++iter)
+- {
+- delete *iter;
+- m_mixDevices.erase(iter);
+- }
+- // Do not emit directly to ensure all connected slots are executed
+- // in their own event loop.
+- QMetaObject::invokeMethod(this,
+- "controlsReconfigured",
+- Qt::QueuedConnection,
+- Q_ARG(QString, _mixer->id()));
++ m_mixDevices.clear();
++
++ // TODO cesken LET-THIS-CHECK Delete should not be required after migration to shared_ptr
++// MixSet::iterator iter;
++// for (iter = m_mixDevices.begin(); iter != m_mixDevices.end(); ++iter)
++// {
++// delete *iter;
++// m_mixDevices.erase(iter);
++// }
++ emitControlsReconfigured();
+ }
+
+ void Mixer_PULSE::addDevice(devinfo& dev, bool isAppStream)
+@@ -841,7 +849,7 @@
+
+ md->addPlaybackVolume(v);
+ md->setMuted(dev.mute);
+- m_mixDevices.append(md);
++ m_mixDevices.append(md->addToPool());
+ }
+ }
+
+@@ -944,6 +952,15 @@
+ Q_ASSERT(s_mainloop);
+
+ connectToDaemon();
++
++#if defined(HAVE_CANBERRA)
++ int ret = ca_context_create(&s_ccontext);
++ if (ret < 0) {
++ kDebug(67100) << "Disabling Sound Feedback. Canberra context failed.";
++ s_ccontext = NULL;
++ } else
++ ca_context_set_driver(s_ccontext, "pulse");
++#endif
+ }
+
+ kDebug(67100) << "PulseAudio status: " << (s_pulseActive==UNKNOWN ? "Unknown (bug)" : (s_pulseActive==ACTIVE ? "Active" : "Inactive"));
+@@ -962,6 +979,13 @@
+ --refcount;
+ if (0 == refcount)
+ {
++#if defined(HAVE_CANBERRA)
++ if (s_ccontext) {
++ ca_context_destroy(s_ccontext);
++ s_ccontext = NULL;
++ }
++#endif
++
+ if (s_context) {
+ pa_context_unref(s_context);
+ s_context = NULL;
+@@ -1039,7 +1063,7 @@
+ return num;
+ }
+
+-int Mixer_PULSE::readVolumeFromHW( const QString& id, MixDevice *md )
++int Mixer_PULSE::readVolumeFromHW( const QString& id, shared_ptr<MixDevice> md )
+ {
+ devmap *map = get_widget_map(m_devnum, id);
+
+@@ -1057,7 +1081,7 @@
+ return 0;
+ }
+
+-int Mixer_PULSE::writeVolumeToHW( const QString& id, MixDevice *md )
++int Mixer_PULSE::writeVolumeToHW( const QString& id, shared_ptr<MixDevice> md )
+ {
+ devmap::iterator iter;
+ if (KMIXPA_PLAYBACK == m_devnum)
+@@ -1081,6 +1105,44 @@
+ }
+ pa_operation_unref(o);
+
++#if defined(HAVE_CANBERRA)
++ if (s_ccontext) {
++ int playing = 0;
++ int cindex = 2; // Note "2" is simply the index we've picked. It's somewhat irrelevant.
++
++
++ ca_context_playing(s_ccontext, cindex, &playing);
++
++ // NB Depending on how this is desired to work, we may want to simply
++ // skip playing, or cancel the currently playing sound and play our
++ // new one... for now, let's do the latter.
++ if (playing) {
++ ca_context_cancel(s_ccontext, cindex);
++ playing = 0;
++ }
++
++ if (!playing) {
++ char dev[64];
++
++ snprintf(dev, sizeof(dev), "%lu", (unsigned long) iter->index);
++ ca_context_change_device(s_ccontext, dev);
++
++ // Ideally we'd use something like ca_gtk_play_for_widget()...
++ ca_context_play(
++ s_ccontext,
++ cindex,
++ CA_PROP_EVENT_DESCRIPTION, i18n("Volume Control Feedback Sound").toUtf8().constData(),
++ CA_PROP_EVENT_ID, "audio-volume-change",
++ CA_PROP_CANBERRA_CACHE_CONTROL, "permanent",
++ CA_PROP_CANBERRA_ENABLE, "1",
++ NULL
++ );
++
++ ca_context_change_device(s_ccontext, NULL);
++ }
++ }
++#endif
++
+ return 0;
+ }
+ }
+@@ -1152,7 +1214,7 @@
+ info.mute = (md->isMuted() ? 1 : 0);
+
+ pa_operation* o;
+- if (!(o = pa_ext_stream_restore_write(s_context, PA_UPDATE_REPLACE, &info, 1, TRUE, NULL, NULL))) {
++ if (!(o = pa_ext_stream_restore_write(s_context, PA_UPDATE_REPLACE, &info, 1, true, NULL, NULL))) {
+ kWarning(67100) << "pa_ext_stream_restore_write() failed" << info.channel_map.channels << info.volume.channels << info.name;
+ return Mixer::ERR_READ;
+ }
+@@ -1248,7 +1310,7 @@
+ info.mute = rule.mute ? 1 : 0;
+
+ pa_operation* o;
+- if (!(o = pa_ext_stream_restore_write(s_context, PA_UPDATE_REPLACE, &info, 1, TRUE, NULL, NULL))) {
++ if (!(o = pa_ext_stream_restore_write(s_context, PA_UPDATE_REPLACE, &info, 1, true, NULL, NULL))) {
+ kWarning(67100) << "pa_ext_stream_restore_write() failed" << info.channel_map.channels << info.volume.channels << info.name;
+ return Mixer::ERR_READ;
+ }
+Index: CMakeLists.txt
+===================================================================
+--- CMakeLists.txt (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ CMakeLists.txt (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -1,5 +1,17 @@
+ project(kmix)
+
++find_package(KDE4 REQUIRED)
++include(KDE4Defaults)
++include(MacroLibrary)
++
++find_package(Alsa)
++
++macro_optional_find_package(PulseAudio "0.9.12")
++macro_log_feature(PULSEAUDIO_FOUND "PulseAudio" "PulseAudio Audio Server" "http://www.pulseaudio.org/" FALSE "0.9.12" "libpulse is needed to let KMix control PulseAudio")
++find_package(GLIB2)
++pkg_check_modules(CANBERRA libcanberra)
++macro_log_feature(CANBERRA_FOUND "libcanberra" "libcanberra audio library" "http://0pointer.de/lennart/projects/libcanberra/" FALSE "" "libcanberra is needed for kmix sound feedback")
++
+ alsa_configure_file(${CMAKE_BINARY_DIR}/config-alsa.h)
+
+
+@@ -21,6 +33,19 @@
+ add_subdirectory( profiles )
+ #add_subdirectory( tests )
+
++if (PULSEAUDIO_FOUND)
++ add_definitions(-DHAVE_PULSE)
++
++ include_directories(${PULSEAUDIO_INCLUDE_DIR})
++endif (PULSEAUDIO_FOUND)
++
++if (CANBERRA_FOUND)
++ add_definitions(-DHAVE_CANBERRA)
++
++ include_directories(${CANBERRA_INCLUDE_DIRS})
++endif (CANBERRA_FOUND)
++
++
+ set(kmix_adaptor_SRCS
+ dbus/dbusmixerwrapper.cpp
+ dbus/dbusmixsetwrapper.cpp
+@@ -42,10 +67,10 @@
+ backends/mixer_alsa9.cpp )
+ endif (HAVE_LIBASOUND2)
+
+-if (HAVE_PULSE)
++if (PULSEAUDIO_FOUND)
+ set(kmix_backend_SRCS ${kmix_backend_SRCS}
+ backends/mixer_pulse.cpp )
+-endif (HAVE_PULSE)
++endif (PULSEAUDIO_FOUND)
+
+ set(kmix_KDEINIT_SRCS ${kmix_adaptor_SRCS} ${kmix_backend_SRCS}
+ apps/main.cpp
+@@ -72,6 +97,7 @@
+ gui/osdwidget.cpp
+ core/mixertoolbox.cpp
+ core/kmixdevicemanager.cpp
++ core/ControlPool.cpp
+ core/MasterControl.cpp
+ core/mixer.cpp
+ core/mixset.cpp
+@@ -89,10 +115,13 @@
+ target_link_libraries(kdeinit_kmix ${ASOUND_LIBRARY})
+ endif (HAVE_LIBASOUND2)
+
+-if (HAVE_PULSE)
++if (PULSEAUDIO_FOUND)
+ target_link_libraries(kdeinit_kmix ${PULSEAUDIO_LIBRARY} ${PULSEAUDIO_MAINLOOP_LIBRARY} ${GLIB2_LIBRARIES})
+-endif (HAVE_PULSE)
++endif (PULSEAUDIO_FOUND)
+
++if (CANBERRA_FOUND)
++ target_link_libraries(kdeinit_kmix ${CANBERRA_LIBRARIES})
++endif (CANBERRA_FOUND)
+
+ install(TARGETS kdeinit_kmix DESTINATION ${LIB_INSTALL_DIR} )
+
+@@ -103,6 +132,7 @@
+
+ set(kded_kmixd_SRCS ${kmix_adaptor_SRCS} ${kmix_backend_SRCS}
+ apps/kmixd.cpp
++ core/ControlPool.cpp
+ core/MasterControl.cpp
+ core/mixer.cpp
+ core/mixset.cpp
+@@ -125,10 +155,14 @@
+ target_link_libraries(kded_kmixd ${ASOUND_LIBRARY})
+ endif (HAVE_LIBASOUND2)
+
+-if (HAVE_PULSE)
++if (PULSEAUDIO_FOUND)
+ target_link_libraries(kded_kmixd ${PULSEAUDIO_LIBRARY} ${PULSEAUDIO_MAINLOOP_LIBRARY} ${GLIB2_LIBRARIES})
+-endif (HAVE_PULSE)
++endif (PULSEAUDIO_FOUND)
+
++if (CANBERRA_FOUND)
++ target_link_libraries(kded_kmixd ${CANBERRA_LIBRARIES})
++endif (CANBERRA_FOUND)
++
+ install(TARGETS kded_kmixd DESTINATION ${PLUGIN_INSTALL_DIR})
+
+ #target_link_libraries( kmixd kded_kmixd )
+@@ -140,6 +174,7 @@
+
+ set(kmixctrl_KDEINIT_SRCS ${kmix_adaptor_SRCS} ${kmix_backend_SRCS}
+ apps/kmixctrl.cpp
++ core/ControlPool.cpp
+ core/MasterControl.cpp
+ core/mixer.cpp
+ core/mixset.cpp
+@@ -160,10 +195,14 @@
+ target_link_libraries(kdeinit_kmixctrl ${ASOUND_LIBRARY})
+ endif (HAVE_LIBASOUND2)
+
+-if (HAVE_PULSE)
++if (PULSEAUDIO_FOUND)
+ target_link_libraries(kdeinit_kmixctrl ${PULSEAUDIO_LIBRARY} ${PULSEAUDIO_MAINLOOP_LIBRARY} ${GLIB2_LIBRARIES})
+-endif (HAVE_PULSE)
++endif (PULSEAUDIO_FOUND)
+
++if (CANBERRA_FOUND)
++ target_link_libraries(kdeinit_kmixctrl ${CANBERRA_LIBRARIES})
++endif (CANBERRA_FOUND)
++
+ ########### next target ###############
+ add_subdirectory( plasma )
+
+Index: plasma/engine/mixerengine.h
+===================================================================
+--- plasma/engine/mixerengine.h (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ plasma/engine/mixerengine.h (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -80,13 +80,14 @@
+ // Keys are mixerIds for control
+ QMultiHash<QString,ControlInfo*> m_controls;
+
+- MixerInfo* createMixerInfo( QString dbusPath );
+- ControlInfo* createControlInfo( QString mixerId, QString dbusPath );
++ MixerInfo* createMixerInfo( const QString& dbusPath );
++ ControlInfo* createControlInfo( const QString& mixerId, const QString& dbusPath );
+
+ void clearInternalData(bool removeSources);
+ bool getMixersData();
+- bool getMixerData( const QString &source );
+- bool getControlData( const QString &source );
++ bool getMixerData( const QString& source );
++ bool getControlData( const QString& source );
++ void setControlData( ControlInfo *ci );
+ private slots:
+ void getInternalData();
+ void updateInternalMixersData();
+Index: plasma/engine/mixer.operations
+===================================================================
+--- plasma/engine/mixer.operations (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ plasma/engine/mixer.operations (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -1,15 +1,20 @@
+ <?xml version="1.0" encoding="UTF-8"?>
+ <!DOCTYPE kcfg SYSTEM
+- "http://www.kde.org/standards/kcfg/1.0/kcfg.xsd">
++ "http://www.kde.org/standards/kcfg/1.0/kcfg.xsd">
+ <kcfg>
+ <group name="setVolume">
+ <entry name="level" type="Int">
+ <label>The volume level between 0 and 100</label>
+- </entry>
++ </entry>
+ </group>
+ <group name="setMute">
+ <entry name="muted" type="Bool">
+- <label>Mute</label>
+- </entry>
++ <label>Mute</label>
++ </entry>
+ </group>
++ <group name="setRecordSource">
++ <entry name="recordSource" type="Bool">
++ <label>Record Source</label>
++ </entry>
++ </group>
+ </kcfg>
+Index: plasma/engine/mixerservice.cpp
+===================================================================
+--- plasma/engine/mixerservice.cpp (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ plasma/engine/mixerservice.cpp (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -60,7 +60,11 @@
+ setResult( res );
+ return;
+ }
+-
++ else if ( operation == "setRecordSource" ) {
++ bool res = m_service->iface()->setProperty( "recordSource", parameters().value("recordSource").toBool() );
++ setResult( res );
++ return;
++ }
+ }
+
+ #include "mixerservice.moc"
+Index: plasma/engine/mixerengine.cpp
+===================================================================
+--- plasma/engine/mixerengine.cpp (.../tags/KDE/4.8.2/kdemultimedia/kmix) (revision 1291338)
++++ plasma/engine/mixerengine.cpp (.../branches/KDE/4.8/kdemultimedia/kmix) (revision 1291338)
+@@ -68,7 +68,7 @@
+ getInternalData();
+ }
+
+-MixerInfo* MixerEngine::createMixerInfo( QString dbusPath )
++MixerInfo* MixerEngine::createMixerInfo( const QString& dbusPath )
+ {
+ MixerInfo* curmi = new MixerInfo;
+ curmi->iface = new OrgKdeKMixMixerInterface( KMIX_DBUS_SERVICE, dbusPath,
+@@ -85,7 +85,7 @@
+ return curmi;
+ }
+
+-ControlInfo* MixerEngine::createControlInfo( QString mixerId, QString dbusPath )
++ControlInfo* MixerEngine::createControlInfo( const QString& mixerId, const QString& dbusPath )
+ {
+ ControlInfo* curci = new ControlInfo;
+ curci->iface = new OrgKdeKMixControlInterface( KMIX_DBUS_SERVICE, dbusPath,
+@@ -112,12 +112,14 @@
+ "org.kde.KMix.MixSet", "changed",
+ this, SLOT(slotMixersChanged()) );
+ }
+- Q_FOREACH( QString path, m_kmix->mixers() )
++ Q_FOREACH( const QString& path, m_kmix->mixers() )
+ {
+ MixerInfo* curmi = createMixerInfo( path );
+- Q_FOREACH( QString controlPath, curmi->iface->controls() )
++ Q_FOREACH( const QString& controlPath, curmi->iface->controls() )
+ createControlInfo( curmi->id, controlPath );
+ }
++ // Update "Mixers" source
++ getMixersData();
+ }
+
+ void MixerEngine::clearInternalData(bool removeSources)
+@@ -133,7 +135,7 @@
+ Q_FOREACH( ControlInfo* ci, m_controls )
+ {
+ if ( removeSources )
+- removeSource( ci->mixerId + "/" + ci->id );
++ removeSource( ci->mixerId + '/' + ci->id );
+ delete ci->iface;
+ delete ci;
+ }
+@@ -162,13 +164,24 @@
+ QStringList mixerIds;
+ if ( interface->isServiceRegistered( KMIX_DBUS_SERVICE ) )
+ {
+- // 'Unused' flag is used for cleanup
+ Q_FOREACH( MixerInfo* mi, m_mixers )
+ mixerIds.append( mi->id );
++ /* FIXME: this is used to know whether kmix isn't running or
++ * it can't find any audio device; also it works as a strange
++ * workaround: without it there is no dataUpdated() call sometimes
++ * when it is updated here */
++ setData( "Mixers", "Running", true );
+ setData( "Mixers", "Mixers", mixerIds );
++ setData( "Mixers", "Current Master Mixer", m_kmix->currentMasterMixer() );
++ setData( "Mixers", "Current Master Control", m_kmix->currentMasterControl() );
+ }
+ else
++ {
++ setData( "Mixers", "Running", false );
+ removeData( "Mixers", "Mixers" );
++ removeData( "Mixers", "Current Master Mixer" );
++ removeData( "Mixers", "Current Master Control" );
++ }
+ return true;
+ }
+
+@@ -234,14 +247,23 @@
+ return false;
+ // Setting data
+ curci->updateRequired = true;
+- setData( source, "Can Be Muted", curci->iface->canMute() );
+- setData( source, "Volume", curci->iface->volume() );
+- setData( source, "Mute", curci->iface->mute() );
+- setData( source, "Readable Name", curci->iface->readableName() );
+- setData( source, "Icon", KIcon(curci->iface->iconName()) );
++ setControlData( curci );
+ return true;
+ }
+
++void MixerEngine::setControlData(ControlInfo* ci)
++{
++ QString source = ci->mixerId + '/' + ci->id;
++ setData( source, "Volume", ci->iface->volume() );
++ setData( source, "Mute", ci->iface->mute() );
++ setData( source, "Can Be Muted", ci->iface->canMute() );
++ setData( source, "Readable Name", ci->iface->readableName() );
++ setData( source, "Icon", KIcon(ci->iface->iconName()) );
++ setData( source, "Record Source", ci->iface->recordSource() );
++ setData( source, "Has Capture Switch", ci->iface->hasCaptureSwitch() );
++}
++
++
+ void MixerEngine::slotServiceRegistered( const QString &serviceName)
+ {
+ // Let's give KMix some time to load
+@@ -253,7 +275,8 @@
+ {
+ if ( serviceName == KMIX_DBUS_SERVICE )
+ clearInternalData(true);
+- removeData( "Mixers", "Mixers" );
++ // Updating 'Mixers' source
++ getMixersData();
+ }
+
+ void MixerEngine::slotControlChanged()
+@@ -265,13 +288,7 @@
+ // Updating all controls that might change
+ Q_FOREACH( ControlInfo* ci, m_controls.values( curmi->id ) )
+ if ( ci->updateRequired )
+- {
+- QString source = ci->mixerId + "/" + ci->id;
+- setData( source, "Can Be Muted", ci->iface->canMute() );
+- setData( source, "Volume", ci->iface->volume() );
+- setData( source, "Mute", ci->iface->mute() );
+- setData( source, "Readable Name", ci->iface->readableName() );
+- }
++ setControlData( ci );
+ }
+
+ void MixerEngine::slotControlsReconfigured()
+@@ -284,9 +301,10 @@
+ QList<ControlInfo*> controlsForMixer = m_controls.values( curmi->id );
+ QStringList controlIds;
+ QStringList controlReadableNames;
++ QStringList controlIconNames;
+ Q_FOREACH( ControlInfo* ci, controlsForMixer )
+ ci->unused = true;
+- Q_FOREACH( QString controlPath, curmi->iface->controls() )
++ Q_FOREACH( const QString& controlPath, curmi->iface->controls() )
+ {
+ ControlInfo* curci = 0;
+ Q_FOREACH( ControlInfo* ci, controlsForMixer )
+@@ -301,6 +319,7 @@
+ curci->unused = false;
+ controlIds.append( curci->id );
+ controlReadableNames.append( curci->iface->readableName() );
++ controlIconNames.append( curci->iface->iconName() );
+ }
+ // If control is unused then we should remove it
+ Q_FOREACH( ControlInfo* ci, controlsForMixer )
+@@ -312,9 +331,9 @@
+ }
+ if ( curmi->updateRequired )
+ {
+- QString source = curmi->id;
+- setData( source, "Controls", controlIds );
+- setData( source, "Controls Readable Names", controlReadableNames );
++ setData( curmi->id, "Controls", controlIds );
++ setData( curmi->id, "Controls Readable Names", controlReadableNames );
++ setData( curmi->id, "Controls Icons Names", controlIconNames );
+ }
+ }
+
+@@ -323,7 +342,7 @@
+ // Some mixer added or removed
+ Q_FOREACH( MixerInfo* mi, m_mixers )
+ mi->unused = true;
+- Q_FOREACH( QString mixerPath, m_kmix->mixers() )
++ Q_FOREACH( const QString& mixerPath, m_kmix->mixers() )
+ {
+ MixerInfo* curmi = m_mixers.value( mixerPath, 0 );
+ // if mixer was added, we need to add one to m_mixers
+@@ -331,7 +350,7 @@
+ if ( !curmi )
+ {
+ curmi = createMixerInfo( mixerPath );
+- Q_FOREACH( QString controlPath, curmi->iface->controls() )
++ Q_FOREACH( const QString& controlPath, curmi->iface->controls() )
+ createControlInfo( curmi->id, controlPath );
+ }
+ curmi->unused = false;
+@@ -344,7 +363,7 @@
+ Q_FOREACH( ControlInfo* ci, m_controls.values( mi->id ) )
+ {
+ m_controls.remove( mi->id, ci );
+- removeSource( ci->mixerId + "/" + ci->id );
++ removeSource( ci->mixerId + '/' + ci->id );
+ delete ci->iface;
+ delete ci;
+ }
diff --git a/kdemultimedia.spec b/kdemultimedia.spec
index 0fad996..4243caf 100644
--- a/kdemultimedia.spec
+++ b/kdemultimedia.spec
@@ -6,7 +6,7 @@
Name: kdemultimedia
Epoch: 6
Version: 4.8.2
-Release: 3%{?dist}
+Release: 4%{?dist}
Summary: KDE Multimedia applications
Group: Applications/Multimedia
@@ -26,6 +26,10 @@ Patch1: kdemultimedia-4.6.2-no_thumbs.patch
## upstream patches
# http://svnweb.mageia.org/packages/cauldron/kdemultimedia4/current/SOURCES/0100-Prevent-kmixctrl-running-with-PulseAudio.patch
Patch100: 0100-Prevent-kmixctrl-running-with-PulseAudio.patch
+# svn diff \
+# svn+ssh://anonsvn.kde.org/home/kde/tags/KDE/4.8.2/kdemultimedia/kmix/ \
+# svn+ssh://anonsvn.kde.org/home/kde/branches/KDE/4.8/kdemultimedia/kmix
+Patch101: kdemultimedia-4.8.2-kmix_backport.patch
BuildRequires: cdparanoia-devel cdparanoia
BuildRequires: kdepimlibs-devel >= %{version}
@@ -142,6 +146,9 @@ Requires: %{name}-kio_audiocd = %{?epoch:%{epoch}:}%{version}-%{release}
%patch1 -p1 -b .no_thumbs
%patch100 -p1 -b .kmixctrl-running-with-PulseAudio
+pushd kmix
+%patch101 -p0 -b .kmix_backport
+popd
%build
@@ -333,6 +340,10 @@ fi
%changelog
+* Tue Apr 24 2012 Rex Dieter <rdieter at fedoraproject.org> 6:4.8.2-4
+- kmix crashes when pulseaudio exits (#804363)
+- kmix is crashing after multiple volume changes (kde#290742)
+
* Fri Apr 13 2012 Rex Dieter <rdieter at fedoraproject.org> 6:4.8.2-3
- -dragonplayer: Provides: dragon
More information about the scm-commits
mailing list