diff options
author | root <root@rshg047.dnsready.net> | 2011-04-07 04:58:41 +0000 |
---|---|---|
committer | root <root@rshg047.dnsready.net> | 2011-04-07 04:58:41 +0000 |
commit | db464f25fec54ddfa7825a17b20fda025c296f8c (patch) | |
tree | 4bb5b8ac4dfd67096125b92d047323e6acbb86cd /extra/kdemultimedia | |
parent | bd65dc7107bfdd881c3b5451d0300824cf435428 (diff) |
Thu Apr 7 04:58:41 UTC 2011
Diffstat (limited to 'extra/kdemultimedia')
-rw-r--r-- | extra/kdemultimedia/PKGBUILD | 17 | ||||
-rw-r--r-- | extra/kdemultimedia/kmix-locale-pulseaudio.patch | 1117 |
2 files changed, 1128 insertions, 6 deletions
diff --git a/extra/kdemultimedia/PKGBUILD b/extra/kdemultimedia/PKGBUILD index f73f5d382..afdc0a8a1 100644 --- a/extra/kdemultimedia/PKGBUILD +++ b/extra/kdemultimedia/PKGBUILD @@ -1,4 +1,4 @@ -# $Id: PKGBUILD 111780 2011-02-28 23:55:31Z andrea $ +# $Id: PKGBUILD 118074 2011-04-05 10:08:23Z andrea $ # Maintainer: Andrea Scarpino <andrea@archlinux.org> # Contributor: Pierre Schmitz <pierre@archlinux.de> @@ -10,7 +10,7 @@ pkgname=('kdemultimedia-dragonplayer' 'kdemultimedia-kmix' 'kdemultimedia-kscd' 'kdemultimedia-mplayerthumbs') -pkgver=4.6.1 +pkgver=4.6.2 pkgrel=1 arch=('i686' 'x86_64') url='http://www.kde.org' @@ -19,12 +19,17 @@ groups=('kde' 'kdemultimedia') makedepends=('pkgconfig' 'cmake' 'automoc4' 'kdebase-runtime' 'tunepimp' 'ffmpeg' 'mplayer' 'docbook-xsl' 'pulseaudio' 'libmusicbrainz3') source=("http://download.kde.org/stable/${pkgver}/src/${pkgbase}-${pkgver}.tar.bz2" - 'mplayerthumbs.config') -sha1sums=('ad8f6e45d60d2b9cc0fd806e000076fcc0c07a5f' - 'ba016fa2563c14ffcba852c62506b66bfc6ee683') + 'mplayerthumbs.config' + 'kmix-locale-pulseaudio.patch') +sha1sums=('4447d26488e3b97c43580d86ad47cee77ff98578' + 'ba016fa2563c14ffcba852c62506b66bfc6ee683' + '5aa443ace9f4b1906c227664b4e50bace666cf99') build() { - cd $srcdir + cd ${srcdir}/${pkgbase}-${pkgver} + patch -Np0 -i ${srcdir}/kmix-locale-pulseaudio.patch + + cd ${srcdir} mkdir build cd build cmake ../${pkgbase}-${pkgver} \ diff --git a/extra/kdemultimedia/kmix-locale-pulseaudio.patch b/extra/kdemultimedia/kmix-locale-pulseaudio.patch new file mode 100644 index 000000000..88be8dbde --- /dev/null +++ b/extra/kdemultimedia/kmix-locale-pulseaudio.patch @@ -0,0 +1,1117 @@ +Index: kmix/apps/kmix.cpp +=================================================================== +--- kmix/apps/kmix.cpp (revision 1226955) ++++ kmix/apps/kmix.cpp (revision 1226956) +@@ -78,8 +78,6 @@ + m_dockWidget(), + m_dontSetDefaultCardOnStart (false) + { +- _cornerLabelNew = 0; +- + setObjectName( QLatin1String("KMixWindow" )); + // disable delete-on-close because KMix might just sit in the background waiting for cards to be plugged in + setAttribute(Qt::WA_DeleteOnClose, false); +@@ -184,16 +182,29 @@ + + void KMixWindow::initActionsAfterInitMixer() + { ++ bool isPulseAudio = false; + // Add "launch_pavucontrol" to menu, if Pulseaudio backend is in use + foreach( Mixer* mixer, Mixer::mixers() ) + { +- if ( mixer->getDriverName() == "PulseAudio") { ++ if ( mixer->getDriverName() == "PulseAudio") ++ { ++ isPulseAudio = true; + KAction* action = actionCollection()->addAction( "launch_pavucontrol" ); + action->setText( i18n( "Audio setup (&Pulseaudio)" ) ); + connect(action, SIGNAL(triggered(bool) ), SLOT( slotPavucontrolExec() )); + break; + } + } ++ ++ if (! isPulseAudio ) ++ { ++ QPixmap cornerNewPM = KIconLoader::global()->loadIcon( "tab-new", KIconLoader::Toolbar, KIconLoader::SizeSmall ); ++ QPushButton* _cornerLabelNew = new QPushButton(); ++ _cornerLabelNew->setIcon(cornerNewPM); ++ //cornerLabelNew->setSizePolicy(QSizePolicy()); ++ m_wsMixers->setCornerWidget(_cornerLabelNew, Qt::TopLeftCorner); ++ connect ( _cornerLabelNew, SIGNAL( clicked() ), SLOT (newView() ) ); ++ } + } + + void KMixWindow::initPrefDlg() +@@ -210,15 +221,10 @@ + m_wsMixers = new KTabWidget(); + m_wsMixers->setDocumentMode(true); + setCentralWidget(m_wsMixers); +- m_wsMixers->setTabsClosable(true); ++ m_wsMixers->setTabsClosable(false); + connect (m_wsMixers, SIGNAL(tabCloseRequested(int)), SLOT(saveAndCloseView(int)) ); + + QPixmap cornerNewPM = KIconLoader::global()->loadIcon( "tab-new", KIconLoader::Toolbar, KIconLoader::SizeSmall ); +- _cornerLabelNew = new QPushButton(); +- _cornerLabelNew->setIcon(cornerNewPM); +- //cornerLabelNew->setSizePolicy(QSizePolicy()); +- m_wsMixers->setCornerWidget(_cornerLabelNew, Qt::TopLeftCorner); +- connect ( _cornerLabelNew, SIGNAL( clicked() ), SLOT (newView() ) ); + + connect( m_wsMixers, SIGNAL( currentChanged ( int ) ), SLOT( newMixerShown(int)) ); + +@@ -516,6 +522,7 @@ + addMixerWidget(mixer->id(), guiprof, -1); + } + else { ++ // did exist => remove and insert new guiprof at old position + int indexOfTab = m_wsMixers->indexOf(kmw); + if ( indexOfTab != -1 ) m_wsMixers->removeTab(indexOfTab); + delete kmw; +@@ -676,9 +683,9 @@ + m_wsMixers->removeTab(idx); + delete kmw; + +- if ( m_wsMixers->count() < 2 ) { +- m_wsMixers->setTabsClosable(false); +- } ++ bool isPulseAudio = kmw->mixer()->getDriverName() == "PulseAudio"; ++ m_wsMixers->setTabsClosable(!isPulseAudio && m_wsMixers->count() > 1); ++ + saveViewConfig(); + } + kDebug() << "Exit"; +@@ -874,9 +881,9 @@ + if ( kmw->getGuiprof()->getId() == m_defaultCardOnStart ) { + m_wsMixers->setCurrentWidget(kmw); + } +- if ( m_wsMixers->count() > 1 ) { +- m_wsMixers->setTabsClosable(true); +- } ++ ++ bool isPulseAudio = mixer->getDriverName() == "PulseAudio"; ++ m_wsMixers->setTabsClosable(!isPulseAudio && m_wsMixers->count() > 1); + m_dontSetDefaultCardOnStart = false; + + +Index: kmix/apps/kmix.h +=================================================================== +--- kmix/apps/kmix.h (revision 1226955) ++++ kmix/apps/kmix.h (revision 1226956) +@@ -116,7 +116,6 @@ + Qt::Orientation m_toplevelOrientation; + + KTabWidget *m_wsMixers; +- QPushButton* _cornerLabelNew; + + KMixPrefDlg *m_prefDlg; + KMixDockWidget *m_dockWidget; +Index: kmix/gui/viewbase.cpp +=================================================================== +--- kmix/gui/viewbase.cpp (revision 1226956) ++++ kmix/gui/viewbase.cpp (revision 1226957) +@@ -226,34 +226,35 @@ + + // Check the guiprofile... if it is not the fallback GUIProfile, then + // make sure that we add a specific entry for any devices not present. +- if ( 0 != _guiprof && GUIProfile::fallbackProfile(_mixer) != _guiprof ) { ++ if ( 0 != _guiprof && GUIProfile::fallbackProfile(_mixer) != _guiprof ) // TODO colin/cesken IMO calling GUIProfile::fallbackProfile(_mixer) is wrong, as it ALWAYS creates a new Object. fallbackProfile() would need to cache the created fallback profiles so this should make any sense. ++ { + kDebug(67100) << "Dynamic mixer " << _mixer->id() << " is NOT using Fallback GUIProfile. Checking to see if new controls are present"; + + QList<QString> new_mix_devices; + MixSet ms = _mixer->getMixSet(); + for (int i=0; i < ms.count(); ++i) ++ { + new_mix_devices.append("^" + ms[i]->id() + "$"); ++ kDebug(67100) << "new_mix_devices.append => " << ms[i]->id(); ++ } + ++ GUIProfile::ControlSet& ctlSet = _guiprof->getControls(); ++ + // std::vector<ProfControl*>::const_iterator itEnd = _guiprof->_controls.end(); + // for ( std::vector<ProfControl*>::const_iterator it = _guiprof->_controls.begin(); it != itEnd; ++it) + // new_mix_devices.removeAll((*it)->id); + // TODO Please check this change, Colin +- foreach ( ProfControl* pctl, _guiprof->getControls() ) { ++ foreach ( ProfControl* pctl, ctlSet ) { + new_mix_devices.removeAll(pctl->id); + } + + + if ( new_mix_devices.count() > 0 ) { + kDebug(67100) << "Found " << new_mix_devices.count() << " new controls. Adding to GUIProfile"; ++ QString sctlMatchAll("*"); + while ( new_mix_devices.count() > 0 ) { +- QString sctlMatchAll("*"); + QString new_mix_devices0 = new_mix_devices.takeAt(0); +- ProfControl* ctl = new ProfControl(new_mix_devices0, sctlMatchAll); +-// ctl->id = new_mix_devices.takeAt(0); +-// ctl->setSubcontrols(QString("*")); +-// ctl->tab = (_guiprof->tabs())[0]->name(); // Use the first tab... not ideal but should work most of the time; +-// ctl->show = "simple"; +- _guiprof->getControls().push_back(ctl); ++ ctlSet.push_back(new ProfControl(new_mix_devices0, sctlMatchAll)); + } + _guiprof->setDirty(); + } +Index: kmix/gui/viewbase.cpp +=================================================================== +--- kmix/gui/viewbase.cpp (revision 1226957) ++++ kmix/gui/viewbase.cpp (revision 1226958) +@@ -33,6 +33,7 @@ + #include <kactioncollection.h> + #include <ktoggleaction.h> + #include <kstandardaction.h> ++#include <kmessagebox.h> + // KMix + #include "dialogviewconfiguration.h" + #include "gui/guiprofile.h" +@@ -43,7 +44,7 @@ + + + ViewBase::ViewBase(QWidget* parent, const char* id, Mixer* mixer, Qt::WFlags f, ViewBase::ViewFlags vflags, GUIProfile *guiprof, KActionCollection *actionColletion) +- : QWidget(parent, f), _actions(actionColletion), _vflags(vflags), _guiprof(guiprof) ++ : QWidget(parent, f), _popMenu(NULL), _actions(actionColletion), _vflags(vflags), _guiprof(guiprof) + { + setObjectName(id); + m_viewId = id; +@@ -73,9 +74,11 @@ + } + } + } +- QAction *action = _localActionColletion->addAction("toggle_channels"); +- action->setText(i18n("&Channels")); +- connect(action, SIGNAL(triggered(bool) ), SLOT(configureView())); ++ if ( !_mixer->isDynamic() ) { ++ QAction *action = _localActionColletion->addAction("toggle_channels"); ++ action->setText(i18n("&Channels")); ++ connect(action, SIGNAL(triggered(bool) ), SLOT(configureView())); ++ } + connect ( _mixer, SIGNAL(controlChanged()), this, SLOT(refreshVolumeLevels()) ); + connect ( _mixer, SIGNAL(controlsReconfigured(const QString&)), this, SLOT(controlsReconfigured(const QString&)) ); + } +@@ -95,7 +98,7 @@ + + bool ViewBase::isValid() const + { +- return ( _mixSet->count() > 0 || _mixer->dynamic() ); ++ return ( _mixSet->count() > 0 || _mixer->isDynamic() ); + } + + void ViewBase::setIcons (bool on) { KMixToolBox::setIcons (_mdws, on ); } +@@ -170,6 +173,8 @@ + { + QAction *a; + ++ if ( _popMenu ) ++ delete _popMenu; + _popMenu = new KMenu( this ); + _popMenu->addTitle( KIcon( QLatin1String( "kmix" ) ), i18n("Device Settings" )); + +@@ -222,44 +227,8 @@ + + void ViewBase::setMixSet() + { +- if ( _mixer->dynamic()) { ++ if ( _mixer->isDynamic() ) { + +- // Check the guiprofile... if it is not the fallback GUIProfile, then +- // make sure that we add a specific entry for any devices not present. +- if ( 0 != _guiprof && GUIProfile::fallbackProfile(_mixer) != _guiprof ) // TODO colin/cesken IMO calling GUIProfile::fallbackProfile(_mixer) is wrong, as it ALWAYS creates a new Object. fallbackProfile() would need to cache the created fallback profiles so this should make any sense. +- { +- kDebug(67100) << "Dynamic mixer " << _mixer->id() << " is NOT using Fallback GUIProfile. Checking to see if new controls are present"; +- +- QList<QString> new_mix_devices; +- MixSet ms = _mixer->getMixSet(); +- for (int i=0; i < ms.count(); ++i) +- { +- new_mix_devices.append("^" + ms[i]->id() + "$"); +- kDebug(67100) << "new_mix_devices.append => " << ms[i]->id(); +- } +- +- GUIProfile::ControlSet& ctlSet = _guiprof->getControls(); +- +-// std::vector<ProfControl*>::const_iterator itEnd = _guiprof->_controls.end(); +-// for ( std::vector<ProfControl*>::const_iterator it = _guiprof->_controls.begin(); it != itEnd; ++it) +-// new_mix_devices.removeAll((*it)->id); +- // TODO Please check this change, Colin +- foreach ( ProfControl* pctl, ctlSet ) { +- new_mix_devices.removeAll(pctl->id); +- } +- +- +- if ( new_mix_devices.count() > 0 ) { +- kDebug(67100) << "Found " << new_mix_devices.count() << " new controls. Adding to GUIProfile"; +- QString sctlMatchAll("*"); +- while ( new_mix_devices.count() > 0 ) { +- QString new_mix_devices0 = new_mix_devices.takeAt(0); +- ctlSet.push_back(new ProfControl(new_mix_devices0, sctlMatchAll)); +- } +- _guiprof->setDirty(); +- } +- } +- + // We need to delete the current MixDeviceWidgets so we can redraw them + while (!_mdws.isEmpty()) { + QWidget* mdw = _mdws.last(); +@@ -280,6 +249,8 @@ + */ + void ViewBase::configureView() { + ++ Q_ASSERT( !_mixer->isDynamic() ); ++ + DialogViewConfiguration* dvc = new DialogViewConfiguration(0, *this); + dvc->show(); + // !! The dialog is modal. Does it delete itself? +@@ -302,6 +273,10 @@ + kDebug(67100) << "KMixToolBox::loadView() grp=" << grp.toAscii(); + + static char guiComplexity[3][20] = { "simple", "extended", "all" }; ++ ++ // Certain bits are not saved for dynamic mixers (e.g. PulseAudio) ++ bool dynamic = _mixer->isDynamic(); ++ + for ( int tries = 0; tries < 3; tries++ ) + { + bool atLeastOneControlIsShown = false; +@@ -315,12 +290,12 @@ + Workaround: If found, write back correct group name. + */ + MixDeviceWidget* mdw = (MixDeviceWidget*)qmdw; +- QString devgrp; +- devgrp.sprintf( "%s.%s.%s", grp.toAscii().data(), mdw->mixDevice()->mixer()->id().toAscii().data(), mdw->mixDevice()->id().toAscii().data() ); ++ MixDevice* md = mdw->mixDevice(); ++ ++ QString devgrp = QString("%1.%2.%3").arg(grp).arg(md->mixer()->id()).arg(md->id()); + KConfigGroup devcg = config->group( devgrp ); + +- QString buggyDevgrp; +- buggyDevgrp.sprintf( "%s.%s.%s", grp.toAscii().data(), view->id().toAscii().data(), mdw->mixDevice()->id().toAscii().data() ); ++ QString buggyDevgrp = QString("%1.%2.%3").arg(grp).arg(view->id()).arg(md->id()); + KConfigGroup buggyDevgrpCG = config->group( buggyDevgrp ); + if ( buggyDevgrpCG.exists() ) { + buggyDevgrpCG.copyTo(&devcg); +@@ -335,7 +310,7 @@ + } + + bool mdwEnabled = false; +- if ( devcg.hasKey("Show") ) ++ if ( !dynamic && devcg.hasKey("Show") ) + { + mdwEnabled = ( true == devcg.readEntry("Show", true) ); + //kDebug() << "Load devgrp" << devgrp << "show=" << mdwEnabled; +@@ -382,20 +357,23 @@ + QString grp = "View."; + grp += view->id(); + // KConfigGroup cg = config->group( grp ); +- kDebug(67100) << "KMixToolBox::saveView() grp=" << grp.toAscii(); ++ kDebug(67100) << "KMixToolBox::saveView() grp=" << grp; + ++ // Certain bits are not saved for dynamic mixers (e.g. PulseAudio) ++ bool dynamic = _mixer->isDynamic(); ++ + for (int i=0; i < view->_mdws.count(); ++i ){ + QWidget *qmdw = view->_mdws[i]; + if ( qmdw->inherits("MixDeviceWidget") ) + { + MixDeviceWidget* mdw = (MixDeviceWidget*)qmdw; ++ MixDevice* md = mdw->mixDevice(); + + //kDebug(67100) << " grp=" << grp.toAscii(); + //kDebug(67100) << " mixer=" << view->id().toAscii(); + //kDebug(67100) << " mdwPK=" << mdw->mixDevice()->id().toAscii(); + +- QString devgrp; +- devgrp.sprintf( "%s.%s.%s", grp.toAscii().data(), mdw->mixDevice()->mixer()->id().toAscii().data(), mdw->mixDevice()->id().toAscii().data() ); ++ QString devgrp = QString("%1.%2.%3").arg(grp).arg(md->mixer()->id()).arg(md->id()); + KConfigGroup devcg = config->group( devgrp ); + + if ( mdw->inherits("MDWSlider") ) +@@ -403,15 +381,19 @@ + // only sliders have the ability to split apart in mutliple channels + devcg.writeEntry( "Split", ! mdw->isStereoLinked() ); + } +- devcg.writeEntry( "Show" , mdw->isVisibleTo(view) ); +-kDebug() << "Save devgrp" << devgrp << "show=" << mdw->isVisibleTo(view); ++ if ( !dynamic ) { ++ devcg.writeEntry( "Show" , mdw->isVisibleTo(view) ); ++ kDebug() << "Save devgrp" << devgrp << "show=" << mdw->isVisibleTo(view); ++ } + + } // inherits MixDeviceWidget + } // for all MDW's + +- kDebug(67100) << "GUIProfile is dirty: " << guiProfile()->isDirty(); +- if ( guiProfile()->isDirty() ) { +- guiProfile()->writeProfile(); ++ if ( !dynamic ) { ++ // We do not save GUIProfiles (as they cannot be customised) for dynamic mixers (e.g. PulseAudio) ++ kDebug(67100) << "GUIProfile is dirty: " << guiProfile()->isDirty(); ++ if ( guiProfile()->isDirty() ) ++ guiProfile()->writeProfile(); + } + } + +Index: kmix/gui/mdwslider.cpp +=================================================================== +--- kmix/gui/mdwslider.cpp (revision 1226957) ++++ kmix/gui/mdwslider.cpp (revision 1226958) +@@ -86,10 +86,14 @@ + KToggleAction *taction = _mdwActions->add<KToggleAction>( "stereo" ); + taction->setText( i18n("&Split Channels") ); + connect( taction, SIGNAL( triggered(bool) ), SLOT( toggleStereoLinked() ) ); +- KAction *action = _mdwActions->add<KToggleAction>( "hide" ); +- action->setText( i18n("&Hide") ); +- connect( action, SIGNAL( triggered(bool) ), SLOT( setDisabled() ) ); + ++ KAction *action; ++ if ( ! m_mixdevice->mixer()->isDynamic() ) { ++ action = _mdwActions->add<KToggleAction>( "hide" ); ++ action->setText( i18n("&Hide") ); ++ connect( action, SIGNAL( triggered(bool) ), SLOT( setDisabled() ) ); ++ } ++ + if( m_mixdevice->playbackVolume().hasSwitch() ) { + taction = _mdwActions->add<KToggleAction>( "mute" ); + taction->setText( i18n("&Muted") ); +@@ -129,8 +133,8 @@ + #ifdef __GNUC__ + #warning GLOBAL SHORTCUTS ARE NOW ASSIGNED TO ALL CONTROLS, as enableGlobalShortcut(), has not been committed + #endif +- if ( ! mixDevice()->isEthereal() ) { +- // virtual / ethereal controls won't get shortcuts ++ if ( ! mixDevice()->mixer()->isDynamic() ) { ++ // virtual / dynamic controls won't get shortcuts + b->setGlobalShortcut(dummyShortcut); // -<- enableGlobalShortcut() is not there => use workaround + // b->enableGlobalShortcut(); + connect( b, SIGNAL( triggered(bool) ), SLOT( increaseVolume() ) ); +@@ -143,8 +147,8 @@ + #ifdef __GNUC__ + #warning GLOBAL SHORTCUTS ARE NOW ASSIGNED TO ALL CONTROLS, as enableGlobalShortcut(), has not been committed + #endif +- if ( ! mixDevice()->isEthereal() ) { +- // virtual / ethereal controls won't get shortcuts ++ if ( ! mixDevice()->mixer()->isDynamic() ) { ++ // virtual / dynamic controls won't get shortcuts + b->setGlobalShortcut(dummyShortcut); // -<- enableGlobalShortcut() is not there => use workaround + // b->enableGlobalShortcut(); + connect( b, SIGNAL( triggered(bool) ), SLOT( decreaseVolume() ) ); +@@ -157,8 +161,8 @@ + #ifdef __GNUC__ + #warning GLOBAL SHORTCUTS ARE NOW ASSIGNED TO ALL CONTROLS, as enableGlobalShortcut(), has not been committed + #endif +- if ( ! mixDevice()->isEthereal() ) { +- // virtual / ethereal controls won't get shortcuts ++ if ( ! mixDevice()->mixer()->isDynamic() ) { ++ // virtual / dynamic controls won't get shortcuts + b->setGlobalShortcut(dummyShortcut); // -<- enableGlobalShortcut() is not there => use workaround + // b->enableGlobalShortcut(); + connect( b, SIGNAL( triggered(bool) ), SLOT( toggleMuted() ) ); +Index: kmix/gui/viewdockareapopup.h +=================================================================== +--- kmix/gui/viewdockareapopup.h (revision 1226957) ++++ kmix/gui/viewdockareapopup.h (revision 1226958) +@@ -24,7 +24,6 @@ + #include "viewbase.h" + + class QGridLayout; +-class QPushButton; + class QWidget; + + class Mixer; +@@ -48,8 +47,6 @@ + + protected: + KMixWindow *_dock; +- //MixDevice *_dockDevice; +- QPushButton *_showPanelBox; + + void wheelEvent ( QWheelEvent * e ); + virtual void _setMixSet(); +Index: kmix/gui/viewsliders.cpp +=================================================================== +--- kmix/gui/viewsliders.cpp (revision 1226957) ++++ kmix/gui/viewsliders.cpp (revision 1226958) +@@ -148,7 +148,7 @@ + { + const MixSet& mixset = _mixer->getMixSet(); + +- if ( _mixer->dynamic() ) { ++ if ( _mixer->isDynamic() ) { + // We will be recreating our sliders, so make sure we trash all the separators too. + qDeleteAll(_separators); + _separators.clear(); +Index: kmix/gui/guiprofile.cpp +=================================================================== +--- kmix/gui/guiprofile.cpp (revision 1226957) ++++ kmix/gui/guiprofile.cpp (revision 1226958) +@@ -158,8 +158,12 @@ + { + GUIProfile* guiprof = 0; + +- if ( mixer == 0 || profileName.isEmpty() ) { ++ if ( mixer == 0 || profileName.isEmpty() ) + return 0; ++ ++ if ( mixer->isDynamic() ) { ++ kDebug(67100) << "GUIProfile::find() Not loading GUIProfile for Dynamic Mixer (e.g. PulseAudio)"; ++ return 0; + } + + QString requestedProfileName; +Index: kmix/gui/viewbase.h +=================================================================== +--- kmix/gui/viewbase.h (revision 1226957) ++++ kmix/gui/viewbase.h (revision 1226958) +@@ -133,7 +133,7 @@ + + ViewFlags _vflags; + GUIProfile* _guiprof; +- KActionCollection *_localActionColletion; ++ KActionCollection *_localActionColletion; + + virtual void _setMixSet() = 0; + +Index: kmix/gui/viewdockareapopup.cpp +=================================================================== +--- kmix/gui/viewdockareapopup.cpp (revision 1226957) ++++ kmix/gui/viewdockareapopup.cpp (revision 1226958) +@@ -88,8 +88,8 @@ + { + // kDebug(67100) << "ViewDockAreaPopup::setMixSet()\n"; + +- if ( _mixer->dynamic() ) { +- // Our _layoutMDW now should only contain spacer widgets from the QSpacerItems's in add() below. ++ 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) ) ) +@@ -114,9 +114,9 @@ + QString matchAllPlaybackAndTheCswitch("pvolume,pswitch,cswitch"); + ProfControl *pctl = new ProfControl( dummyMatchAll, matchAllPlaybackAndTheCswitch); + MixDeviceWidget *mdw = new MDWSlider( +- md, // only 1 device. This is actually _dockDevice ++ md, // only 1 device. + true, // Show Mute LED +- false, // Show Record LED ++ false, // Show Record LED + false, // Small + Qt::Vertical, // Direction: only 1 device, so doesn't matter + this, // parent +@@ -128,10 +128,10 @@ + _layoutMDW->addWidget( mdw, 0, 1 ); + + // Add button to show main panel +- _showPanelBox = new QPushButton( i18n("Mixer"), this ); +- _showPanelBox->setObjectName( QLatin1String("MixerPanel" )); +- connect ( _showPanelBox, SIGNAL( clicked() ), SLOT( showPanelSlot() ) ); +- _layoutMDW->addWidget( _showPanelBox, 1, 0, 1, 3 ); ++ QPushButton *pb = new QPushButton( i18n("Mixer"), this ); ++ pb->setObjectName( QLatin1String("MixerPanel" )); ++ connect ( pb, SIGNAL( clicked() ), SLOT( showPanelSlot() ) ); ++ _layoutMDW->addWidget( pb, 1, 0, 1, 3 ); + + return mdw; + } +Index: kmix/core/mixdevice.h +=================================================================== +--- kmix/core/mixdevice.h (revision 1226957) ++++ kmix/core/mixdevice.h (revision 1226958) +@@ -157,15 +157,6 @@ + _artificial = artificial; + } + +- bool isEthereal() const +- { +- return _ethereal; +- } +- void setEthereal(bool _ethereal) +- { +- this->_ethereal = _ethereal; +- } +- + void setControlProfile(ProfControl* control); + ProfControl* controlProfile(); + +@@ -191,14 +182,12 @@ + int _enumCurrentId; + QList<QString> _enumValues; // A MixDevice, that is an ENUM, has these _enumValues + +- //bool _doNotRestore; + // 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 ethereal controls: ++ // Actually we discriminate those "virtual" controls in artificial controls and dynamic controls: + // Type Shortcut Restore + // Artificial: yes no Virtual::GlobalMaster or Virtual::CaptureGroup_3 (controls that are constructed artificially from other controls) +- // Ethereal : no no Controls that come and go, like Pulse Stream controls ++ // Dynamic : no no Controls that come and go, like Pulse Stream controls + bool _artificial; +- bool _ethereal; + MixSet *_moveDestinationMixSet; + QString _iconName; + +Index: kmix/core/mixer.cpp +=================================================================== +--- kmix/core/mixer.cpp (revision 1226957) ++++ kmix/core/mixer.cpp (revision 1226958) +@@ -748,7 +748,7 @@ + m_dynamic = dynamic; + } + +-bool Mixer::dynamic() ++bool Mixer::isDynamic() + { + return m_dynamic; + } +Index: kmix/core/mixer.h +=================================================================== +--- kmix/core/mixer.h (revision 1226957) ++++ kmix/core/mixer.h (revision 1226958) +@@ -164,7 +164,7 @@ + + /// Says if we are dynamic (e.g. widgets can come and go) + virtual void setDynamic( bool dynamic = true ); +- virtual bool dynamic(); ++ virtual bool isDynamic(); + + virtual bool moveStream( const QString id, const QString& destId ); + +Index: kmix/core/mixdevice.cpp +=================================================================== +--- kmix/core/mixdevice.cpp (revision 1226957) ++++ kmix/core/mixdevice.cpp (revision 1226958) +@@ -23,6 +23,7 @@ + #include <klocale.h> + + #include "core/mixdevice.h" ++#include "core/mixer.h" + #include "gui/guiprofile.h" + #include "core/volume.h" + +@@ -96,14 +97,12 @@ + + MixDevice::MixDevice( Mixer* mixer, const QString& id, const QString& name, const QString& iconName, MixSet* moveDestinationMixSet ) + { +- // doNotRestore is superseded by the more generic concepts isEthereal(), isArtificial() + init(mixer, id, name, iconName, moveDestinationMixSet); + } + + void MixDevice::init( Mixer* mixer, const QString& id, const QString& name, const QString& iconName, MixSet* moveDestinationMixSet ) + { + _artificial = false; +- _ethereal = false; + _mixer = mixer; + _id = id; + if( name.isEmpty() ) +@@ -117,9 +116,10 @@ + _moveDestinationMixSet = moveDestinationMixSet; + if ( _id.contains(' ') ) { + // The key is used in the config file. It MUST NOT contain spaces +- kError(67100) << "MixDevice::setId(\"" << id << "\") . Invalid key - it might not contain spaces" << endl; ++ kError(67100) << "MixDevice::setId(\"" << id << "\") . Invalid key - it must not contain spaces" << endl; + _id.replace(' ', '_'); + } ++ kDebug(67100) << "MixDevice::init() _id=" << _id; + } + + void MixDevice::addPlaybackVolume(Volume &playbackVol) +@@ -216,11 +216,10 @@ + */ + void MixDevice::read( KConfig *config, const QString& grp ) + { +- if ( isEthereal() || isArtificial() ) { ++ if ( _mixer->isDynamic() || isArtificial() ) { + kDebug(67100) << "MixDevice::read(): This MixDevice does not permit volume restoration (i.e. because it is handled lower down in the audio stack). Ignoring."; + } else { +- QString devgrp; +- devgrp.sprintf( "%s.Dev%s", grp.toAscii().data(), _id.toAscii().data() ); ++ QString devgrp = QString("%1.Dev%2").arg(grp).arg(_id); + KConfigGroup cg = config->group( devgrp ); + //kDebug(67100) << "MixDevice::read() of group devgrp=" << devgrp; + +@@ -264,11 +263,10 @@ + */ + void MixDevice::write( KConfig *config, const QString& grp ) + { +- if (isEthereal() || isArtificial()) { ++ if (_mixer->isDynamic() || isArtificial()) { + kDebug(67100) << "MixDevice::write(): This MixDevice does not permit volume saving (i.e. because it is handled lower down in the audio stack). Ignoring."; + } else { +- QString devgrp; +- devgrp.sprintf( "%s.Dev%s", grp.toAscii().data(), _id.toAscii().data() ); ++ QString devgrp = QString("%1.Dev%2").arg(grp).arg(_id); + KConfigGroup cg = config->group(devgrp); + // kDebug(67100) << "MixDevice::write() of group devgrp=" << devgrp; + +Index: kmix/apps/kmix.cpp +=================================================================== +--- kmix/apps/kmix.cpp (revision 1226957) ++++ kmix/apps/kmix.cpp (revision 1226958) +@@ -182,21 +182,20 @@ + + void KMixWindow::initActionsAfterInitMixer() + { +- bool isPulseAudio = false; +- // Add "launch_pavucontrol" to menu, if Pulseaudio backend is in use ++ // Only show the new tab widget if some of the mixers are not Dynamic. ++ // The GUI that then pops up could then make a new mixer from a dynamic one, ++ // if mixed dynamic and non-dynamic mixers were allowed, but this is generally not the case. ++ bool allDynamic = true; + foreach( Mixer* mixer, Mixer::mixers() ) + { +- if ( mixer->getDriverName() == "PulseAudio") ++ if ( !mixer->isDynamic() ) + { +- isPulseAudio = true; +- KAction* action = actionCollection()->addAction( "launch_pavucontrol" ); +- action->setText( i18n( "Audio setup (&Pulseaudio)" ) ); +- connect(action, SIGNAL(triggered(bool) ), SLOT( slotPavucontrolExec() )); ++ allDynamic = false; + break; + } + } + +- if (! isPulseAudio ) ++ if (! allDynamic ) + { + QPixmap cornerNewPM = KIconLoader::global()->loadIcon( "tab-new", KIconLoader::Toolbar, KIconLoader::SizeSmall ); + QPushButton* _cornerLabelNew = new QPushButton(); +@@ -339,8 +338,11 @@ + + // The following loop is necessary for the case that the user has hidden all views for a Mixer instance. + // Otherwise we would not save the Meta information (step -2- below for that mixer. +- foreach ( Mixer* mixer, Mixer::mixers() ) +- mixerViews[mixer->id()]; // just insert a map entry ++ // We also do not save dynamic mixers (e.g. PulseAudio) ++ foreach ( Mixer* mixer, Mixer::mixers() ) { ++ if ( !mixer->isDynamic() ) ++ mixerViews[mixer->id()]; // just insert a map entry ++ } + + // -1- Save the views themselves + for ( int i=0; i<m_wsMixers->count() ; ++i ) { +@@ -351,8 +353,10 @@ + // Otherwise the user will be confused afer re-plugging the card (as the config was not saved). + mw->saveConfig( KGlobal::config().data() ); + // add the view to the corresponding mixer list, so we can save a views-per-mixer list below +- QStringList& qsl = mixerViews[mw->mixer()->id()]; +- qsl.append(mw->getGuiprof()->getId()); ++ if ( !mw->mixer()->isDynamic() ) { ++ QStringList& qsl = mixerViews[mw->mixer()->id()]; ++ qsl.append(mw->getGuiprof()->getId()); ++ } + } + } + +@@ -539,22 +543,29 @@ + continue; // OK, this mixer already has a profile => skip it + } + // No TAB YET => This should mean KMix is just started, or the user has just plugged in a card +- bool profileListHasKey = pconfig.hasKey( mixer->id() ); // <<< SHOULD be before the following line +- QStringList profileList = pconfig.readEntry( mixer->id(), QStringList() ); ++ bool profileListHasKey = false; ++ QStringList profileList; ++ bool aProfileWasAddedSucesufully = false; + +- bool aProfileWasAddedSucesufully = false; +- foreach ( QString profileId, profileList) +- { +- // This handles the profileList form the kmixrc +- kDebug() << "Now searching for profile: " << profileId ; +- GUIProfile* guiprof = GUIProfile::find(mixer, profileId, true, false); // ### Card specific profile ### +- if ( guiprof != 0 ) { +- addMixerWidget(mixer->id(), guiprof, -1); +- aProfileWasAddedSucesufully = true; ++ if ( !mixer->isDynamic() ) { ++ // We do not support save profiles for dynamic mixers (i.e. PulseAudio) ++ ++ profileListHasKey = pconfig.hasKey( mixer->id() ); // <<< SHOULD be before the following line ++ profileList = pconfig.readEntry( mixer->id(), QStringList() ); ++ ++ foreach ( QString profileId, profileList) ++ { ++ // This handles the profileList form the kmixrc ++ kDebug() << "Now searching for profile: " << profileId ; ++ GUIProfile* guiprof = GUIProfile::find(mixer, profileId, true, false); // ### Card specific profile ### ++ if ( guiprof != 0 ) { ++ addMixerWidget(mixer->id(), guiprof, -1); ++ aProfileWasAddedSucesufully = true; ++ } ++ else { ++ kError() << "Cannot load profile " << profileId << " . It was removed by the user, or the KMix config file is defective."; ++ } + } +- else { +- kError() << "Cannot load profile " << profileId << " . It was removed by the user, or the KMix config file is defective."; +- } + } + + // The we_need_a_fallback case is a bit tricky. Please ask the author (cesken) before even considering to change the code. +@@ -568,11 +579,17 @@ + + // Lets try a bunch of fallback strategies: + GUIProfile* guiprof = 0; ++ if ( !mixer->isDynamic() ) { ++ // We know that GUIProfile::find() will return 0 if the mixer is dynamic, so don't bother checking. ++ kDebug() << "Attempting to find a card-specific GUI Profile for the mixer " << mixer->id(); + guiprof = GUIProfile::find(mixer, QString("default"), false, false); // ### Card specific profile ### +- if ( guiprof == 0 ) { +- guiprof = GUIProfile::find(mixer, QString("default"), false, true); // ### Card unspecific profile ### ++ if ( guiprof == 0 ) { ++ kDebug() << "Not found. Attempting to find a generic GUI Profile for the mixer " << mixer->id(); ++ guiprof = GUIProfile::find(mixer, QString("default"), false, true); // ### Card unspecific profile ### ++ } + } + if ( guiprof == 0) { ++ kDebug() << "Using fallback GUI Profile for the mixer " << mixer->id(); + // This means there is neither card specific nor card unspecific profile + // This is the case for some backends (as they don't ship profiles). + guiprof = GUIProfile::fallbackProfile(mixer); +@@ -683,8 +700,7 @@ + m_wsMixers->removeTab(idx); + delete kmw; + +- bool isPulseAudio = kmw->mixer()->getDriverName() == "PulseAudio"; +- m_wsMixers->setTabsClosable(!isPulseAudio && m_wsMixers->count() > 1); ++ m_wsMixers->setTabsClosable(!kmw->mixer()->isDynamic() && m_wsMixers->count() > 1); + + saveViewConfig(); + } +@@ -882,8 +898,7 @@ + m_wsMixers->setCurrentWidget(kmw); + } + +- bool isPulseAudio = mixer->getDriverName() == "PulseAudio"; +- m_wsMixers->setTabsClosable(!isPulseAudio && m_wsMixers->count() > 1); ++ m_wsMixers->setTabsClosable(!mixer->isDynamic() && m_wsMixers->count() > 1); + m_dontSetDefaultCardOnStart = false; + + +@@ -1071,12 +1086,6 @@ + KMessageBox::information( 0, m_hwInfoString, i18n("Mixer Hardware Information") ); + } + +-void KMixWindow::slotPavucontrolExec() +-{ +- QStringList args("pavucontrol"); +- forkExec(args); +-} +- + void KMixWindow::slotKdeAudioSetupExec() + { + QStringList args; +@@ -1133,6 +1142,12 @@ + m_defaultCardOnStart = kmw->getGuiprof()->getId(); + // As switching the tab does NOT mean switching the master card, we do not need to update dock icon here. + // It would lead to unnecesary flickering of the (complete) dock area. ++ ++ // We only show the "Configure Channels..." menu item if the mixer is not dynamic ++ ViewBase* view = kmw->currentView(); ++ QAction* action = actionCollection()->action( "toggle_channels_currentview" ); ++ if (view && action) ++ action->setVisible( !view->getMixer()->isDynamic() ); + } + } + +Index: kmix/apps/kmix.h +=================================================================== +--- kmix/apps/kmix.h (revision 1226957) ++++ kmix/apps/kmix.h (revision 1226958) +@@ -136,7 +136,6 @@ + private slots: + void saveConfig(); + void slotHWInfo(); +- void slotPavucontrolExec(); + void slotKdeAudioSetupExec(); + void slotConfigureCurrentView(); + void slotSelectMaster(); +Index: kmix/kmixui.rc +=================================================================== +--- kmix/kmixui.rc (revision 1226957) ++++ kmix/kmixui.rc (revision 1226958) +@@ -17,7 +17,6 @@ + <Action name="toggle_channels_currentview" append="save_merge"/> + <Action name="select_master" append="save_merge"/> + <Action name="launch_kdesoundsetup" append="save_merge"/> +- <Action name="launch_pavucontrol" append="save_merge"/> + </Menu> + <Menu name="help" append="about_merge"><text>&Help</text> + <Action name="hwinfo"/> +Index: kmix/backends/mixer_backend.cpp +=================================================================== +--- kmix/backends/mixer_backend.cpp (revision 1226957) ++++ kmix/backends/mixer_backend.cpp (revision 1226958) +@@ -48,7 +48,7 @@ + bool Mixer_Backend::openIfValid() { + bool valid = false; + int ret = open(); +- if ( ret == 0 && (m_mixDevices.count() > 0 || _mixer->dynamic())) { ++ if ( ret == 0 && (m_mixDevices.count() > 0 || _mixer->isDynamic())) { + valid = true; + // A better ID is now calculated in mixertoolbox.cpp, and set via setID(), + // but we want a somehow usable fallback just in case. +@@ -139,7 +139,7 @@ + return m_mixDevices.at(0); // Backend has NOT set a recommended master. Evil backend => lets help out. + } //first device (if exists) + else { +- if ( !_mixer->dynamic()) { ++ if ( !_mixer->isDynamic()) { + // This should never ever happen, as KMix doe 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; + } +Index: kmix/backends/mixer_pulse.cpp +=================================================================== +--- kmix/backends/mixer_pulse.cpp (revision 1226957) ++++ kmix/backends/mixer_pulse.cpp (revision 1226958) +@@ -36,6 +36,8 @@ + #define KMIXPA_APP_CAPTURE 3 + #define KMIXPA_WIDGET_MAX KMIXPA_APP_CAPTURE + ++#define KMIXPA_EVENT_KEY "sink-input-by-media-role:event" ++ + static unsigned int refcount = 0; + static pa_glib_mainloop *s_mainloop = NULL; + static pa_context *s_context = NULL; +@@ -189,7 +191,7 @@ + + devinfo s; + s.index = s.device_index = i->index; +- s.name = QString(i->name).replace(' ', '_'); ++ s.name = QString::fromUtf8(i->name).replace(' ', '_'); + s.description = QString::fromUtf8(i->description); + s.icon_name = QString::fromUtf8(pa_proplist_gets(i->proplist, PA_PROP_DEVICE_ICON_NAME)); + s.volume = i->volume; +@@ -242,7 +244,7 @@ + + devinfo s; + s.index = s.device_index = i->index; +- s.name = QString(i->name).replace(' ', '_'); ++ s.name = QString::fromUtf8(i->name).replace(' ', '_'); + s.description = QString::fromUtf8(i->description); + s.icon_name = QString::fromUtf8(pa_proplist_gets(i->proplist, PA_PROP_DEVICE_ICON_NAME)); + s.volume = i->volume; +@@ -307,26 +309,28 @@ + + const char *t; + if ((t = pa_proplist_gets(i->proplist, "module-stream-restore.id"))) { +- if (strcmp(t, "sink-input-by-media-role:event") == 0) { ++ if (strcmp(t, KMIXPA_EVENT_KEY) == 0) { + kWarning(67100) << "Ignoring sink-input due to it being designated as an event and thus handled by the Event slider"; + return; + } + } + +- QString prefix = QString("%1: ").arg(i18n("Unknown Application")); ++ QString appname = i18n("Unknown Application"); + if (clients.contains(i->client)) +- prefix = QString("%1: ").arg(clients[i->client]); ++ appname = clients[i->client]; + ++ QString prefix = QString("%1: ").arg(appname); ++ + devinfo s; + s.index = i->index; + s.device_index = i->sink; + s.description = prefix + QString::fromUtf8(i->name); +- s.name = QString("stream:") + i->index; ++ s.name = QString("stream:") + QString::number(i->index); //appname.replace(' ', '_').toLower(); + s.icon_name = getIconNameFromProplist(i->proplist); + s.volume = i->volume; + s.channel_map = i->channel_map; + s.mute = !!i->mute; +- s.stream_restore_rule = t; ++ s.stream_restore_rule = QString::fromUtf8(t); + + translateMasksAndMaps(s); + +@@ -370,22 +374,24 @@ + return; + } + +- QString prefix = QString("%1: ").arg(i18n("Unknown Application")); ++ QString appname = i18n("Unknown Application"); + if (clients.contains(i->client)) +- prefix = QString("%1: ").arg(clients[i->client]); ++ appname = clients[i->client]; + ++ QString prefix = QString("%1: ").arg(appname); ++ + devinfo s; + s.index = i->index; + s.device_index = i->source; + s.description = prefix + QString::fromUtf8(i->name); +- s.name = QString("stream:") + i->index; ++ s.name = QString("stream:") + QString::number(i->index); //appname.replace(' ', '_').toLower(); + s.icon_name = getIconNameFromProplist(i->proplist); + //s.volume = i->volume; + s.volume = captureDevices[i->source].volume; + s.channel_map = i->channel_map; + //s.mute = !!i->mute; + s.mute = captureDevices[i->source].mute; +- s.stream_restore_rule = pa_proplist_gets(i->proplist, "module-stream-restore.id"); ++ s.stream_restore_rule = QString::fromUtf8(pa_proplist_gets(i->proplist, "module-stream-restore.id")); + + translateMasksAndMaps(s); + +@@ -407,7 +413,7 @@ + } + + +-static devinfo create_role_devinfo(const char* name) { ++static devinfo create_role_devinfo(QString name) { + + Q_ASSERT(s_RestoreRules.contains(name)); + +@@ -436,9 +442,10 @@ + + if (eol > 0) { + dec_outstanding(c); ++ + // Special case: ensure that our media events exists. + // On first login by a new users, this wont be in our database so we should create it. +- if (!outputRoles.contains(PA_INVALID_INDEX)) { ++ if (!s_RestoreRules.contains(KMIXPA_EVENT_KEY)) { + // Create a fake rule + restoreRule rule; + rule.channel_map.channels = 1; +@@ -447,37 +454,56 @@ + rule.volume.values[0] = PA_VOLUME_NORM; + rule.mute = false; + rule.device = ""; +- s_RestoreRules["sink-input-by-media-role:event"] = rule; ++ s_RestoreRules[KMIXPA_EVENT_KEY] = rule; ++ kDebug(67100) << "Initialising restore rule for new user: " << i18n("Event Sounds"); ++ } + +- devinfo s = create_role_devinfo("sink-input-by-media-role:event"); +- outputRoles[s.index] = s; +- kDebug(67100) << "Initialising restore rule for new user: " << s.description; ++ if (s_mixers.contains(KMIXPA_APP_PLAYBACK)) { ++ // If we have rules, it will be created below... but if no rules ++ // then we add it here. ++ if (!outputRoles.contains(PA_INVALID_INDEX)) { ++ devinfo s = create_role_devinfo(KMIXPA_EVENT_KEY); ++ outputRoles[s.index] = s; + +- if (s_mixers.contains(KMIXPA_APP_PLAYBACK)) + s_mixers[KMIXPA_APP_PLAYBACK]->addWidget(s.index); ++ } ++ ++ s_mixers[KMIXPA_APP_PLAYBACK]->triggerUpdate(); + } + +- if (s_mixers.contains(KMIXPA_APP_PLAYBACK)) +- s_mixers[KMIXPA_APP_PLAYBACK]->triggerUpdate(); + return; + } + +- kDebug(67100) << "Got some info about restore rule: " << i->name << i->device; ++ ++ QString name = QString::fromUtf8(i->name); ++ kDebug(67100) << QString("Got some info about restore rule: '%1' (Device: %2)").arg(name).arg(i->device ? i->device : "None"); + restoreRule rule; + rule.channel_map = i->channel_map; + rule.volume = i->volume; + rule.mute = !!i->mute; + rule.device = i->device; +- s_RestoreRules[i->name] = rule; + +- // We only want to know about Sound Events for now... +- if (strcmp(i->name, "sink-input-by-media-role:event") == 0) { +- devinfo s = create_role_devinfo(i->name); +- bool is_new = !outputRoles.contains(s.index); +- outputRoles[s.index] = s; ++ if (rule.channel_map.channels < 1 && name == KMIXPA_EVENT_KEY) { ++ // Stream restore rules may not have valid volumes/channel maps (as these are optional) ++ // but we need a valid volume+channelmap for our events sounds so fix it up. ++ rule.channel_map.channels = 1; ++ rule.channel_map.map[0] = PA_CHANNEL_POSITION_MONO; ++ rule.volume.channels = 1; ++ rule.volume.values[0] = PA_VOLUME_NORM; ++ } + +- if (is_new && s_mixers.contains(KMIXPA_APP_PLAYBACK)) +- s_mixers[KMIXPA_APP_PLAYBACK]->addWidget(s.index); ++ s_RestoreRules[name] = rule; ++ ++ if (s_mixers.contains(KMIXPA_APP_PLAYBACK)) { ++ // We only want to know about Sound Events for now... ++ if (name == KMIXPA_EVENT_KEY) { ++ devinfo s = create_role_devinfo(name); ++ bool is_new = !outputRoles.contains(s.index); ++ outputRoles[s.index] = s; ++ ++ if (is_new) ++ s_mixers[KMIXPA_APP_PLAYBACK]->addWidget(s.index); ++ } + } + } + +@@ -788,7 +814,6 @@ + Volume v(dev.chanMask, PA_VOLUME_NORM, PA_VOLUME_MUTED, true, false); + setVolumeFromPulse(v, dev); + MixDevice* md = new MixDevice( _mixer, dev.name, dev.description, dev.icon_name, ms); +- md->setEthereal(true); + md->addPlaybackVolume(v); + md->setMuted(dev.mute); + m_mixDevices.append(md); +@@ -1095,10 +1120,10 @@ + { + restoreRule &rule = s_RestoreRules[iter->stream_restore_rule]; + pa_ext_stream_restore_info info; +- info.name = iter->stream_restore_rule.toAscii().constData(); ++ info.name = iter->stream_restore_rule.toUtf8().constData(); + info.channel_map = rule.channel_map; + info.volume = genVolumeForPulse(*iter, md->playbackVolume()); +- info.device = rule.device.isEmpty() ? NULL : rule.device.toAscii().constData(); ++ info.device = rule.device.isEmpty() ? NULL : rule.device.toUtf8().constData(); + info.mute = (md->isMuted() ? 1 : 0); + + pa_operation* o; +@@ -1153,13 +1178,13 @@ + + // Lookup the stream index. + uint32_t stream_index = PA_INVALID_INDEX; +- const char* stream_restore_rule = NULL; ++ QString stream_restore_rule = ""; + devmap::iterator iter; + devmap *map = get_widget_map(m_devnum); + for (iter = map->begin(); iter != map->end(); ++iter) { + if (iter->name == id) { + stream_index = iter->index; +- stream_restore_rule = iter->stream_restore_rule.isEmpty() ? NULL : iter->stream_restore_rule.toAscii().constData(); ++ stream_restore_rule = iter->stream_restore_rule; + break; + } + } +@@ -1171,12 +1196,12 @@ + + if (destId.isEmpty()) { + // We want to remove any specific device in the stream restore rule. +- if (!stream_restore_rule || !s_RestoreRules.contains(stream_restore_rule)) { ++ if (stream_restore_rule.isEmpty() || !s_RestoreRules.contains(stream_restore_rule)) { + kWarning(67100) << "Mixer_PULSE::moveStream(): Trying to set Automatic on a stream with no rule"; + } else { + restoreRule &rule = s_RestoreRules[stream_restore_rule]; + pa_ext_stream_restore_info info; +- info.name = stream_restore_rule; ++ info.name = stream_restore_rule.toUtf8().constData(); + info.channel_map = rule.channel_map; + info.volume = rule.volume; + info.device = NULL; +@@ -1192,12 +1217,12 @@ + } else { + pa_operation* o; + if (KMIXPA_APP_PLAYBACK == m_devnum) { +- if (!(o = pa_context_move_sink_input_by_name(s_context, stream_index, destId.toAscii().constData(), NULL, NULL))) { ++ if (!(o = pa_context_move_sink_input_by_name(s_context, stream_index, destId.toUtf8().constData(), NULL, NULL))) { + kWarning(67100) << "pa_context_move_sink_input_by_name() failed"; + return false; + } + } else { +- if (!(o = pa_context_move_source_output_by_name(s_context, stream_index, destId.toAscii().constData(), NULL, NULL))) { ++ if (!(o = pa_context_move_source_output_by_name(s_context, stream_index, destId.toUtf8().constData(), NULL, NULL))) { + kWarning(67100) << "pa_context_move_source_output_by_name() failed"; + return false; + } |