[kdebase-runtime] - pa speakersetup backport (courtesy of coling/mandriva) - hammer rpath from phonon_platform/kde.so

Rex Dieter rdieter at fedoraproject.org
Fri Oct 15 17:52:46 UTC 2010


commit 57c10a4327c3ad5bd8aed98d349ad2c1f9ea9a0b
Author: Rex Dieter <rdieter at fedoraproject.org>
Date:   Fri Oct 15 12:58:48 2010 -0500

    - pa speakersetup backport (courtesy of coling/mandriva)
    - hammer rpath from phonon_platform/kde.so

 kdebase-runtime-4.5-speakersetup.patch | 1318 ++++++++++++++++++++++++++++++++
 kdebase-runtime.spec                   |   19 +-
 2 files changed, 1336 insertions(+), 1 deletions(-)
---
diff --git a/kdebase-runtime-4.5-speakersetup.patch b/kdebase-runtime-4.5-speakersetup.patch
new file mode 100644
index 0000000..acd828a
--- /dev/null
+++ b/kdebase-runtime-4.5-speakersetup.patch
@@ -0,0 +1,1318 @@
+Index: runtime/phonon/kcm/testspeakerwidget.cpp
+===================================================================
+--- runtime/phonon/kcm/testspeakerwidget.cpp	(revision 0)
++++ runtime/phonon/kcm/testspeakerwidget.cpp	(revision 1154776)
+@@ -0,0 +1,194 @@
++/*  This file is part of the KDE project
++    Copyright (C) 2010 Colin Guthrie <cguthrie at mandriva.org>
++
++    This program is free software; you can redistribute it and/or modify
++    it under the terms of the GNU General Public License version 2
++    as published by the Free Software Foundation.
++
++    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 General Public License for more details.
++
++    You should have received a copy of the GNU 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 "testspeakerwidget.h"
++#include "speakersetup.h"
++#include <stdio.h>
++
++TestSpeakerWidget::TestSpeakerWidget(const pa_channel_position_t pos, ca_context *canberra, SpeakerSetup* ss)
++  : KPushButton(KIcon("preferences-desktop-sound"), "Test", ss)
++  , m_Ss(ss)
++  , m_Pos(pos)
++  , m_Canberra(canberra)
++{
++    setText(_positionName());
++    connect(this, SIGNAL(clicked()), SLOT(clicked()));
++}
++
++void TestSpeakerWidget::clicked()
++{
++    uint32_t sink_index = m_Ss->getCurrentSinkIndex();
++    char dev[64];
++    snprintf(dev, sizeof(dev), "%lu", (unsigned long) sink_index);
++    ca_context_change_device(m_Canberra, dev);
++
++    const char* sound_name = _positionSoundName();
++    ca_proplist* proplist;
++    ca_proplist_create(&proplist);
++    
++    ca_proplist_sets(proplist, CA_PROP_MEDIA_ROLE, "test");
++    ca_proplist_sets(proplist, CA_PROP_MEDIA_NAME, _positionName().toAscii().constData());
++    ca_proplist_sets(proplist, CA_PROP_CANBERRA_FORCE_CHANNEL, _positionAsString());
++    ca_proplist_sets(proplist, CA_PROP_CANBERRA_ENABLE, "1");
++
++    ca_proplist_sets(proplist, CA_PROP_EVENT_ID, sound_name);
++    if (ca_context_play_full(m_Canberra, 0, proplist, NULL, NULL) < 0) {
++        // Try a different sound name.
++        ca_proplist_sets(proplist, CA_PROP_EVENT_ID, "audio-test-signal");
++        if (ca_context_play_full(m_Canberra, 0, proplist, NULL, NULL) < 0) {
++            // Finaly try this... if this doesn't work, then stuff it.
++            ca_proplist_sets(proplist, CA_PROP_EVENT_ID, "bell-window-system");
++        }
++    }
++
++    ca_context_change_device(m_Canberra, NULL);
++    ca_proplist_destroy(proplist);
++}
++
++const char* TestSpeakerWidget::_positionAsString()
++{
++    switch (m_Pos)
++    {
++        case PA_CHANNEL_POSITION_FRONT_LEFT:
++            return "front-left";
++
++        case PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER:
++            return "front-left-of-center";
++
++        case PA_CHANNEL_POSITION_FRONT_CENTER:
++            return "front-center";
++
++        case PA_CHANNEL_POSITION_MONO:
++            return "mono";
++
++        case PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER:
++            return "front-right-of-center";
++
++        case PA_CHANNEL_POSITION_FRONT_RIGHT:
++            return "front-right";
++
++        case PA_CHANNEL_POSITION_SIDE_LEFT:
++            return "side-left";
++
++        case PA_CHANNEL_POSITION_SIDE_RIGHT:
++            return "side-right";
++
++        case PA_CHANNEL_POSITION_REAR_LEFT:
++            return "rear-left";
++
++        case PA_CHANNEL_POSITION_REAR_CENTER:
++            return "rear-center";
++
++        case PA_CHANNEL_POSITION_REAR_RIGHT:
++            return "rear-right";
++
++        case PA_CHANNEL_POSITION_LFE:
++            return "lfe";
++
++        default:
++            break;
++    }
++    return "invalid";
++}
++
++QString TestSpeakerWidget::_positionName()
++{
++    switch (m_Pos)
++    {
++        case PA_CHANNEL_POSITION_FRONT_LEFT:
++            return i18n("Front Left");
++
++        case PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER:
++            return i18n("Front Left of Center");
++
++        case PA_CHANNEL_POSITION_FRONT_CENTER:
++            return i18n("Front Center");
++
++        case PA_CHANNEL_POSITION_MONO:
++            return i18n("Mono");
++
++        case PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER:
++            return i18n("Front Right of Center");
++
++        case PA_CHANNEL_POSITION_FRONT_RIGHT:
++            return i18n("Front Right");
++
++        case PA_CHANNEL_POSITION_SIDE_LEFT:
++            return i18n("Side Left");
++
++        case PA_CHANNEL_POSITION_SIDE_RIGHT:
++            return i18n("Side Right");
++
++        case PA_CHANNEL_POSITION_REAR_LEFT:
++            return i18n("Rear Left");
++
++        case PA_CHANNEL_POSITION_REAR_CENTER:
++            return i18n("Rear Center");
++
++        case PA_CHANNEL_POSITION_REAR_RIGHT:
++            return i18n("Rear Right");
++
++        case PA_CHANNEL_POSITION_LFE:
++            return i18n("Subwoofer");
++
++        default:
++            break;
++    }
++    return i18n("Unknown Channel");
++}
++
++const char* TestSpeakerWidget::_positionSoundName()
++{
++    switch (m_Pos)
++    {
++        case PA_CHANNEL_POSITION_FRONT_LEFT:
++            return "audio-channel-front-left";
++
++        case PA_CHANNEL_POSITION_FRONT_RIGHT:
++            return "audio-channel-front-right";
++
++        case PA_CHANNEL_POSITION_FRONT_CENTER:
++            return "audio-channel-front-center";
++
++        case PA_CHANNEL_POSITION_REAR_LEFT:
++            return "audio-channel-rear-left";
++
++        case PA_CHANNEL_POSITION_REAR_RIGHT:
++            return "audio-channel-rear-right";
++
++        case PA_CHANNEL_POSITION_REAR_CENTER:
++            return "audio-channel-rear-center";
++
++        case PA_CHANNEL_POSITION_LFE:
++            return "audio-channel-lfe";
++
++        case PA_CHANNEL_POSITION_SIDE_LEFT:
++            return "audio-channel-side-left";
++
++        case PA_CHANNEL_POSITION_SIDE_RIGHT:
++            return "audio-channel-side-right";
++        default:
++            break;
++    }
++    return NULL;
++}
++
++
++#include "testspeakerwidget.moc"
++// vim: sw=4 sts=4 et tw=100
+
+Property changes on: runtime/phonon/kcm/testspeakerwidget.cpp
+___________________________________________________________________
+Added: svn:mime-type
+   + text/plain
+Added: svn:eol-style
+   + native
+
+Index: runtime/phonon/kcm/testspeakerwidget.h
+===================================================================
+--- runtime/phonon/kcm/testspeakerwidget.h	(revision 0)
++++ runtime/phonon/kcm/testspeakerwidget.h	(revision 1154776)
+@@ -0,0 +1,50 @@
++/*  This file is part of the KDE project
++    Copyright (C) 2010 Colin Guthrie <cguthrie at mandriva.org>
++
++    This program is free software; you can redistribute it and/or modify
++    it under the terms of the GNU General Public License version 2
++    as published by the Free Software Foundation.
++
++    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 General Public License for more details.
++
++    You should have received a copy of the GNU 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 PHONON_TESTSPEAKERWIDGET_H
++#define PHONON_TESTSPEAKERWIDGET_H
++
++#include <kpushbutton.h>
++
++#include <canberra.h>
++#include <pulse/pulseaudio.h>
++
++
++class SpeakerSetup;
++
++class TestSpeakerWidget: public KPushButton
++{
++    Q_OBJECT
++    public:
++        TestSpeakerWidget(const pa_channel_position_t pos, ca_context *canberra, SpeakerSetup* ss);
++
++    private slots:
++        void clicked();
++
++    private:
++        QString _positionName();
++        const char* _positionAsString();
++        const char* _positionSoundName();
++
++        SpeakerSetup* m_Ss;
++        pa_channel_position_t m_Pos;
++        ca_context* m_Canberra;
++};
++
++#endif // PHONON_TESTSPEAKERWIDGET_H
+
+Property changes on: runtime/phonon/kcm/testspeakerwidget.h
+___________________________________________________________________
+Added: svn:eol-style
+   + native
+
+Index: runtime/phonon/kcm/speakersetup.ui
+===================================================================
+--- runtime/phonon/kcm/speakersetup.ui	(revision 0)
++++ runtime/phonon/kcm/speakersetup.ui	(revision 1154776)
+@@ -0,0 +1,142 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<ui version="4.0">
++ <author>Matthias Kretz &lt;kretz at kde.org</author>
++ <class>SpeakerSetup</class>
++ <widget class="QWidget" name="SpeakerSetup">
++  <property name="geometry">
++   <rect>
++    <x>0</x>
++    <y>0</y>
++    <width>537</width>
++    <height>465</height>
++   </rect>
++  </property>
++  <layout class="QVBoxLayout" name="verticalLayout">
++   <item>
++    <widget class="QGroupBox" name="hardwareGroupBox">
++     <property name="title">
++      <string>Hardware</string>
++     </property>
++     <layout class="QGridLayout" name="_3">
++      <item row="3" column="1">
++       <widget class="QComboBox" name="profileBox">
++        <property name="sizePolicy">
++         <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
++          <horstretch>0</horstretch>
++          <verstretch>0</verstretch>
++         </sizepolicy>
++        </property>
++       </widget>
++      </item>
++      <item row="2" column="1">
++       <widget class="KComboBox" name="cardBox">
++        <property name="sizePolicy">
++         <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
++          <horstretch>0</horstretch>
++          <verstretch>0</verstretch>
++         </sizepolicy>
++        </property>
++       </widget>
++      </item>
++      <item row="3" column="0">
++       <widget class="QLabel" name="profileLabel">
++        <property name="text">
++         <string>Profile</string>
++        </property>
++        <property name="buddy">
++         <cstring>profileBox</cstring>
++        </property>
++       </widget>
++      </item>
++      <item row="2" column="0">
++       <widget class="QLabel" name="cardLabel">
++        <property name="text">
++         <string>Sound Card</string>
++        </property>
++        <property name="buddy">
++         <cstring>cardBox</cstring>
++        </property>
++       </widget>
++      </item>
++     </layout>
++    </widget>
++   </item>
++   <item>
++    <widget class="QGroupBox" name="outputGroupBox">
++     <property name="title">
++      <string>Output</string>
++     </property>
++     <layout class="QGridLayout" name="_2">
++      <item row="0" column="1">
++       <widget class="KComboBox" name="sinkBox">
++        <property name="sizePolicy">
++         <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
++          <horstretch>0</horstretch>
++          <verstretch>0</verstretch>
++         </sizepolicy>
++        </property>
++       </widget>
++      </item>
++      <item row="1" column="0">
++       <widget class="QLabel" name="portLabel">
++        <property name="text">
++         <string>Connector</string>
++        </property>
++        <property name="buddy">
++         <cstring>portBox</cstring>
++        </property>
++       </widget>
++      </item>
++      <item row="1" column="1">
++       <widget class="QComboBox" name="portBox">
++        <property name="sizePolicy">
++         <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
++          <horstretch>0</horstretch>
++          <verstretch>0</verstretch>
++         </sizepolicy>
++        </property>
++       </widget>
++      </item>
++      <item row="0" column="0">
++       <widget class="QLabel" name="sinkLabel">
++        <property name="text">
++         <string>Sound Output</string>
++        </property>
++        <property name="buddy">
++         <cstring>sinkBox</cstring>
++        </property>
++       </widget>
++      </item>
++     </layout>
++    </widget>
++   </item>
++   <item>
++    <widget class="QGroupBox" name="groupBox">
++     <property name="sizePolicy">
++      <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
++       <horstretch>0</horstretch>
++       <verstretch>0</verstretch>
++      </sizepolicy>
++     </property>
++     <property name="title">
++      <string>Speaker Placement and Testing</string>
++     </property>
++     <layout class="QVBoxLayout" name="_4">
++      <item>
++       <layout class="QGridLayout" name="placementGrid"/>
++      </item>
++     </layout>
++    </widget>
++   </item>
++  </layout>
++ </widget>
++ <customwidgets>
++  <customwidget>
++   <class>KComboBox</class>
++   <extends>QComboBox</extends>
++   <header>kcombobox.h</header>
++  </customwidget>
++ </customwidgets>
++ <resources/>
++ <connections/>
++</ui>
+Index: runtime/phonon/kcm/speakersetup.cpp
+===================================================================
+--- runtime/phonon/kcm/speakersetup.cpp	(revision 0)
++++ runtime/phonon/kcm/speakersetup.cpp	(revision 1154776)
+@@ -0,0 +1,664 @@
++/*  This file is part of the KDE project
++    Copyright (C) 2010 Colin Guthrie <cguthrie at mandriva.org>
++
++    This program is free software; you can redistribute it and/or modify
++    it under the terms of the GNU General Public License version 2
++    as published by the Free Software Foundation.
++
++    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 General Public License for more details.
++
++    You should have received a copy of the GNU 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 "speakersetup.h"
++#include "testspeakerwidget.h"
++#include <kgenericfactory.h>
++#include <kconfiggroup.h>
++#include <kaboutdata.h>
++#include <kicon.h>
++
++#include <glib.h>
++#include <pulse/xmalloc.h>
++#include <pulse/glib-mainloop.h>
++#include <QtCore/QAbstractEventDispatcher>
++#include <QtCore/QFileInfo>
++#include <QtCore/QDir>
++#include <QtDBus/QDBusConnection>
++#include <QtDBus/QDBusInterface>
++
++#define SS_DEFAULT_ICON "audio-card"
++
++
++static pa_glib_mainloop *s_mainloop = NULL;
++static pa_context *s_context = NULL;
++
++typedef struct {
++  uint32_t index;
++  QString name;
++  QString icon;
++  QMap<uint32_t,QPair<QString,QString> > profiles;
++  QString activeProfile;
++} cardInfo;
++
++QMap<uint32_t,cardInfo> s_Cards;
++
++typedef struct {
++  uint32_t index;
++  uint32_t cardIndex;
++  QString name;
++  QString icon;
++  pa_channel_map channelMap;
++  QMap<uint32_t,QPair<QString,QString> > ports;
++  QString activePort;
++} sinkInfo;
++
++QMap<uint32_t,sinkInfo> s_Sinks;
++
++static int debugLevel() {
++    static int level = -1;
++    if (level < 1) {
++        level = 0;
++        QString pulseenv = qgetenv("PHONON_PULSEAUDIO_DEBUG");
++        int l = pulseenv.toInt();
++        if (l > 0)
++            level = (l > 2 ? 2 : l);
++    }
++    return level;
++}
++
++static void logMessage(const QString &message, int priority = 2, QObject *obj=0);
++static void logMessage(const QString &message, int priority, QObject *obj)
++{
++    if (debugLevel() > 0) {
++        QString output;
++        if (obj) {
++            // Strip away namespace from className
++            QString className(obj->metaObject()->className());
++            int nameLength = className.length() - className.lastIndexOf(':') - 1;
++            className = className.right(nameLength);
++            output.sprintf("%s %s (%s %p)", message.toLatin1().constData(), 
++                           obj->objectName().toLatin1().constData(), 
++                           className.toLatin1().constData(), obj);
++        }
++        else {
++            output = message;
++        }
++        if (priority <= debugLevel()) {
++            qDebug() << QString("PulseSupport(%1): %2").arg(priority).arg(output);
++        }
++    }
++}
++
++
++static void card_cb(pa_context *c, const pa_card_info *i, int eol, void *userdata) {
++    Q_ASSERT(c);
++    Q_ASSERT(userdata);
++
++    SpeakerSetup* ss = static_cast<SpeakerSetup*>(userdata);
++
++    if (eol < 0) {
++        if (pa_context_errno(c) == PA_ERR_NOENTITY)
++            return;
++
++        logMessage(QString("Card callback failure"));
++        return;
++    }
++
++    if (eol > 0) {
++        ss->updateFromPulse();
++        return;
++    }
++
++    Q_ASSERT(i);
++    ss->updateCard(i);
++}
++
++static void sink_cb(pa_context *c, const pa_sink_info *i, int eol, void *userdata) {
++    Q_ASSERT(c);
++    Q_ASSERT(userdata);
++
++    SpeakerSetup* ss = static_cast<SpeakerSetup*>(userdata);
++
++    if (eol < 0) {
++        if (pa_context_errno(c) == PA_ERR_NOENTITY)
++            return;
++
++        logMessage(QString("Sink callback failure"));
++        return;
++    }
++
++    if (eol > 0) {
++        ss->updateIndependantDevices();
++        ss->updateFromPulse();
++        return;
++    }
++
++    Q_ASSERT(i);
++    ss->updateSink(i);
++}
++
++static void subscribe_cb(pa_context *c, pa_subscription_event_type_t t, uint32_t index, void *userdata) {
++    Q_ASSERT(c);
++    Q_ASSERT(userdata);
++
++    SpeakerSetup* ss = static_cast<SpeakerSetup*>(userdata);
++
++    switch (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) {
++        case PA_SUBSCRIPTION_EVENT_CARD:
++            if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
++                ss->removeCard(index);
++            } else {
++                pa_operation *o;
++                if (!(o = pa_context_get_card_info_by_index(c, index, card_cb, ss))) {
++                    logMessage(QString("pa_context_get_card_info_by_index() failed"));
++                    return;
++                }
++                pa_operation_unref(o);
++            }
++            break;
++
++        case PA_SUBSCRIPTION_EVENT_SINK:
++            if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
++              ss->removeSink(index);
++            } else {
++                pa_operation *o;
++                if (!(o = pa_context_get_sink_info_by_index(c, index, sink_cb, ss))) {
++                    logMessage(QString("pa_context_get_sink_info_by_index() failed"));
++                    return;
++                }
++                pa_operation_unref(o);
++            }
++            break;
++    }
++}
++
++
++static const char* statename(pa_context_state_t state)
++{
++    switch (state)
++    {
++        case PA_CONTEXT_UNCONNECTED:  return "Unconnected";
++        case PA_CONTEXT_CONNECTING:   return "Connecting";
++        case PA_CONTEXT_AUTHORIZING:  return "Authorizing";
++        case PA_CONTEXT_SETTING_NAME: return "Setting Name";
++        case PA_CONTEXT_READY:        return "Ready";
++        case PA_CONTEXT_FAILED:       return "Failed";
++        case PA_CONTEXT_TERMINATED:   return "Terminated";
++    }
++
++    static QString unknown;
++    unknown = QString("Unknown state: %0").arg(state);
++    return unknown.toAscii().constData();
++}
++
++static void context_state_callback(pa_context *c, void *userdata)
++{
++    Q_ASSERT(c);
++    Q_ASSERT(userdata);
++
++    SpeakerSetup* ss = static_cast<SpeakerSetup*>(userdata);
++
++    logMessage(QString("context_state_callback %1").arg(statename(pa_context_get_state(c))));
++    pa_context_state_t state = pa_context_get_state(c);
++    if (state == PA_CONTEXT_READY) {
++        // Attempt to load things up
++        pa_operation *o;
++
++        pa_context_set_subscribe_callback(c, subscribe_cb, ss);
++
++        if (!(o = pa_context_subscribe(c, (pa_subscription_mask_t)
++                                          (PA_SUBSCRIPTION_MASK_CARD|
++                                           PA_SUBSCRIPTION_MASK_SINK), NULL, NULL))) {
++            logMessage(QString("pa_context_subscribe() failed"));
++            return;
++        }
++        pa_operation_unref(o);
++
++        if (!(o = pa_context_get_card_info_list(c, card_cb, ss))) {
++          logMessage(QString("pa_context_get_card_info_list() failed"));
++          return;
++        }
++        pa_operation_unref(o);
++
++        if (!(o = pa_context_get_sink_info_list(c, sink_cb, ss))) {
++          logMessage(QString("pa_context_get_sink_info_list() failed"));
++          return;
++        }
++        pa_operation_unref(o);
++
++        ss->load();
++
++    } else if (!PA_CONTEXT_IS_GOOD(state)) {
++        /// @todo Deal with reconnection...
++        //logMessage(QString("Connection to PulseAudio lost: %1").arg(pa_strerror(pa_context_errno(c))));
++
++        // If this is our probe phase, exit our context immediately
++        if (s_context != c)
++            pa_context_disconnect(c);
++        else {
++            pa_context_unref(s_context);
++            s_context = NULL;
++            //QTimer::singleShot(50, PulseSupport::getInstance(), SLOT(connectToDaemon()));
++        }
++    }
++}
++
++
++SpeakerSetup::SpeakerSetup(QWidget *parent)
++    : QWidget(parent)
++    , m_OutstandingRequests(2)
++    , m_Canberra(NULL)
++{
++    setupUi(this);
++
++    cardLabel->setEnabled(false);
++    cardBox->setEnabled(false);
++    profileLabel->setVisible(false);
++    profileBox->setVisible(false);
++
++    sinkLabel->setEnabled(false);
++    sinkBox->setEnabled(false);
++    portLabel->setVisible(false);
++    portBox->setVisible(false);
++
++    for (int i=0; i<5; ++i)
++        placementGrid->setColumnStretch(i, 1);
++    for (int i=0; i<3; ++i)
++        placementGrid->setRowStretch(i, 1);
++
++    m_Icon = new QLabel(this);
++    const QFileInfo fi(QDir(QDir::homePath()), ".face.icon");
++    if (fi.exists())
++        m_Icon->setPixmap(QPixmap(fi.absoluteFilePath()).scaled(KIconLoader::SizeHuge, KIconLoader::SizeHuge, Qt::KeepAspectRatio));
++    else
++        m_Icon->setPixmap(KIcon("system-users").pixmap(KIconLoader::SizeHuge, KIconLoader::SizeHuge));
++    placementGrid->addWidget(m_Icon, 1, 2, Qt::AlignCenter);
++
++    update();
++    connect(cardBox,    SIGNAL(currentIndexChanged(int)), SLOT(cardChanged()));
++    connect(profileBox, SIGNAL(currentIndexChanged(int)), SLOT(profileChanged()));
++    connect(sinkBox,    SIGNAL(currentIndexChanged(int)), SLOT(sinkChanged()));
++    connect(portBox,    SIGNAL(currentIndexChanged(int)), SLOT(portChanged()));
++
++    // We require a glib event loop
++    if (QLatin1String(QAbstractEventDispatcher::instance()->metaObject()->className())
++            != "QGuiEventDispatcherGlib") {
++        logMessage("Disabling PulseAudio integration for lack of GLib event loop.");
++        return;
++    }
++
++    s_mainloop = pa_glib_mainloop_new(NULL);
++    Q_ASSERT(s_mainloop);
++
++    pa_mainloop_api *api = pa_glib_mainloop_get_api(s_mainloop);
++
++    s_context = pa_context_new(api, "kspeakersetup");
++    int rv;
++    rv = pa_context_connect(s_context, NULL, PA_CONTEXT_NOFAIL, 0);
++    Q_ASSERT(rv >= 0);
++
++    pa_context_set_state_callback(s_context, &context_state_callback, this);
++
++    rv = ca_context_create(&m_Canberra);
++    Q_ASSERT(rv >= 0);
++}
++
++SpeakerSetup::~SpeakerSetup()
++{
++    ca_context_destroy(m_Canberra);
++    pa_context_unref(s_context);
++    s_context = NULL;
++    pa_glib_mainloop_free(s_mainloop);
++    s_mainloop = NULL;
++}
++
++void SpeakerSetup::load()
++{
++}
++
++void SpeakerSetup::save()
++{
++}
++
++void SpeakerSetup::defaults()
++{
++}
++
++void SpeakerSetup::updateCard(const pa_card_info* i)
++{
++    cardInfo info;
++    info.index = i->index;
++
++    const char* description = pa_proplist_gets(i->proplist, PA_PROP_DEVICE_DESCRIPTION);
++    info.name = description ? QString::fromUtf8(description) : i->name;
++
++    const char* icon = pa_proplist_gets(i->proplist, PA_PROP_DEVICE_ICON_NAME);
++    info.icon = icon ? icon : SS_DEFAULT_ICON;
++
++    for (uint32_t j = 0; j < i->n_profiles; ++j)
++      info.profiles[i->profiles[j].priority] = QPair<QString,QString>(i->profiles[j].name, QString::fromUtf8(i->profiles[j].description));
++    if (i->active_profile)
++      info.activeProfile = i->active_profile->name;
++
++
++    bool bs = cardBox->blockSignals(true);
++    if (s_Cards.contains(i->index)) {
++      int idx = cardBox->findData(i->index);
++      if (idx >= 0) {
++        cardBox->setItemIcon(idx, KIcon(info.icon));
++        cardBox->setItemText(idx, info.name);
++      }
++    }
++    else
++      cardBox->addItem(KIcon(info.icon), info.name, i->index);
++    cardBox->blockSignals(bs);
++
++    s_Cards[i->index] = info;
++
++    cardChanged();
++
++    logMessage(QString("Got info about card %1").arg(info.name));
++}
++
++void SpeakerSetup::removeCard(uint32_t index)
++{
++    s_Cards.remove(index);
++    updateFromPulse();
++    int idx = cardBox->findData(index);
++    if (idx >= 0)
++        cardBox->removeItem(idx);
++}
++
++void SpeakerSetup::updateSink(const pa_sink_info* i)
++{
++    sinkInfo info;
++    info.index = i->index;
++    info.cardIndex = i->card;
++    info.name = QString::fromUtf8(i->description);
++
++    const char* icon = pa_proplist_gets(i->proplist, PA_PROP_DEVICE_ICON_NAME);
++    info.icon = icon ? icon : SS_DEFAULT_ICON;
++
++    info.channelMap = i->channel_map;
++
++    for (uint32_t j = 0; j < i->n_ports; ++j)
++      info.ports[i->ports[j]->priority] = QPair<QString,QString>(i->ports[j]->name, QString::fromUtf8(i->ports[j]->description));
++    if (i->active_port)
++      info.activePort = i->active_port->name;
++
++    s_Sinks[i->index] = info;
++
++    // Need to update the currently displayed port if this sink is the currently displayed one.
++    if (info.ports.size()) {
++        int idx = sinkBox->currentIndex();
++        if (idx >= 0) {
++            uint32_t sink_index = sinkBox->itemData(idx).toUInt();
++            if (sink_index == i->index) {
++                bool bs = portBox->blockSignals(true);
++                portBox->setCurrentIndex(portBox->findData(info.activePort));
++                portBox->blockSignals(bs);
++            }
++        }
++    }
++
++    logMessage(QString("Got info about sink %1").arg(info.name));
++}
++
++void SpeakerSetup::removeSink(uint32_t index)
++{
++    s_Sinks.remove(index);
++    updateIndependantDevices();
++    updateFromPulse();
++    int idx = sinkBox->findData(index);
++    if (idx >= 0)
++        sinkBox->removeItem(idx);
++}
++
++void SpeakerSetup::updateFromPulse()
++{
++    if (m_OutstandingRequests > 0) {
++        if (0 == --m_OutstandingRequests) {
++            // Work out which seclector to pick by default (we want to choose a real Card if possible)
++            if (s_Cards.size() != cardBox->count())
++                cardBox->setCurrentIndex(1);
++            emit ready();
++        }
++    }
++
++    if (!m_OutstandingRequests) {
++        if (!s_Cards.size() && !s_Sinks.size()) {
++            cardLabel->setEnabled(false);
++            cardBox->setEnabled(false);
++            profileLabel->setVisible(false);
++            profileBox->setVisible(false);
++
++            sinkLabel->setEnabled(false);
++            sinkBox->setEnabled(false);
++            portLabel->setVisible(false);
++            portBox->setVisible(false);
++        }
++        if (s_Cards.size() && !cardBox->isEnabled()) {
++            cardLabel->setEnabled(true);
++            cardBox->setEnabled(true);
++            cardChanged();
++        }
++        if (s_Sinks.size() && !sinkBox->isEnabled()) {
++            sinkLabel->setEnabled(true);
++            sinkBox->setEnabled(true);
++            sinkChanged();
++        }
++    }
++}
++
++void SpeakerSetup::cardChanged()
++{
++    int idx = cardBox->currentIndex();
++    if (idx < 0) {
++        profileLabel->setVisible(false);
++        profileBox->setVisible(false);
++        return;
++    }
++
++    uint32_t card_index = cardBox->itemData(idx).toUInt();
++    Q_ASSERT(PA_INVALID_INDEX == card_index || s_Cards.contains(card_index));
++    bool show_profiles = (PA_INVALID_INDEX != card_index && s_Cards[card_index].profiles.size());
++    if (show_profiles) {
++        cardInfo &card_info = s_Cards[card_index];
++        bool bs = profileBox->blockSignals(true);
++        profileBox->clear();
++        for (QMap<uint32_t, QPair<QString,QString> >::iterator it = card_info.profiles.begin(); it != card_info.profiles.end(); ++it)
++            profileBox->insertItem(0, it.value().second, it.value().first);
++        profileBox->setCurrentIndex(profileBox->findData(card_info.activeProfile));
++        profileBox->blockSignals(bs);
++    }
++    profileLabel->setVisible(show_profiles);
++    profileBox->setVisible(show_profiles);
++
++
++    bool bs = sinkBox->blockSignals(true);
++    sinkBox->clear();
++    for (QMap<uint32_t,sinkInfo>::iterator it = s_Sinks.begin(); it != s_Sinks.end(); ++it) {
++        if (it->cardIndex == card_index)
++            sinkBox->addItem(KIcon(it->icon), it->name, it->index);
++    }
++    sinkBox->blockSignals(bs);
++
++    outputGroupBox->setEnabled(!!sinkBox->count());
++
++    sinkChanged();
++
++    logMessage(QString("Doing update %1").arg(cardBox->currentIndex()));
++
++    emit changed();
++}
++
++void SpeakerSetup::profileChanged()
++{
++    uint32_t card_index = cardBox->itemData(cardBox->currentIndex()).toUInt();
++    Q_ASSERT(PA_INVALID_INDEX != card_index);
++
++    QString profile = profileBox->itemData(profileBox->currentIndex()).toString();
++    logMessage(QString("Changing profile to %1").arg(profile));
++
++    cardInfo &card_info = s_Cards[card_index];
++    Q_ASSERT(card_info.profiles.size());
++
++    pa_operation *o;
++    if (!(o = pa_context_set_card_profile_by_index(s_context, card_index, profile.toAscii().constData(), NULL, NULL)))
++        logMessage(QString("pa_context_set_card_profile_by_name() failed"));
++    else
++        pa_operation_unref(o);
++
++    emit changed();
++}
++
++void SpeakerSetup::updateIndependantDevices()
++{
++    // Should we display the "Independant Devices" drop down?
++    // Count all the sinks without cards
++    bool showID = false;
++    for (QMap<uint32_t,sinkInfo>::iterator it = s_Sinks.begin(); it != s_Sinks.end(); ++it) {
++        if (PA_INVALID_INDEX == it->cardIndex) {
++            showID = true;
++            break;
++        }
++    }
++
++    bool haveID = (PA_INVALID_INDEX == cardBox->itemData(0).toUInt());
++
++    logMessage(QString("Want ID: %1; Have ID: %2").arg(showID?"Yes":"No").arg(haveID?"Yes":"No"));
++
++    bool bs = cardBox->blockSignals(true);
++    if (haveID && !showID)
++        cardBox->removeItem(0);
++    else if (!haveID && showID)
++        cardBox->insertItem(0, KIcon(SS_DEFAULT_ICON), "Independent Devices", PA_INVALID_INDEX);
++    cardBox->blockSignals(bs);
++}
++
++void SpeakerSetup::sinkChanged()
++{
++    int idx = sinkBox->currentIndex();
++    if (idx < 0) {
++        portLabel->setVisible(false);
++        portBox->setVisible(false);
++        _updatePlacementTester();
++        return;
++    }
++    uint32_t sink_index = sinkBox->itemData(idx).toUInt();
++    Q_ASSERT(s_Sinks.contains(sink_index));
++    sinkInfo &sink_info = s_Sinks[sink_index];
++    logMessage(QString("Updating ports for sink '%1' (%2 ports available)").arg(sink_info.name).arg(sink_info.ports.size()));
++
++    bool show_ports = !!sink_info.ports.size();
++    if (show_ports) {
++        bool bs = portBox->blockSignals(true);
++        portBox->clear();
++        for (QMap<uint32_t, QPair<QString,QString> >::iterator it = sink_info.ports.begin(); it != sink_info.ports.end(); ++it)
++            portBox->insertItem(0, it.value().second, it.value().first);
++        portBox->setCurrentIndex(portBox->findData(sink_info.activePort));
++        portBox->blockSignals(bs);
++    }
++    portLabel->setVisible(show_ports);
++    portBox->setVisible(show_ports);
++
++    if (sinkBox->currentIndex() >= 0)
++        _updatePlacementTester();
++
++    emit changed();
++}
++
++void SpeakerSetup::portChanged()
++{
++    uint32_t sink_index = sinkBox->itemData(sinkBox->currentIndex()).toUInt();
++    Q_ASSERT(PA_INVALID_INDEX != sink_index);
++
++    QString port = portBox->itemData(portBox->currentIndex()).toString();
++    logMessage(QString("Changing port to %1").arg(port));
++
++    sinkInfo &sink_info = s_Sinks[sink_index];
++    Q_ASSERT(sink_info.ports.size());
++
++    pa_operation *o;
++    if (!(o = pa_context_set_sink_port_by_index(s_context, sink_index, port.toAscii().constData(), NULL, NULL)))
++        logMessage(QString("pa_context_set_sink_port_by_index() failed"));
++    else
++        pa_operation_unref(o);
++
++    emit changed();
++}
++
++void SpeakerSetup::_updatePlacementTester()
++{
++    static const int position_table[] = {
++        /* Position, X, Y */
++        PA_CHANNEL_POSITION_FRONT_LEFT,            0, 0,
++        PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER,  1, 0,
++        PA_CHANNEL_POSITION_FRONT_CENTER,          2, 0,
++        PA_CHANNEL_POSITION_MONO,                  2, 0,
++        PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER, 3, 0,
++        PA_CHANNEL_POSITION_FRONT_RIGHT,           4, 0,
++        PA_CHANNEL_POSITION_SIDE_LEFT,             0, 1,
++        PA_CHANNEL_POSITION_SIDE_RIGHT,            4, 1,
++        PA_CHANNEL_POSITION_REAR_LEFT,             0, 2,
++        PA_CHANNEL_POSITION_REAR_CENTER,           2, 2,
++        PA_CHANNEL_POSITION_REAR_RIGHT,            4, 2,
++        PA_CHANNEL_POSITION_LFE,                   3, 2
++    };
++
++    QLayoutItem* w;
++    while ((w = placementGrid->takeAt(0))) {
++        if (w->widget() != m_Icon) {
++            if (w->widget())
++                delete w->widget();
++            delete w;
++        }
++    }
++    placementGrid->addWidget(m_Icon, 1, 2, Qt::AlignCenter);
++    int idx = sinkBox->currentIndex();
++    if (idx < 0)
++      return;
++
++    uint32_t sink_index = sinkBox->itemData(idx).toUInt();
++    Q_ASSERT(s_Sinks.contains(sink_index));
++    sinkInfo& sink_info = s_Sinks[sink_index];
++
++    for (int i = 0; i < 36; i += 3) {
++        pa_channel_position_t pos = (pa_channel_position_t)position_table[i];
++        // Check to see if we have this item in our current channel map.
++        bool have = false;
++        for (uint32_t j = 0; j < sink_info.channelMap.channels; ++j) {
++            if (sink_info.channelMap.map[j] == pos) {
++                have = true;
++                break;
++            }
++        }
++        if (!have) {
++            continue;
++        }
++
++        KPushButton* btn = new TestSpeakerWidget(pos, m_Canberra, this);//KPushButton(KIcon("audio-card"), (name ? name : "Unknown Channel"), this);
++        placementGrid->addWidget(btn, position_table[i+2], position_table[i+1], Qt::AlignCenter);
++    }
++
++}
++
++uint32_t SpeakerSetup::getCurrentSinkIndex()
++{
++    int idx = sinkBox->currentIndex();
++    if (idx < 0)
++        return PA_INVALID_INDEX;
++
++    return sinkBox->itemData(idx).toUInt();
++}
++
++
++#include "speakersetup.moc"
++// vim: sw=4 sts=4 et tw=100
+
+Property changes on: runtime/phonon/kcm/speakersetup.cpp
+___________________________________________________________________
+Added: svn:mime-type
+   + text/plain
+Added: svn:eol-style
+   + native
+
+Index: runtime/phonon/kcm/speakersetup.h
+===================================================================
+--- runtime/phonon/kcm/speakersetup.h	(revision 0)
++++ runtime/phonon/kcm/speakersetup.h	(revision 1154776)
+@@ -0,0 +1,70 @@
++/*  This file is part of the KDE project
++    Copyright (C) 2010 Colin Guthrie <cguthrie at mandriva.org>
++
++    This program is free software; you can redistribute it and/or modify
++    it under the terms of the GNU General Public License version 2
++    as published by the Free Software Foundation.
++
++    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 General Public License for more details.
++
++    You should have received a copy of the GNU 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 PHONON_SPEAKERSETUP_H
++#define PHONON_SPEAKERSETUP_H
++
++#include <canberra.h>
++#include <pulse/pulseaudio.h>
++
++#include "ui_speakersetup.h"
++#define KDE3_SUPPORT
++#include <kcmodule.h>
++#undef KDE3_SUPPORT
++#include <kconfig.h>
++
++//class QLabel;
++
++class SpeakerSetup : public QWidget, private Ui::SpeakerSetup
++{
++    Q_OBJECT
++    public:
++        SpeakerSetup(QWidget *parent = 0);
++        ~SpeakerSetup();
++
++        void load();
++        void save();
++        void defaults();
++        uint32_t getCurrentSinkIndex();
++        void updateCard(const pa_card_info*);
++        void removeCard(uint32_t idx);
++        void updateSink(const pa_sink_info*);
++        void removeSink(uint32_t idx);
++        void updateFromPulse();
++        void updateIndependantDevices();
++
++    public Q_SLOTS:
++        void cardChanged();
++        void profileChanged();
++        void sinkChanged();
++        void portChanged();
++
++    Q_SIGNALS:
++        void changed();
++        void ready();
++
++    private:
++        void _updatePlacementTester();
++
++        QLabel* m_Icon;
++        int m_OutstandingRequests;
++        ca_context* m_Canberra;
++};
++
++#endif // PHONON_SPEAKERSETUP_H
+
+Property changes on: runtime/phonon/kcm/speakersetup.h
+___________________________________________________________________
+Added: svn:eol-style
+   + native
+
+Index: runtime/phonon/kcm/main.cpp
+===================================================================
+--- runtime/phonon/kcm/main.cpp	(revision 1154775)
++++ runtime/phonon/kcm/main.cpp	(revision 1154776)
+@@ -1,5 +1,6 @@
+ /*  This file is part of the KDE project
+     Copyright (C) 2006-2007 Matthias Kretz <kretz at kde.org>
++    Copyright (C) 2010 Colin Guthrie <cguthrie at mandriva.org>
+ 
+     This program is free software; you can redistribute it and/or
+     modify it under the terms of the GNU Library General Public
+@@ -28,6 +29,10 @@
+ #include "devicepreference.h"
+ #include "backendselection.h"
+ 
++#ifdef HAVE_PULSEAUDIO
++#  include "speakersetup.h"
++#endif
++
+ K_PLUGIN_FACTORY(PhononKcmFactory, registerPlugin<PhononKcm>();)
+ K_EXPORT_PLUGIN(PhononKcmFactory("kcm_phonon"))
+ 
+@@ -39,23 +44,33 @@
+             KDE_VERSION_STRING, KLocalizedString(), KAboutData::License_GPL,
+             ki18n("Copyright 2006 Matthias Kretz"));
+     about->addAuthor(ki18n("Matthias Kretz"), KLocalizedString(), "kretz at kde.org");
++    about->addAuthor(ki18n("Colin Guthrie"), KLocalizedString(), "cguthrie at mandriva.org");
+     setAboutData(about);
+ 
+     setLayout(new QHBoxLayout);
+     layout()->setMargin(0);
+     layout()->setSpacing(0);
+ 
+-    KTabWidget *tabs = new KTabWidget(this);
+-    layout()->addWidget(tabs);
++    m_tabs = new KTabWidget(this);
++    layout()->addWidget(m_tabs);
+ 
+     m_devicePreferenceWidget = new DevicePreference(this);
+-    tabs->addTab(m_devicePreferenceWidget, i18n("Device Preference"));
++    m_tabs->addTab(m_devicePreferenceWidget, i18n("Device Preference"));
+     m_backendSelection = new BackendSelection(this);
+-    tabs->addTab(m_backendSelection, i18n("Backend"));
++    m_tabs->addTab(m_backendSelection, i18n("Backend"));
++
+     load();
+     connect(m_backendSelection, SIGNAL(changed()), SLOT(changed()));
+     connect(m_devicePreferenceWidget, SIGNAL(changed()), SLOT(changed()));
++
+     setButtons( KCModule::Default|KCModule::Apply|KCModule::Help );
++
++#ifdef HAVE_PULSEAUDIO
++    m_speakerSetup = new SpeakerSetup(this);
++    m_speakerSetup->setVisible(false);
++    connect(m_speakerSetup, SIGNAL(ready()), SLOT(speakerSetupReady()));
++    connect(m_speakerSetup, SIGNAL(changed()), SLOT(changed()));
++#endif
+ }
+ 
+ void PhononKcm::load()
+@@ -76,5 +91,13 @@
+     m_backendSelection->defaults();
+ }
+ 
++#ifdef HAVE_PULSEAUDIO
++void PhononKcm::speakerSetupReady()
++{
++  m_tabs->insertTab(1, m_speakerSetup, i18n("Speaker Setup"));
++  emit changed();
++}
++#endif
++
+ #include "main.moc"
+ // vim: ts=4
+Index: runtime/phonon/kcm/main.h
+===================================================================
+--- runtime/phonon/kcm/main.h	(revision 1154775)
++++ runtime/phonon/kcm/main.h	(revision 1154776)
+@@ -25,6 +25,11 @@
+ class DevicePreference;
+ class BackendSelection;
+ 
++#ifdef HAVE_PULSEAUDIO
++class SpeakerSetup;
++#endif
++class KTabWidget;
++
+ class PhononKcm : public KCModule
+ {
+     Q_OBJECT
+@@ -35,9 +40,18 @@
+         void save();
+         void defaults();
+ 
++#ifdef HAVE_PULSEAUDIO
++    private Q_SLOTS:
++        void speakerSetupReady();
++#endif
++
+     private:
++        KTabWidget* m_tabs;
+         DevicePreference *m_devicePreferenceWidget;
+         BackendSelection *m_backendSelection;
++#ifdef HAVE_PULSEAUDIO
++        SpeakerSetup* m_speakerSetup;
++#endif
+ };
+ 
+ #endif // MAIN_H
+Index: runtime/phonon/kcm/CMakeLists.txt
+===================================================================
+--- runtime/phonon/kcm/CMakeLists.txt	(revision 1154775)
++++ runtime/phonon/kcm/CMakeLists.txt	(revision 1154776)
+@@ -1,3 +1,11 @@
++set(PULSEAUDIO_MINIMUM_VERSION "0.9.16")
++macro_optional_find_package(PulseAudio)
++macro_log_feature(PULSEAUDIO_FOUND "PulseAudio" "PulseAudio Audio Server" "http://www.pulseaudio.org/" FALSE "0.9.16" "libpulse is needed for speaker setup GUI")
++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 speaker setup GUI")
++
+ add_subdirectory(xine)
+ 
+ set(kcmphonon_SRCS main.cpp devicepreference.cpp backendselection.cpp)
+@@ -2,6 +10,17 @@
+ kde4_add_ui_files(kcmphonon_SRCS devicepreference.ui backendselection.ui)
++set(kcmphonon_LIBS ${KDE4_PHONON_LIBS} ${KDE4_KCMUTILS_LIBS} ${KDE4_KIO_LIBS})
+ 
++if(GLIB2_FOUND AND PULSEAUDIO_FOUND AND CANBERRA_FOUND)
++  add_definitions(-DHAVE_PULSEAUDIO)
++
++  set(kcmphonon_SRCS ${kcmphonon_SRCS} speakersetup.cpp testspeakerwidget.cpp)
++  kde4_add_ui_files(kcmphonon_SRCS speakersetup.ui)
++
++  include_directories(${GLIB2_INCLUDE_DIR} ${PULSEAUDIO_INCLUDE_DIR} ${CANBERRA_INCLUDE_DIRS})
++
++  set(kcmphonon_LIBS ${kcmphonon_LIBS} ${GLIB2_LIBRARIES} ${PULSEAUDIO_LIBRARY} ${PULSEAUDIO_MAINLOOP_LIBRARY} ${CANBERRA_LIBRARIES})
++endif(GLIB2_FOUND AND PULSEAUDIO_FOUND AND CANBERRA_FOUND)
++
+ kde4_add_plugin(kcm_phonon ${kcmphonon_SRCS})
+-target_link_libraries(kcm_phonon ${KDE4_PHONON_LIBS} ${KDE4_KCMUTILS_LIBS}
+-   ${KDE4_KIO_LIBS})
++target_link_libraries(kcm_phonon ${kcmphonon_LIBS})
+ 
diff --git a/kdebase-runtime.spec b/kdebase-runtime.spec
index 6caafab..f8130ca 100644
--- a/kdebase-runtime.spec
+++ b/kdebase-runtime.spec
@@ -6,7 +6,7 @@
 Name:          kdebase-runtime
 Summary:       KDE Runtime
 Version:       4.5.2
-Release:       2%{?dist}
+Release:       3%{?dist}
 
 # http://techbase.kde.org/Policies/Licensing_Policy
 License:       LGPLv2+
@@ -23,6 +23,11 @@ Patch5:        kdebase-runtime-4.3.1-manpath.patch
 # add OnlyShowIn=KDE  to Desktop/Home.desktop (like trash.desktop)
 Patch6:        kdebase-runtime-4.3.3-home_onlyshowin_kde.patch
 
+## upstream patches
+# pulseaudio speaker setup backport, courtesy of coling/mandriva
+# http://svn.mandriva.com/cgi-bin/viewvc.cgi/packages/cooker/kdebase4-runtime/current/SOURCES/kdebase-runtime-4.5-speakersetup.patch
+Patch100: kdebase-runtime-4.5-speakersetup.patch
+
 Provides:  kdebase4-runtime = %{version}-%{release}
 Obsoletes: kdebase4-runtime < %{version}-%{release}
 
@@ -52,11 +57,13 @@ BuildRequires: kde-filesystem
 BuildRequires: alsa-lib-devel
 BuildRequires: attica-devel
 BuildRequires: bzip2-devel
+BuildRequires: chrpath
 BuildRequires: clucene-core-devel
 BuildRequires: exiv2-devel
 BuildRequires: hal-devel
 BuildRequires: kdelibs4-devel >= %{version}
 BuildRequires: kdepimlibs-devel >= %{version}
+BuildRequires: libcanberra-devel 
 BuildRequires: libsmbclient-devel
 BuildRequires: libssh-devel >= 0.4.2
 BuildRequires: libXScrnSaver-devel
@@ -110,6 +117,8 @@ BuildArch: noarch
 %patch3 -p1 -b .iconthemes-inherit
 #patch5 -p1 -b .manpath
 %patch6 -p1 -b .home_onlyshowin_kde
+%patch100 -p1 -b .speakersetup
+
 
 %build
 mkdir -p %{_target_platform}
@@ -147,6 +156,10 @@ install -p -D -m755 drkonqi/doc/examples/installdbgsymbols_fedora.sh \
 # FIXME: -devel type files, omit for now
 rm -vf  %{buildroot}%{_kde4_libdir}/lib{kwalletbackend,molletnetwork}.so
 
+# rpaths
+# use chrpath hammer for now, find better patching solutions later -- Rex
+chrpath --delete %{buildroot}%{_libdir}/kde4/plugins/phonon_platform/kde.so
+
 
 %clean
 rm -rf %{buildroot}
@@ -236,6 +249,10 @@ fi
 
 
 %changelog
+* Fri Oct 15 2010 Rex Dieter <rdieter at fedoraproject.org> - 4.5.2-3
+- pa speakersetup backport (courtesy of coling/mandriva)
+- hammer rpath from phonon_platform/kde.so
+
 * Fri Oct 15 2010 Rex Dieter <rdieter at fedoraproject.org> - 4.5.2-2
 - use kde4's copy of khelpcenter.desktop
 


More information about the scm-commits mailing list