summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHarald Sitter <sitter@kde.org>2012-09-13 20:11:49 (GMT)
committerHarald Sitter <sitter@kde.org>2012-09-13 20:11:49 (GMT)
commitd1344b63ded3b53dff44794f8e17e67ca530de9e (patch)
tree8d4a303f9211e772e1eae3b19acb6835b1435b2d
parentd6ff1b0cc3293a89b3f01a9b7606450e6404aaaf (diff)
implement runtime KSNI updates
previously kmix would throw away the KSNI and completely recreate it to pick up mixer changes. incidentally enough doing that triggers repaints and rescaling in plasma leading to utterly silly flickering. paritcularly since pulseaudio stream changes (e.g. a track change in amarok) would cause such an "update" you'd have a steady flow of flickering systray the situation was resolved by introducing a MetaMixer in the DockWidget. MetaMixer behaves like an abstraction wrapper around the actual Mixer. it replicates the necessary interfaces/signals/slots and internally controls the wiring to the actual mixer. that way the dockwidget can connect() once to the metamixer signals while internally the mixer might be constantly changing. then when an update is required the new update() function is called, which calls reset() on the metamixer, which rewires against the new master mixer and then automatically triggers UI updates
-rw-r--r--apps/kmix.cpp21
-rw-r--r--gui/kmixdockwidget.cpp142
-rw-r--r--gui/kmixdockwidget.h35
3 files changed, 99 insertions, 99 deletions
diff --git a/apps/kmix.cpp b/apps/kmix.cpp
index 6bc26b4..46707ee 100644
--- a/apps/kmix.cpp
+++ b/apps/kmix.cpp
@@ -313,20 +313,23 @@ void KMixWindow::recreateDockWidget()
*/
bool KMixWindow::updateDocking()
{
- // delete old dock widget
- if (m_dockWidget)
- {
- // If this is called during a master control change, the dock widget is currently active, so we use deleteLater().
- m_dockWidget->deleteLater();
- m_dockWidget = 0L;
- }
+ kDebug();
if ( m_showDockWidget == false || Mixer::mixers().count() == 0 ) {
+ if (m_dockWidget) { // Config update: we are not supposed to have one, but we have one.
+ m_dockWidget->deleteLater();
+ m_dockWidget = 0;
+ }
return false;
}
- m_dockWidget = new KMixDockWidget( this, m_volumeWidget ); // Could be optimized, by refreshing instead of recreating.
- connect(m_dockWidget, SIGNAL(newMasterSelected()), SLOT(saveConfig()) );
+ if (!m_dockWidget) {
+ m_dockWidget = new KMixDockWidget( this, m_volumeWidget ); // Could be optimized, by refreshing instead of recreating.
+ connect(m_dockWidget, SIGNAL(newMasterSelected()), SLOT(saveConfig()) );
+ } else {
+ m_dockWidget->update();
+ }
+
return true;
}
diff --git a/gui/kmixdockwidget.cpp b/gui/kmixdockwidget.cpp
index d448a10..1d21e1f 100644
--- a/gui/kmixdockwidget.cpp
+++ b/gui/kmixdockwidget.cpp
@@ -25,24 +25,13 @@
#include <kaction.h>
#include <klocale.h>
-#include <kapplication.h>
#include <kmenu.h>
-#include <kurl.h>
-#include <kglobalsettings.h>
-#include <kdialog.h>
-#include <kiconloader.h>
#include <kdebug.h>
#include <kwindowsystem.h>
#include <kactioncollection.h>
#include <ktoggleaction.h>
-#include <qapplication.h>
-#include <qcursor.h>
#include <QDesktopWidget>
-#include <QMouseEvent>
-
-#ifdef Q_WS_X11
-#include <fixx11h.h>
-#endif
+#include <QApplication>
#include "gui/dialogselectmaster.h"
#include "apps/kmix.h"
@@ -51,9 +40,17 @@
#include "core/mixertoolbox.h"
#include "gui/viewdockareapopup.h"
+void MetaMixer::reset()
+{
+ disconnect(m_mixer, SIGNAL(controlChanged()), this, SIGNAL(controlChanged()));
+ m_mixer = Mixer::getGlobalMasterMixer();
+ m_mixer->readSetFromHWforceUpdate();
+ connect(m_mixer, SIGNAL(controlChanged()), this, SIGNAL(controlChanged()));
+ emit controlChanged(); // Triggers UI updates accordingly
+}
+
KMixDockWidget::KMixDockWidget(KMixWindow* parent, bool volumePopup)
: KStatusNotifierItem(parent)
- // : KStatusNotifierItem(0)
, _oldToolTipValue(-1)
, _oldPixmapType('-')
, _volumePopup(volumePopup)
@@ -64,23 +61,15 @@ KMixDockWidget::KMixDockWidget(KMixWindow* parent, bool volumePopup)
setTitle(i18n( "Volume Control"));
setCategory(Hardware);
setStatus(Active);
- m_mixer = Mixer::getGlobalMasterMixer(); // ugly, but we'll live with that for now
+
+ m_metaMixer.reset();
createMasterVolWidget();
createActions();
+
connect(this, SIGNAL(scrollRequested(int,Qt::Orientation)), this, SLOT(trayWheelEvent(int,Qt::Orientation)));
connect(this, SIGNAL(secondaryActivateRequested(QPoint)), this, SLOT(dockMute()));
- bool NO_MENU_ANYMORE = true;
-
- if ( NO_MENU_ANYMORE )
- {
- connect(contextMenu(), SIGNAL(aboutToShow()), this, SLOT(contextMenuAboutToShow()));
- }
- else
- {
- connect(this, SIGNAL(activateRequested(bool,QPoint)), this, SLOT(activateMenuOrWindow(bool,QPoint)));
- connect(contextMenu(), SIGNAL(aboutToShow()), this, SLOT(contextMenuAboutToShow()));
- }
+ connect(contextMenu(), SIGNAL(aboutToShow()), this, SLOT(contextMenuAboutToShow()));
#ifdef __GNUC__
#warning minimizeRestore usage is currently slightly broken in KMIx. This should be fixed before doing a release.
@@ -98,56 +87,50 @@ KMixDockWidget::KMixDockWidget(KMixWindow* parent, bool volumePopup)
_volWA->setDefaultWidget(_referenceWidget2);
_referenceWidget->addAction(_volWA);
- connect( m_mixer, SIGNAL(controlChanged()), _referenceWidget2, SLOT(refreshVolumeLevels()) );
+ connect( &m_metaMixer, SIGNAL(controlChanged()), _referenceWidget2, SLOT(refreshVolumeLevels()) );
//setAssociatedWidget(_referenceWidget);
//setAssociatedWidget(_referenceWidget); // If you use the popup, associate that instead of the MainWindow
-
- //setContextMenu(_referenceWidget2);
- }
- else {
+
+ //setContextMenu(_referenceWidget2);
+ } else {
_volWA = 0;
_referenceWidget = 0;
}
}
-
KMixDockWidget::~KMixDockWidget()
{
// Note: deleting _volWA also deletes its associated ViewDockAreaPopup (_referenceWidget) and prevents the
// action to be left with a dangling pointer.
// cesken: I adapted the patch from https://bugs.kde.org/show_bug.cgi?id=220621#c27 to branch /branches/work/kmix
delete _volWA;
-
}
void KMixDockWidget::createActions()
{
- QMenu *menu = contextMenu();
-
- shared_ptr<MixDevice> md = Mixer::getGlobalMasterMD();
- if ( md.get() != 0 && md->playbackVolume().hasSwitch() )
- {
- // Put "Mute" selector in context menu
- KToggleAction *action = actionCollection()->add<KToggleAction>( "dock_mute" );
- action->setText( i18n( "M&ute" ) );
- connect(action, SIGNAL(triggered(bool)), SLOT(dockMute()));
+ QMenu *menu = contextMenu();
+
+ shared_ptr<MixDevice> md = Mixer::getGlobalMasterMD();
+ if ( md.get() != 0 && md->playbackVolume().hasSwitch() ) {
+ // Put "Mute" selector in context menu
+ KToggleAction *action = actionCollection()->add<KToggleAction>( "dock_mute" );
+ action->setText( i18n( "M&ute" ) );
+ connect(action, SIGNAL(triggered(bool)), SLOT(dockMute()));
+ menu->addAction( action );
+ }
+
+ // Put "Select Master Channel" dialog in context menu
+ QAction *action = actionCollection()->addAction( "select_master" );
+ action->setText( i18n("Select Master Channel...") );
+ action->setEnabled(m_metaMixer.hasMixer());
+ connect(action, SIGNAL(triggered(bool)), SLOT(selectMaster()));
menu->addAction( action );
-}
- // Put "Select Master Channel" dialog in context menu
- if ( m_mixer != 0 ) {
- QAction *action = actionCollection()->addAction( "select_master" );
- action->setText( i18n("Select Master Channel...") );
- connect(action, SIGNAL(triggered(bool)), SLOT(selectMaster()));
- menu->addAction( action );
- }
- //Context menu entry to access phonon settings
- menu->addAction(_kmixMainWindow->actionCollection()->action("launch_kdesoundsetup"));
+ //Context menu entry to access phonon settings
+ menu->addAction(_kmixMainWindow->actionCollection()->action("launch_kdesoundsetup"));
}
-
-void
-KMixDockWidget::createMasterVolWidget()
+void KMixDockWidget::createMasterVolWidget()
{
// Reset flags, so that the dock icon will be reconstructed
_oldToolTipValue = -1;
@@ -162,34 +145,22 @@ KMixDockWidget::createMasterVolWidget()
}
// create devices
- m_mixer->readSetFromHWforceUpdate(); // after changing the master device, make sure to re-read (otherwise no "changed()" signals might get sent by the Mixer
- /* With the recently introduced QSocketNotifier stuff, we can't rely on regular timer updates
- any longer. Also the readSetFromHWforceUpdate() won't be enough. As a workaround, we trigger
- all "repaints" manually here.
- The call to m_mixer->readSetFromHWforceUpdate() is most likely superfluous, even if we don't use QSocketNotifier (e.g. in backends OSS, Solaris, ...)
- */
setVolumeTip();
updatePixmap();
- /* We are setting up 3 connections:
- * Refreshig the _dockAreaPopup (not anymore necessary, because ViewBase already does it)
- * Refreshing the Tooltip
- * Refreshing the Icon
- */
- // connect( m_mixer, SIGNAL(controlChanged()), _dockAreaPopup, SLOT(refreshVolumeLevels()) );
- connect( m_mixer, SIGNAL(controlChanged()), this, SLOT(setVolumeTip()) );
- connect( m_mixer, SIGNAL(controlChanged()), this, SLOT(updatePixmap()) );
+
+ connect( &m_metaMixer, SIGNAL(controlChanged()), this, SLOT(setVolumeTip()) );
+ connect( &m_metaMixer, SIGNAL(controlChanged()), this, SLOT(updatePixmap()) );
}
void KMixDockWidget::selectMaster()
{
- DialogSelectMaster* dsm = new DialogSelectMaster(m_mixer);
+ DialogSelectMaster* dsm = new DialogSelectMaster(m_metaMixer.mixer());
dsm->setAttribute(Qt::WA_DeleteOnClose, true);
connect ( dsm, SIGNAL(newMasterSelected(QString&,QString&)), SLOT(handleNewMaster(QString&,QString&)) );
connect ( dsm, SIGNAL(newMasterSelected(QString&,QString&)), SIGNAL(newMasterSelected()) );
dsm->show();
}
-
void KMixDockWidget::handleNewMaster(QString& /*mixerID*/, QString& /*control_id*/)
{
/* When a new master is selected, we will need to destroy *this instance of KMixDockWidget.
@@ -201,11 +172,16 @@ void KMixDockWidget::handleNewMaster(QString& /*mixerID*/, QString& /*control_id
_kmixMainWindow->updateDocking();
}
+void KMixDockWidget::update()
+{
+ m_metaMixer.reset();
+ actionCollection()->action(QLatin1String("select_master"))->setEnabled(m_metaMixer.hasMixer());
+}
void
KMixDockWidget::setVolumeTip()
{
- shared_ptr<MixDevice> md = Mixer::getGlobalMasterMD();
+ shared_ptr<MixDevice> md = Mixer::getGlobalMasterMD();
QString tip = "";
int newToolTipValue = 0;
@@ -283,14 +259,6 @@ KMixDockWidget::updatePixmap()
_oldPixmapType = newPixmapType;
}
-
-
-void KMixDockWidget::activateMenuOrWindow(bool val, const QPoint &pos)
-{
- kDebug() << "activateMenuOrWindow: " << val << "," << pos;
-}
-
-
void KMixDockWidget::activate(const QPoint &pos)
{
kDebug() << "Activate at " << pos;
@@ -304,12 +272,12 @@ void KMixDockWidget::activate(const QPoint &pos)
kDebug() << "Use default KStatusNotifierItem behavior";
setAssociatedWidget(_kmixMainWindow);
// KStatusNotifierItem::activate(pos);
- KStatusNotifierItem::activate();
+ KStatusNotifierItem::activate();
return;
}
KMenu* dockAreaPopup =_referenceWidget; // TODO Refactor to use _referenceWidget directly
- kDebug() << "Skip default KStatusNotifierItkdebem behavior";
+ kDebug() << "Skip default KStatusNotifierItem behavior";
if ( dockAreaPopup->isVisible() ) {
dockAreaPopup->hide();
kDebug() << "dap is visible => hide and return";
@@ -407,12 +375,12 @@ KMixDockWidget::trayWheelEvent(int delta,Qt::Orientation wheelOrientation)
void
KMixDockWidget::dockMute()
{
- shared_ptr<MixDevice> md = Mixer::getGlobalMasterMD();
- if ( md )
- {
- md->toggleMute();
- md->mixer()->commitVolumeChange( md );
- }
+ shared_ptr<MixDevice> md = Mixer::getGlobalMasterMD();
+ if ( md )
+ {
+ md->toggleMute();
+ md->mixer()->commitVolumeChange( md );
+ }
}
void
diff --git a/gui/kmixdockwidget.h b/gui/kmixdockwidget.h
index 7160961..2767298 100644
--- a/gui/kmixdockwidget.h
+++ b/gui/kmixdockwidget.h
@@ -24,7 +24,6 @@
#define KMIXDOCKWIDGET_H
class QString;
-#include <QWidget>
class QWidgetAction;
#include <kstatusnotifieritem.h>
@@ -33,6 +32,35 @@ class Mixer;
class ViewDockAreaPopup;
class Volume;
+/**
+ * @brief The MetaMixer class provides a solid wrapper around a possible changing mixer.
+ *
+ * The primay use of this class is to provide one instance to connect slots to
+ * while the underlying object that triggers the signals can be changing.
+ * Additionally it nicely hides the rewiring logic that is going on in the back.
+ */
+class MetaMixer : public QObject
+{
+ Q_OBJECT
+public:
+ MetaMixer() : m_mixer(0) {}
+
+ /**
+ * @brief rewires against current master mixer
+ * @note this also triggers all signals to ensure UI updates are done accordingly
+ */
+ void reset();
+
+ Mixer *mixer() const { return m_mixer; }
+ bool hasMixer() const { return m_mixer; }
+
+signals:
+ void controlChanged();
+
+private:
+ Mixer *m_mixer;
+};
+
class KMixDockWidget : public KStatusNotifierItem
{
Q_OBJECT
@@ -46,6 +74,8 @@ class KMixDockWidget : public KStatusNotifierItem
void setErrorPixmap();
void ignoreNextEvent();
+ void update();
+
signals:
void newMasterSelected();
@@ -69,7 +99,7 @@ class KMixDockWidget : public KStatusNotifierItem
char _oldPixmapType;
bool _volumePopup;
KMixWindow* _kmixMainWindow;
- Mixer *m_mixer;
+ MetaMixer m_metaMixer;
bool _contextMenuWasOpen;
@@ -81,7 +111,6 @@ class KMixDockWidget : public KStatusNotifierItem
void selectMaster();
void handleNewMaster(QString& soundcard_id, QString& channel_id);
void contextMenuAboutToShow();
- void activateMenuOrWindow(bool, const QPoint &);
};
#endif