From 081a614cf2f586c07f5978764077699a8f93898f Mon Sep 17 00:00:00 2001 From: Rex Dieter Date: Apr 24 2012 12:35:03 +0000 Subject: kmix crashes when pulseaudio exits (#804363) - kmix is crashing after multiple volume changes (kde#290742) --- 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 , FreeBSD has 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 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 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 md, _mixSet ) + { + // kDebug() << "VVV Add to " << md->mixer()->id(); + // MixDeviceWidget* mdw = qobject_cast(qw); +@@ -321,7 +307,7 @@ + Workaround: If found, write back correct group name. + */ + MixDeviceWidget* mdw = (MixDeviceWidget*)qmdw; +- MixDevice* md = mdw->mixDevice(); ++ shared_ptr 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 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 + #include ++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); + virtual void constructionFinished(); + virtual void configurationUpdate(); + +@@ -52,6 +53,7 @@ + QLayout* _layoutSliders; + QLayout* _layoutEnum; + QHash _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 + #include + #include +@@ -30,7 +32,6 @@ + #include + #include + +-#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 master = mixer->getLocalMasterMD(); ++ if ( master.get() != 0 ) ++ masterKey = master->id(); + + const MixSet& mixset = mixer->getMixSet(); + MixSet& mset = const_cast(mixset); + for( int i=0; i< mset.count(); ++i ) + { +- MixDevice* md = mset[i]; ++ shared_ptr 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 + +-MDWMoveAction::MDWMoveAction(MixDevice* md, QObject *parent) ++MDWMoveAction::MDWMoveAction(shared_ptr 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 + #include +@@ -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 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 +- ++class QWidgetAction; + #include + + 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 + +@@ -33,7 +35,6 @@ + #include + + #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 ++#include "core/mixdevice.h" + #include "core/volume.h" + #include + +@@ -44,7 +45,7 @@ + Q_OBJECT + + public: +- MixDeviceWidget( MixDevice* md, ++ MixDeviceWidget( shared_ptr 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() { 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 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 + #include + #include +@@ -40,20 +42,19 @@ + #include + #include + ++#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 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& 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=" <value(); +- //kDebug(67100) << "firstVolume=" <value()); ++ } ++ else ++ { ++ for( int i=0; ivalue()); + } // 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 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 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 ++#include + + // Qt ++#include + #include + #include + #include +@@ -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 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 mds; // For temporary test ++ QList > 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 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 +@@ -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::const_iterator itEnd = guiprof->tabs().end(); +- for ( QList::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 + #include + #include +@@ -30,7 +32,6 @@ + #include + #include + +-#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 + 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) = 0; + + /** + * Popup stuff +@@ -130,7 +131,7 @@ + + + protected: +- MixSet *_mixSet; ++ MixSet _mixSet; + Mixer *_mixer; + QSet _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 + #include + #include + #include + #include + +-#include +-// For "kapp" + #include ++#include + +-//#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 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 + #include + #include +@@ -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 md = Mixer::getGlobalMasterMD(); ++ if ( md.get() != 0 && md->playbackVolume().hasSwitch() ) ++ { + // Put "Mute" selector in context menu + KToggleAction *action = actionCollection()->add( "dock_mute" ); + action->setText( i18n( "M&ute" ) ); +@@ -212,11 +214,11 @@ + void + KMixDockWidget::setVolumeTip() + { +- MixDevice *md = Mixer::getGlobalMasterMD(); ++ shared_ptr 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 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 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 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 md = Mixer::getGlobalMasterMD(); + KToggleAction *dockMuteAction = static_cast(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 + #include + #include + #include +@@ -33,10 +36,7 @@ + #include + #include + +-#include +- + #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 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 + +-class MixDevice; ++#include "core/mixdevice.h" + + class MDWMoveAction : public KAction + { + Q_OBJECT + + public: +- MDWMoveAction(MixDevice* md, QObject *parent); ++ MDWMoveAction(shared_ptr md, QObject *parent); + ~MDWMoveAction(); + + signals: +@@ -40,7 +40,7 @@ + void triggered(bool checked); + + private: +- MixDevice *m_mixDevice; ++ shared_ptr 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 + + #include +@@ -33,7 +35,6 @@ + #include + #include + +-#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(qw); +- MixDevice *md = mdw->mixDevice(); ++ shared_ptr 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_ptrdockMD = 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 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 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& mds, const QString& name, ChannelType type ) : ++MixDeviceComposite::MixDeviceComposite( Mixer* mixer, const QString& id, QList >& 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 it(mds); ++ QListIterator > it(mds); + while ( it.hasNext()) { +- MixDevice* md = it.next(); ++ shared_ptr md = it.next(); + _mds.append(md); + } + } +@@ -75,11 +75,12 @@ + + long MixDeviceComposite::calculateVolume(Volume::VolumeType vt) + { +- QListIterator it(_mds); ++ QListIterator > it(_mds); + long volSum = 0; + int volCount = 0; +- while ( it.hasNext()) { +- MixDevice* md = it.next(); ++ while ( it.hasNext()) ++ { ++ shared_ptr 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 it(_mds); ++ QListIterator > it(_mds); + while ( it.hasNext()) { +- MixDevice* md = it.next(); ++ shared_ptr 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 it(_mds); ++ QListIterator > it(_mds); + while ( it.hasNext()) { +- MixDevice* md = it.next(); ++ shared_ptr md = it.next(); + md->setMuted(value); + } + } +@@ -123,9 +124,9 @@ + bool MixDeviceComposite::isRecSource() + { + bool isRecSource = false; +- QListIterator it(_mds); ++ QListIterator > it(_mds); + while ( it.hasNext()) { +- MixDevice* md = it.next(); ++ shared_ptr 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 it(_mds); ++ QListIterator > it(_mds); + while ( it.hasNext()) { +- MixDevice* md = it.next(); ++ shared_ptr md = it.next(); + md->setRecSource(value); + } + } +@@ -146,9 +147,9 @@ + bool MixDeviceComposite::isEnum() + { + bool isEnum = true; +- QListIterator it(_mds); ++ QListIterator > it(_mds); + while ( it.hasNext()) { +- MixDevice* md = it.next(); ++ shared_ptr 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 + ++// std::shared_ptr ++#include ++#include ++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& mds, const QString& name, ChannelType type ); ++ MixDeviceComposite( Mixer* mixer, const QString& id, QList >& 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 _mds; ++ QList > _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 + + #include + +-#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 + + ++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 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 md, *this) + { +- MixDevice *md = operator[](i); + md->write( config, grp ); + } + } +@@ -65,23 +67,26 @@ + m_name = name; + } + +-MixDevice* MixSet::get(QString id) ++shared_ptr 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 mdRet; ++ ++ foreach ( shared_ptr 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 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 + + #include + #include + +-#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::addToPool() ++{ ++ const QString& fullyQualifiedId = getFullyQualifiedId(); ++ kDebug() << "MixDevice::init() id=" << fullyQualifiedId; ++ ++ shared_ptr thisSharedPtr(this); ++ //shared_ptr 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 ++class MixSet : public QList > + { + 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 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 ++#include ++using namespace ::std::tr1; ++ + //KMix + class Mixer; + class MixSet; + class ProfControl; + #include "core/volume.h" ++class DBusControlWrapper; + + // KDE + #include +@@ -96,7 +102,10 @@ + enum SwitchType { OnOff, Mute, Capture, Activator }; + + /** +- * Constructor: ++ * Constructor for a MixDevice. ++ * After having constructed a MixDevice, you must add it to the ControlPool ++ * by calling addToPool(). You may then not 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 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 _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 + #include + #include + #include + +-#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 it( _mixerBackend->m_mixDevices ); + for(int i=0; i<_mixerBackend->m_mixDevices.count() ; i++ ) + { +- MixDevice *md = _mixerBackend->m_mixDevices[i]; ++ shared_ptr 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 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 Mixer::operator[](int num) + { +- MixDevice* md = _mixerBackend->m_mixDevices.at( num ); +- Q_ASSERT( md ); +- return md; ++ shared_ptr 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 master = getLocalMasterMD(); ++ if ( master.get() == 0 ) ++ { + // no master device available => return + return; + } +@@ -427,39 +432,41 @@ + } + + +-MixDevice* Mixer::getGlobalMasterMD() ++shared_ptr Mixer::getGlobalMasterMD() + { + return getGlobalMasterMD(true); + } + + +-MixDevice* Mixer::getGlobalMasterMD(bool fallbackAllowed) ++shared_ptr 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 mdRet; ++ Mixer *mixer = fallbackAllowed ? ++ Mixer::getGlobalMasterMixer() : Mixer::getGlobalMasterMixerNoFalback(); ++ ++ if ( mixer == 0 ) ++ return mdRet; ++ ++ foreach (shared_ptr 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 Mixer::getLocalMasterMD() + { + return find( _masterDevicePK ); + } +@@ -470,25 +477,32 @@ + } + + +-MixDevice* Mixer::find(const QString& mixdeviceID) ++shared_ptr 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 mdRet; ++ ++ foreach (shared_ptr 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 Mixer::getMixdeviceById( const QString& mixdeviceID ) + { +- MixDevice* md = 0; ++ shared_ptr 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 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 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 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 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 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 getGlobalMasterMD(); ++ static shared_ptr 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 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 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 + #include +@@ -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 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 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 +- +-DBusControlWrapper::DBusControlWrapper(MixDevice* parent, QString path) +- : QObject(parent) +- , m_dbusPath(path) ++DBusControlWrapper::DBusControlWrapper(shared_ptr 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 + +-#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 md, m_mixer->getMixSet() ) + { + result.append( md->dbusPath() ); + } +@@ -60,7 +61,7 @@ + + QString DBusMixerWrapper::masterControl() + { +- MixDevice* md = m_mixer->getLocalMasterMD(); ++ shared_ptr 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 parent, const QString& path); + ~DBusControlWrapper(); + + void increaseVolume(); + void decreaseVolume(); + void toggleMute(); + private: +- MixDevice *m_md; +- QString m_dbusPath; ++ shared_ptr 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 + #include +@@ -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 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 + #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 @@ + + + +- ++ + + + ++ + + + +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 ++ + #include + #include + #include +@@ -8,9 +10,7 @@ + #include + #include + +-#include + +- + 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 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 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 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 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 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 + #include + +@@ -27,9 +29,7 @@ + #include + #include + #include +-//#include + #include +-//#include + #include + #include + #include +@@ -40,20 +40,10 @@ + #include + + // 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(); + ) +@@ -167,7 +157,7 @@ + if ( mixerMasterCard != 0 ) { + config.writeEntry( "MasterMixer", mixerMasterCard->id() ); + } +- MixDevice* mdMaster = Mixer::getGlobalMasterMD(); ++ shared_ptr 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 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 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 header file. */ +-#cmakedefine HAVE_ALIB_H 1 +- +-/* Define to 1 if you have the 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 header file. */ +-#cmakedefine HAVE_LINUX_CDROM_H 1 +- +-/* Define to 1 if you have the header file. */ +-#cmakedefine HAVE_LINUX_UCDROM_H 1 +- +-/* Define to 1 if you have the header file. */ +-#cmakedefine HAVE_MACHINE_SOUNDCARD_H 1 +- +-/* Define to 1 if you have the header file. */ +-#cmakedefine HAVE_SOUNDCARD_H 1 +- +-/* Define to 1 if you have the header file. */ +-#cmakedefine HAVE_SYS_AUDIOIO_H 1 +- +-/* Define to 1 if you have the header file. */ +-#cmakedefine HAVE_SYS_SOUNDCARD_H 1 +- +-/* Define to 1 if you have the header file. */ +-#cmakedefine HAVE_SYS_STAT_H 1 +- + /* Define to 1 if you have the header file. */ + #cmakedefine HAVE_MACHINE_ENDIAN_H 1 + +@@ -43,14 +13,5 @@ + /* Define to 1 if you have the header file. */ + #cmakedefine HAVE_ENDIAN_H 1 + +-/* Define if you have XShmGetEventBase in 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 +- * HP/UX-Port: Copyright (C) 1999 by Helge Deller +- * +- * 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<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 +- * Copyright (C) 1999 by Helge Deller +- * +- * 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 +-#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 ) = 0; + /// Volume Write +- virtual int writeVolumeToHW( const QString& id, MixDevice * ) = 0; ++ virtual int writeVolumeToHW( const QString& id, shared_ptr ) = 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 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 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 md); ++ virtual int writeVolumeToHW(const QString& id, shared_ptr 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 ); ++ virtual int writeVolumeToHW ( const QString& id, shared_ptr ); + + 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 md = m_mixDevices[i]; + bool isRecsrc = ( (recsrcMask & ( 1<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 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 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 + #include + #include +@@ -29,7 +31,6 @@ + #include + #include + +-#include "mixer_sun.h" + #include "core/mixer.h" + #include + #include +@@ -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 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 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 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 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 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 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 ); ++ virtual int writeVolumeToHW ( const QString& id, shared_ptr ); + + 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 ); ++ virtual int writeVolumeToHW ( const QString& id, shared_ptr ); + + 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 + #include + #include + #include +- +- + #include + ++#include ++ + // 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 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 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)) ); + 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::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 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 ); ++ virtual int writeVolumeToHW( const QString& id, shared_ptr ); + 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 md ); ++ virtual int writeVolumeToHW ( const QString& id, shared_ptr 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 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 + +-#include "mixer_backend.h" + // for the "ERR_" declartions, #include mixer.h + #include "core/mixer.h" + #include +@@ -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 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 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 + #include + #include +@@ -28,8 +31,6 @@ + #include + #include + +-/* We're getting soundcard.h via mixer_oss4.h */ +-#include "mixer_oss4.h" + #include + #include + #include +@@ -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 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 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 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 + #include + #include + + #include + +-#include "mixer_pulse.h" + #include "core/mixer.h" + + #include + #include ++#if defined(HAVE_CANBERRA) ++# include ++#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 s_mixers; + + typedef QMap 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 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 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 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 @@ + + ++ "http://www.kde.org/standards/kcfg/1.0/kcfg.xsd"> + + + + +- ++ + + + +- +- ++ ++ + ++ ++ ++ ++ ++ + +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 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 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 6:4.8.2-3 - -dragonplayer: Provides: dragon