SVN commit 1268580 by esken: Show and remove MPRIS2 Streams (Stream hotplugging) BUGS: 288637 M +6 -0 apps/kmix.cpp M +2 -0 apps/kmix.h M +41 -30 backends/mixer_mpris2.cpp M +3 -5 backends/mixer_mpris2.h M +1 -0 gui/kmixdockwidget.cpp M +14 -18 gui/viewbase.cpp M +9 -0 gui/viewdockareapopup.cpp M +6 -0 gui/viewdockareapopup.h --- trunk/KDE/kdemultimedia/kmix/apps/kmix.cpp #1268579:1268580 @@ -300,6 +300,12 @@ } +void KMixWindow::recreateDockWidget() +{ +// kDebug() << "recreate dock urgently requested"; + updateDocking(); +} + /** * Updates the docking icon by recreating it. * @returns Whether the docking succeeded. Failure usually means that there --- trunk/KDE/kdemultimedia/kmix/apps/kmix.h #1268579:1268580 @@ -94,6 +94,7 @@ void recreateGUI(bool saveConfig, const QString& mixerId, bool forceNewTab); void recreateGUIwithSavingView(); void recreateGUIwithoutSavingView(); + void recreateDockWidget(); void redrawMixer( const QString& mixer_ID ); void newMixerShown(int tabIndex); @@ -138,6 +139,7 @@ private: static QString getKmixctrlRcFilename(QString postfix); + private slots: void saveConfig(); void slotHWInfo(); --- trunk/KDE/kdemultimedia/kmix/backends/mixer_mpris2.cpp #1268579:1268580 @@ -43,7 +43,6 @@ Mixer_MPRIS2::Mixer_MPRIS2(Mixer *mixer, int device) : Mixer_Backend(mixer, device ) { - // run(); } @@ -53,7 +52,7 @@ return Mixer::ERR_OPEN; _mixer->setDynamic(); - run(); + addAllRunningPlayersAndInitHotplug(); return 0; } @@ -77,18 +76,22 @@ return mediaControl(id, "Next"); } -int Mixer_MPRIS2::mediaControl(QString id, QString commandName) +/** + * Sends a media control command to the given application. + * @param applicationId The MPRIS applicationId + */ +int Mixer_MPRIS2::mediaControl(QString applicationId, QString commandName) { - kDebug() << commandName << " " << id; + kDebug() << commandName << " " << applicationId; QList arg; // arg.append(QString("org.mpris.MediaPlayer2.Player")); // arg.append(QString("PlayPause")); - MPrisAppdata* mad = apps.value(id); + MPrisAppdata* mad = apps.value(applicationId); QDBusMessage msg = mad->playerIfc->callWithArgumentList(QDBus::NoBlock, commandName, arg); if ( msg.type() == QDBusMessage::ErrorMessage ) { - kError(67100) << "ERROR SET " << id << ": " << msg; + kError(67100) << "ERROR SET " << applicationId << ": " << msg; return Mixer::ERR_WRITE; } return 0; @@ -177,11 +180,12 @@ /** - * @brief Test method + * Adds all currently running players and then starts listening + * for changes (new players, and disappearing players).
* * @return int **/ -int Mixer_MPRIS2::run() +int Mixer_MPRIS2::addAllRunningPlayersAndInitHotplug() { QDBusConnection dbusConn = QDBusConnection::sessionBus(); if (! dbusConn.isConnected() ) @@ -192,8 +196,15 @@ return Mixer::ERR_OPEN; } - this->dbusConnPtr = &dbusConn; + // Start listening for new Mediaplayers + bool ret = dbusConn.connect("", QString("/org/freedesktop/DBus"), "org.freedesktop.DBus", "NameOwnerChanged", this, SLOT(newMediaPlayer(QString,QString,QString)) ); + kDebug() << "Start listening for new Mediaplayers: " << ret; + /* Here is a small concurrency issue. + * If new players appear between registeredServiceNames() below and the connect() above these players *might* show up doubled in KMix. + * There is no simple solution (reversing could have the problem of not-adding), so we live for now with it. + */ + QDBusReply repl = dbusConn.interface()->registeredServiceNames(); if ( repl.isValid() ) @@ -203,19 +214,24 @@ foreach ( s , result ) { if ( s.startsWith("org.mpris.MediaPlayer2") ) - getMprisControl(dbusConn, s); + addMprisControl(dbusConn, s); } } - // Start listening for new Mediaplayers - dbusConn.connect("", QString("/org/freedesktop/DBus"), "org.freedesktop.DBus", "NameOwnerChanged", this, SLOT(newMediaPlayer(QString,QString,QString)) ); return 0; } -void Mixer_MPRIS2::getMprisControl(QDBusConnection& conn, QString busDestination) +/** + * Add the MPRIS control designated by the DBUS busDestination + * to the internal apps list. + * + * @param conn An open connection to the DBUS Session Bus + * @param busDestination The DBUS busDestination, e.g. "org.mpris.MediaPlayer2.amarok" + */ +void Mixer_MPRIS2::addMprisControl(QDBusConnection& conn, QString busDestination) { int lastDot = busDestination.lastIndexOf('.'); QString id = ( lastDot == -1 ) ? busDestination : busDestination.mid(lastDot+1); @@ -287,29 +303,27 @@ +void Mixer_MPRIS2::notifyToReconfigureControls() +{ + QMetaObject::invokeMethod(this, + "controlsReconfigured", + Qt::QueuedConnection, + Q_ARG(QString, _mixer->id())); +} + /** - * This slot is a simple proxy that enriches the DBUS signal with our data, which especially contains the id of the MixDevice. + * Handles the hotplug of new MPRIS2 enabled Media Players */ void Mixer_MPRIS2::newMediaPlayer(QString name, QString oldOwner, QString newOwner) { - if (dbusConnPtr == 0) - { - kError() << "We see a new application is registering on DBUS, but we have no DBUS connection. This is most definitely weird."; - return; // No DBUS connection. We should never enter this SLOT at all - } - if ( name.startsWith("org.mpris.MediaPlayer2") ) { - kDebug() << "DO SOMETHING: " << name << "," << oldOwner << "," << newOwner; if ( oldOwner.isEmpty() && !newOwner.isEmpty()) { kDebug() << "Mediaplayer registers: " << name; QDBusConnection dbusConn = QDBusConnection::sessionBus(); - getMprisControl(dbusConn, name); - QMetaObject::invokeMethod(this, - "controlsReconfigured", - Qt::QueuedConnection, - Q_ARG(QString, _mixer->id())); + addMprisControl(dbusConn, name); + notifyToReconfigureControls(); } else if ( !oldOwner.isEmpty() && newOwner.isEmpty()) { @@ -318,10 +332,7 @@ QString id = ( lastDot == -1 ) ? name : name.mid(lastDot+1); apps.remove(id); m_mixDevices.removeById(id); - QMetaObject::invokeMethod(this, - "controlsReconfigured", - Qt::QueuedConnection, - Q_ARG(QString, _mixer->id())); + notifyToReconfigureControls(); } else { --- trunk/KDE/kdemultimedia/kmix/backends/mixer_mpris2.h #1268579:1268580 @@ -56,7 +56,7 @@ public: explicit Mixer_MPRIS2(Mixer *mixer, int device = -1 ); virtual ~Mixer_MPRIS2(); - void getMprisControl(QDBusConnection& conn, QString arg1); + void addMprisControl(QDBusConnection& conn, QString arg1); QString getDriverName(); virtual int open(); @@ -76,12 +76,10 @@ public slots: void volumeChanged(MPrisAppdata* mad, double); void newMediaPlayer(QString name, QString oldOwner, QString newOwner); - private: - int run(); + int addAllRunningPlayersAndInitHotplug(); + void notifyToReconfigureControls(); - QDBusConnection* dbusConnPtr; - static QString MPRIS_IFC2; QMap apps; }; --- trunk/KDE/kdemultimedia/kmix/gui/kmixdockwidget.cpp #1268579:1268580 @@ -95,6 +95,7 @@ _referenceWidget = new KMenu(parent); ViewDockAreaPopup* _referenceWidget2 = new ViewDockAreaPopup(_referenceWidget, "dockArea", Mixer::getGlobalMasterMixer(), 0, (GUIProfile*)0, parent); _referenceWidget2->createDeviceWidgets(); + connect(_referenceWidget2, SIGNAL(recreateMe()), _kmixMainWindow, SLOT(recreateDockWidget())); _volWA = new QWidgetAction(_referenceWidget); _volWA->setDefaultWidget(_referenceWidget2); --- trunk/KDE/kdemultimedia/kmix/gui/viewbase.cpp #1268579:1268580 @@ -145,23 +145,6 @@ void ViewBase::rebuildFromProfile() { emit rebuildGUI(); -/* - // Redo everything from scratch, as visibility and the order of the controls might have changed. - - // As the order of the controls is stored in the profile, we need - // to rebuild the _mixSet -kDebug() << "rebuild 1"; - _mixSet->clear(); -kDebug() << "rebuild 2"; - _mdws.clear(); -kDebug() << "rebuild 3"; - setMixSet(); -kDebug() << "rebuild 4"; - createDeviceWidgets(); -kDebug() << "rebuild 5"; - constructionFinished(); -kDebug() << "rebuild 6"; -*/ } @@ -215,7 +198,20 @@ void ViewBase::controlsReconfigured( const QString& mixer_ID ) { // TODO Search _mixers for the correct Mixer*. After that, remove _mixer instance variable - if ( _mixer->id() == mixer_ID ) + bool isRelevantMixer = (_mixer->id() == mixer_ID ); + // if (!isRelevantMixer) + // { + // foreach ( Mixer* mixer , _mixers) + // { + // if ( mixer->id() == mixer_ID ) + // { + // isRelevantMixer = true; + // break; + // } + // } + // } + + if (isRelevantMixer) { kDebug(67100) << "ViewBase::controlsReconfigured() " << mixer_ID << " is being redrawn (mixset contains: " << _mixSet->count() << ")"; setMixSet(); --- trunk/KDE/kdemultimedia/kmix/gui/viewdockareapopup.cpp #1268579:1268580 @@ -115,6 +115,15 @@ } + +void ViewDockAreaPopup::controlsReconfigured( const QString& mixer_ID ) +{ + kDebug(67100) << "RECONFIGURE AND RECREATE DOCK"; + ViewBase::controlsReconfigured(mixer_ID); + emit recreateMe(); +} + + QWidget* ViewDockAreaPopup::add(MixDevice *md) { QString dummyMatchAll("*"); --- trunk/KDE/kdemultimedia/kmix/gui/viewdockareapopup.h #1268579:1268580 @@ -52,9 +52,15 @@ QLayout* _layoutControls; QGridLayout* _layoutMDW; +public slots: + virtual void controlsReconfigured( const QString& mixer_ID ); private slots: void showPanelSlot(); +signals: + void recreateMe(); + + }; #endif