mirror of
https://bitbucket.org/smil3y/kde-extraapps.git
synced 2025-02-24 19:02:53 +00:00

since Katie requires compiler with C++11 support the shared pointer checks could be ommited Signed-off-by: Ivailo Monev <xakepa10@laimg.moc>
422 lines
14 KiB
C++
422 lines
14 KiB
C++
/*
|
|
* KMix -- KDE's full featured mini mixer
|
|
*
|
|
*
|
|
* Copyright (C) 1996-2004 Christian Esken <esken@kde.org>
|
|
*
|
|
* 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 "gui/viewdockareapopup.h"
|
|
|
|
// Qt
|
|
#include <qevent.h>
|
|
#include <qframe.h>
|
|
#include <QGridLayout>
|
|
#include <QLayoutItem>
|
|
#include <QPushButton>
|
|
#include <QSizePolicy>
|
|
|
|
// KDE
|
|
#include <kaction.h>
|
|
#include <kapplication.h>
|
|
#include <kdebug.h>
|
|
#include <kdialog.h>
|
|
#include <klocale.h>
|
|
#include <kwindowsystem.h>
|
|
|
|
// KMix
|
|
#include "apps/kmix.h"
|
|
#include "core/mixer.h"
|
|
#include "core/ControlManager.h"
|
|
#include "core/GlobalConfig.h"
|
|
#include "gui/dialogchoosebackends.h"
|
|
#include "gui/guiprofile.h"
|
|
#include "gui/kmixprefdlg.h"
|
|
#include "gui/mdwslider.h"
|
|
|
|
// Restore volume button feature is incomplete => disabling for KDE 4.10
|
|
#undef RESTORE_VOLUME_BUTTON
|
|
|
|
QString ViewDockAreaPopup::InternedString_Star = QString("*");
|
|
QString ViewDockAreaPopup::InternedString_Subcontrols = QString("pvolume,cvolume,pswitch,cswitch");
|
|
ProfControl ViewDockAreaPopup::MatchAllForSoundMenu = ProfControl(ViewDockAreaPopup::InternedString_Star, ViewDockAreaPopup::InternedString_Subcontrols);
|
|
|
|
ViewDockAreaPopup::ViewDockAreaPopup(QWidget* parent, QString id, ViewBase::ViewFlags vflags, QString guiProfileId,
|
|
KMixWindow *dockW) :
|
|
ViewBase(parent, id, 0, vflags, guiProfileId), _kmixMainWindow(dockW)
|
|
{
|
|
resetRefs();
|
|
setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
|
|
|
foreach ( Mixer* mixer, Mixer::mixers() )
|
|
{
|
|
// Adding all mixers, as we potentially want to show all master controls
|
|
addMixer(mixer);
|
|
// The list will be redone in _setMixSet() with the actual Mixer instances to use
|
|
}
|
|
|
|
restoreVolumeIcon = new KIcon(QLatin1String("quickopen-file"));
|
|
createDeviceWidgets();
|
|
|
|
// Register listeners for all mixers
|
|
ControlManager::instance().addListener(
|
|
QString(), // all mixers
|
|
(ControlChangeType::Type) (ControlChangeType::GUI | ControlChangeType::ControlList | ControlChangeType::Volume
|
|
| ControlChangeType::MasterChanged), this, QString("ViewDockAreaPopup"));
|
|
}
|
|
|
|
|
|
ViewDockAreaPopup::~ViewDockAreaPopup()
|
|
{
|
|
ControlManager::instance().removeListener(this);
|
|
delete _layoutMDW;
|
|
delete restoreVolumeIcon;
|
|
// Hint: optionsLayout and "everything else" is deleted when "delete _layoutMDW" cascades down
|
|
}
|
|
|
|
|
|
void ViewDockAreaPopup::controlsChange(int changeType)
|
|
{
|
|
ControlChangeType::Type type = ControlChangeType::fromInt(changeType);
|
|
switch (type )
|
|
{
|
|
case ControlChangeType::ControlList:
|
|
case ControlChangeType::MasterChanged:
|
|
createDeviceWidgets();
|
|
break;
|
|
case ControlChangeType::GUI:
|
|
updateGuiOptions();
|
|
break;
|
|
|
|
case ControlChangeType::Volume:
|
|
refreshVolumeLevels();
|
|
break;
|
|
|
|
default:
|
|
ControlManager::warnUnexpectedChangeType(type, this);
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
void ViewDockAreaPopup::wheelEvent ( QWheelEvent * e )
|
|
{
|
|
if ( _mdws.isEmpty() )
|
|
return;
|
|
|
|
// Pass wheel event from "border widget" to child
|
|
QApplication::sendEvent( _mdws.first(), e);
|
|
}
|
|
|
|
|
|
void ViewDockAreaPopup::configurationUpdate()
|
|
{
|
|
// TODO Do we still need configurationUpdate(). It was never implemented for ViewDockAreaPopup
|
|
}
|
|
|
|
// TODO Currently no right-click, as we have problems to get the ViewDockAreaPopup resized
|
|
void ViewDockAreaPopup::showContextMenu()
|
|
{
|
|
// no right-button-menu on "dock area popup"
|
|
return;
|
|
}
|
|
|
|
void ViewDockAreaPopup::resetRefs()
|
|
{
|
|
seperatorBetweenMastersAndStreams = 0;
|
|
separatorBetweenMastersAndStreamsInserted = false;
|
|
separatorBetweenMastersAndStreamsRequired = false;
|
|
configureViewButton = 0;
|
|
restoreVolumeButton1 = 0;
|
|
restoreVolumeButton2 = 0;
|
|
restoreVolumeButton3 = 0;
|
|
restoreVolumeButton4 = 0;
|
|
mainWindowButton = 0;
|
|
optionsLayout = 0;
|
|
_layoutMDW = 0;
|
|
}
|
|
|
|
void ViewDockAreaPopup::_setMixSet()
|
|
{
|
|
resetMdws();
|
|
|
|
if (optionsLayout != 0)
|
|
{
|
|
QLayoutItem *li2;
|
|
while ((li2 = optionsLayout->takeAt(0)))
|
|
delete li2;
|
|
}
|
|
// Hint : optionsLayout itself is deleted when "delete _layoutMDW" cascades down
|
|
|
|
if (_layoutMDW != 0)
|
|
{
|
|
QLayoutItem *li;
|
|
while ((li = _layoutMDW->takeAt(0)))
|
|
delete li;
|
|
}
|
|
|
|
/*
|
|
* Strangely enough, I cannot delete optionsLayout in a loop. I get a strange stacktrace:
|
|
*
|
|
Application: KMix (kmix), signal: Segmentation fault
|
|
[...]
|
|
#6 0x00007f9c9a282900 in QString::shared_null () from /usr/lib/x86_64-linux-gnu/libQtCore.so.4
|
|
#7 0x00007f9c9d4286b0 in ViewDockAreaPopup::_setMixSet (this=0x1272b60) at /home/chris/workspace/kmix-git-trunk/gui/viewdockareapopup.cpp:164
|
|
#8 0x00007f9c9d425700 in ViewBase::createDeviceWidgets (this=0x1272b60) at /home/chris/workspace/kmix-git-trunk/gui/viewbase.cpp:137
|
|
#9 0x00007f9c9d42845b in ViewDockAreaPopup::controlsChange (this=0x1272b60, changeType=2) at /home/chris/workspace/kmix-git-trunk/gui/viewdockareapopup.cpp:91
|
|
*/
|
|
// if ( optionsLayout != 0 )
|
|
// {
|
|
// QLayoutItem *li2;
|
|
// while ( ( li2 = optionsLayout->takeAt(0) ) ) // strangely enough, it crashes here
|
|
// delete li2;
|
|
// }
|
|
|
|
// --- Due to the strange crash, delete everything manually : START ---------------
|
|
// I am a bit confused why this doesn't crash. I moved the "optionsLayout->takeAt(0) delete" loop at the beginning,
|
|
// so the obejcts should already be deleted. ...
|
|
delete configureViewButton;
|
|
delete restoreVolumeButton1;
|
|
delete restoreVolumeButton2;
|
|
delete restoreVolumeButton3;
|
|
delete restoreVolumeButton4;
|
|
|
|
delete mainWindowButton;
|
|
delete seperatorBetweenMastersAndStreams;
|
|
// --- Due to the strange crash, delete everything manually : END ---------------
|
|
|
|
resetRefs();
|
|
setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
|
|
|
/*
|
|
* BKO 299754: Looks like I need to explicitly delete layout(). I have no idea why
|
|
* "delete _layoutMDW" is not enough, as that is supposed to be the layout
|
|
* of this ViewDockAreaPopup
|
|
* (Hint: it might have been 0 already. Nowadays it is definitely, see #resetRefs())
|
|
*/
|
|
delete layout(); // BKO 299754
|
|
_layoutMDW = new QGridLayout(this);
|
|
_layoutMDW->setSpacing(KDialog::spacingHint());
|
|
_layoutMDW->setMargin(0);
|
|
//_layoutMDW->setSizeConstraint(QLayout::SetMinimumSize);
|
|
_layoutMDW->setSizeConstraint(QLayout::SetMaximumSize);
|
|
_layoutMDW->setObjectName(QLatin1String("KmixPopupLayout"));
|
|
setLayout(_layoutMDW);
|
|
|
|
// Adding all mixers, as we potentially want to show all master controls. Due to hotplugging
|
|
// we have to redo the list on each _setMixSet() (instead of setting it once in the Constructor)
|
|
_mixers.clear();
|
|
|
|
QSet<QString> preferredMixersForSoundmenu = GlobalConfig::instance().getMixersForSoundmenu();
|
|
// kDebug() << "Launch with " << preferredMixersForSoundmenu;
|
|
foreach ( Mixer* mixer, Mixer::mixers() )
|
|
{
|
|
bool useMixer = preferredMixersForSoundmenu.isEmpty() || preferredMixersForSoundmenu.contains(mixer->id());
|
|
if (useMixer)
|
|
addMixer(mixer);
|
|
}
|
|
|
|
// The following loop is for the case when everything gets filtered out. We "reset" to show everything then.
|
|
// Hint: Filtering everything out can only be an "accident", e.g. when restarting KMix with changed hardware or
|
|
// backends.
|
|
if ( _mixers.isEmpty() )
|
|
{
|
|
foreach ( Mixer* mixer, Mixer::mixers() )
|
|
{
|
|
addMixer(mixer);
|
|
}
|
|
}
|
|
|
|
|
|
// A loop that adds the Master control of each card
|
|
foreach ( Mixer* mixer, _mixers )
|
|
{
|
|
// kDebug() << "ADD? mixerId=" << mixer->id();
|
|
std::shared_ptr<MixDevice>dockMD = mixer->getLocalMasterMD();
|
|
if ( !dockMD && mixer->size() > 0 )
|
|
{
|
|
// If we have no dock device yet, we will take the first available mixer device.
|
|
dockMD = (*mixer)[0];
|
|
}
|
|
if ( dockMD )
|
|
{
|
|
// kDebug() << "ADD? mixerId=" << mixer->id() << ", md=" << dockMD->id();
|
|
if ( !dockMD->isApplicationStream() && dockMD->playbackVolume().hasVolume())
|
|
{
|
|
// kDebug() << "ADD? mixerId=" << mixer->id() << ", md=" << dockMD->id() << ": YES";
|
|
// don't add application streams here. They are handled below, so
|
|
// we make sure to not add them twice
|
|
_mixSet.append(dockMD);
|
|
}
|
|
}
|
|
} // loop over all cards
|
|
|
|
// Add all application streams
|
|
foreach ( Mixer* mixer2 , _mixers )
|
|
{
|
|
foreach ( std::shared_ptr<MixDevice> md, mixer2->getMixSet() )
|
|
{
|
|
if (md->isApplicationStream())
|
|
{
|
|
_mixSet.append(md);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
QWidget* ViewDockAreaPopup::add(std::shared_ptr<MixDevice> md)
|
|
{
|
|
bool vertical = (GlobalConfig::instance().data.getTraypopupOrientation() == Qt::Vertical); // I am wondering whether using vflags for this would still make sense
|
|
/*
|
|
QString dummyMatchAll("*");
|
|
QString matchAllPlaybackAndTheCswitch("pvolume,cvolume,pswitch,cswitch");
|
|
// Leak | relevant | pctl Each time a stream is added, a new ProfControl gets created.
|
|
// It cannot be deleted in ~MixDeviceWidget, as ProfControl* ownership is not consistent.
|
|
// here a new pctl is created (could be deleted), but in ViewSliders the ProcControl is taken from the
|
|
// MixDevice, which in turn uses it from the GUIProfile.
|
|
// Summarizing: ProfControl* is either owned by the GUIProfile or created new (ownership unclear).
|
|
// Hint: dummyMatchAll and matchAllPlaybackAndTheCswitch leak together with pctl
|
|
ProfControl *pctl = new ProfControl( dummyMatchAll, matchAllPlaybackAndTheCswitch);
|
|
*/
|
|
|
|
if ( !md->isApplicationStream() )
|
|
{
|
|
separatorBetweenMastersAndStreamsRequired = true;
|
|
}
|
|
if ( !separatorBetweenMastersAndStreamsInserted && separatorBetweenMastersAndStreamsRequired && md->isApplicationStream() )
|
|
{
|
|
// First application stream => add separator
|
|
separatorBetweenMastersAndStreamsInserted = true;
|
|
|
|
int sliderColumn = vertical ? _layoutMDW->columnCount() : _layoutMDW->rowCount();
|
|
int row = vertical ? 0 : sliderColumn;
|
|
int col = vertical ? sliderColumn : 0;
|
|
seperatorBetweenMastersAndStreams = new QFrame(this);
|
|
if (vertical)
|
|
seperatorBetweenMastersAndStreams->setFrameStyle(QFrame::VLine);
|
|
else
|
|
seperatorBetweenMastersAndStreams->setFrameStyle(QFrame::HLine);
|
|
_layoutMDW->addWidget( seperatorBetweenMastersAndStreams, row, col );
|
|
//_layoutMDW->addItem( new QSpacerItem( 5, 5 ), row, col );
|
|
}
|
|
|
|
ProfControl *pctl = &MatchAllForSoundMenu;
|
|
MixDeviceWidget *mdw = new MDWSlider(
|
|
md, // only 1 device.
|
|
true, // Show Mute LE
|
|
true, // Show Record LED
|
|
true, // Include Mixer Name
|
|
false, // Small
|
|
vertical ? Qt::Vertical : Qt::Horizontal,
|
|
this, // parent
|
|
this // NOT ANYMORE!!! -> Is "NULL", so that there is no RMB-popup
|
|
, pctl
|
|
);
|
|
mdw->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
|
int sliderColumn = vertical ? _layoutMDW->columnCount() : _layoutMDW->rowCount();
|
|
//if (sliderColumn == 1 ) sliderColumn =0;
|
|
int row = vertical ? 0 : sliderColumn;
|
|
int col = vertical ? sliderColumn : 0;
|
|
|
|
_layoutMDW->addWidget( mdw, row, col );
|
|
|
|
//kDebug(67100) << "ADDED " << md->id() << " at column " << sliderColumn;
|
|
return mdw;
|
|
}
|
|
|
|
void ViewDockAreaPopup::constructionFinished()
|
|
{
|
|
// kDebug(67100) << "ViewDockAreaPopup::constructionFinished()\n";
|
|
|
|
mainWindowButton = new QPushButton(i18n("Mixer"), this);
|
|
mainWindowButton->setObjectName(QLatin1String("MixerPanel"));
|
|
connect(mainWindowButton, SIGNAL(clicked()), SLOT(showPanelSlot()));
|
|
|
|
configureViewButton = createConfigureViewButton();
|
|
|
|
optionsLayout = new QHBoxLayout();
|
|
optionsLayout->addWidget(mainWindowButton);
|
|
optionsLayout->addWidget(configureViewButton);
|
|
|
|
#ifdef RESTORE_VOLUME_BUTTON
|
|
restoreVolumeButton1 = createRestoreVolumeButton(1);
|
|
optionsLayout->addWidget( restoreVolumeButton1 ); // TODO enable only if user has saved a volume profile
|
|
|
|
// optionsLayout->addWidget( createRestoreVolumeButton(2) );
|
|
// optionsLayout->addWidget( createRestoreVolumeButton(3) );
|
|
// optionsLayout->addWidget( createRestoreVolumeButton(4) );
|
|
#endif
|
|
|
|
int sliderRow = _layoutMDW->rowCount();
|
|
_layoutMDW->addLayout(optionsLayout, sliderRow, 0, 1, _layoutMDW->columnCount());
|
|
|
|
updateGuiOptions();
|
|
|
|
_layoutMDW->update();
|
|
_layoutMDW->activate();
|
|
// kDebug() << "F layout()=" << layout() << ", _layoutMDW=" << _layoutMDW;
|
|
}
|
|
|
|
QPushButton* ViewDockAreaPopup::createRestoreVolumeButton ( int storageSlot )
|
|
{
|
|
QString buttonText = QString("%1").arg(storageSlot);
|
|
QPushButton* profileButton = new QPushButton(*restoreVolumeIcon, buttonText, this);
|
|
profileButton->setToolTip(i18n("Load volume profile %1").arg(storageSlot));
|
|
profileButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
|
return profileButton;
|
|
}
|
|
|
|
void ViewDockAreaPopup::refreshVolumeLevels()
|
|
{
|
|
foreach ( QWidget* qw, _mdws )
|
|
{
|
|
//kDebug() << "rvl: " << qw;
|
|
MixDeviceWidget* mdw = qobject_cast<MixDeviceWidget*>(qw);
|
|
if ( mdw != 0 ) mdw->update();
|
|
}
|
|
}
|
|
|
|
void ViewDockAreaPopup::configureView()
|
|
{
|
|
// Q_ASSERT( !pulseaudioPresent() );
|
|
|
|
// QSet<QString> currentlyActiveMixersInDockArea;
|
|
// foreach ( Mixer* mixer, _mixers )
|
|
// {
|
|
// currentlyActiveMixersInDockArea.insert(mixer->id());
|
|
// }
|
|
|
|
KMixPrefDlg* prefDlg = KMixPrefDlg::getInstance();
|
|
//prefDlg->setActiveMixersInDock(currentlyActiveMixersInDockArea);
|
|
prefDlg->switchToPage(KMixPrefDlg::PrefSoundMenu);
|
|
}
|
|
|
|
/**
|
|
* This gets activated whne a user clicks the "Mixer" PushButton in this popup.
|
|
*/
|
|
void ViewDockAreaPopup::showPanelSlot()
|
|
{
|
|
_kmixMainWindow->setVisible(true);
|
|
KWindowSystem::setOnDesktop(_kmixMainWindow->winId(), KWindowSystem::currentDesktop());
|
|
KWindowSystem::activateWindow(_kmixMainWindow->winId());
|
|
// This is only needed when the window is already visible.
|
|
static_cast<QWidget*>(parent())->hide();
|
|
}
|
|
|
|
#include "moc_viewdockareapopup.cpp"
|