KMilo: added support for PulseAudio volume control.

Signed-off-by: Michele Calgaro <michele.calgaro@yahoo.it>
pull/26/head
Michele Calgaro 4 years ago
parent 9fdd3356a8
commit c20f6cb658
Signed by: MicheleC
GPG Key ID: 2A75B7CA8ADED5CF

@ -42,27 +42,54 @@
using namespace KMilo; using namespace KMilo;
// now the key data (from kkeyserver_x11.h and $TQTDIR/include/tqnamespace.h)
struct ShortcutInfo
{
const char* name;
int symbol;
const char *slot;
};
static const ShortcutInfo shortcuts[] =
{
{ "Search", TDEShortcut("XF86Search"), TQT_SLOT(launchSearch()) },
{ "Home Folder", TDEShortcut("XF86MyComputer"), TQT_SLOT(launchHomeFolder()) },
{ "Mail", TDEShortcut("XF86Mail"), TQT_SLOT(launchMail()) },
{ "Audio Media", TDEShortcut("XF86AudioMedia"), TQT_SLOT(launchMusic()) },
{ "Music", TDEShortcut("XF86Music"), TQT_SLOT(launchMusic()) },
{ "Browser", TDEShortcut("XF86WWW"), TQT_SLOT(launchBrowser()) },
{ "Calculator", TDEShortcut("XF86Calculator"), TQT_SLOT(launchCalculator()) },
{ "Terminal", TDEShortcut("XF86Terminal"), TQT_SLOT(launchTerminal()) },
{ "Eject", TDEShortcut("XF86Eject"), TQT_SLOT(eject()) },
{ "Help", TDEShortcut("XF86Launch0"), TQT_SLOT(launchHelp()) },
{ "Light Bulb", TDEShortcut("XF86LightBulb"), TQT_SLOT(lightBulb()) },
{ "Battery", TDEShortcut("XF86LaunchB"), TQT_SLOT(pmBattery()) },
{ "FastVolumeUp", TQt::Key_VolumeUp, TQT_SLOT(fastVolumeUp()) },
{ "FastVolumeDown", TQt::Key_VolumeDown, TQT_SLOT(fastVolumeDown()) },
{ "SlowVolumeUp", TQt::CTRL+TQt::Key_VolumeUp, TQT_SLOT(slowVolumeUp()) },
{ "SlowVolumeDown", TQt::CTRL+TQt::Key_VolumeDown, TQT_SLOT(slowVolumeDown()) },
{ "Mute", TDEShortcut("XF86AudioMute"), TQT_SLOT(toggleMute()) },
{ "BrightnessUp", TDEShortcut("XF86MonBrightnessUp"), TQT_SLOT(brightnessUp()) },
{ "BrightnessDown", TDEShortcut("XF86MonBrightnessDown"), TQT_SLOT(brightnessDown()) }
};
GenericMonitor::GenericMonitor(TQObject *parent, const char *name, const TQStringList& args) GenericMonitor::GenericMonitor(TQObject *parent, const char *name, const TQStringList& args)
: Monitor(parent, name, args), kmixClient(NULL), kmixWindow(NULL), tdepowersave(NULL) : Monitor(parent, name, args), kmixClient(NULL), kmixWindow(NULL), tdepowersave(NULL),
m_progress(0), m_displayType(Monitor::None)
{ {
_poll = false; _poll = false;
m_displayType = Monitor::None;
m_mute = false;
m_progress = 0;
m_minVolume = 0;
m_maxVolume = 100;
m_volume = 50;
} }
GenericMonitor::~GenericMonitor() GenericMonitor::~GenericMonitor()
{ {
if(ga) { if (ga)
ga->remove("FastVolumeUp"); {
ga->remove("FastVolumeDown"); int len = (int)sizeof(shortcuts)/sizeof(ShortcutInfo);
ga->remove("SlowVolumeUp"); for (int i = 0; i < len; i++)
ga->remove("SlowVolumeDown"); {
ga->remove("Mute"); ga->remove(shortcuts[i].name);
}
ga->updateConnections();
delete ga; delete ga;
} }
} }
@ -75,27 +102,6 @@ bool GenericMonitor::init()
if(!m_enabled) if(!m_enabled)
return false; // exit early if we are not supposed to run return false; // exit early if we are not supposed to run
static const ShortcutInfo shortcuts[] = {
{ "Search", TDEShortcut("XF86Search"), TQT_SLOT(launchSearch()) },
{ "Home Folder", TDEShortcut("XF86MyComputer"), TQT_SLOT(launchHomeFolder()) },
{ "Mail", TDEShortcut("XF86Mail"), TQT_SLOT(launchMail()) },
{ "Audio Media", TDEShortcut("XF86AudioMedia"), TQT_SLOT(launchMusic()) },
{ "Music", TDEShortcut("XF86Music"), TQT_SLOT(launchMusic()) },
{ "Browser", TDEShortcut("XF86WWW"), TQT_SLOT(launchBrowser()) },
{ "Calculator", TDEShortcut("XF86Calculator"), TQT_SLOT(launchCalculator()) },
{ "Terminal", TDEShortcut("XF86Terminal"), TQT_SLOT(launchTerminal()) },
{ "Eject", TDEShortcut("XF86Eject"), TQT_SLOT(eject()) },
{ "Help", TDEShortcut("XF86Launch0"), TQT_SLOT(launchHelp()) },
{ "Light Bulb", TDEShortcut("XF86LightBulb"), TQT_SLOT(lightBulb()) },
{ "Battery", TDEShortcut("XF86LaunchB"), TQT_SLOT(pmBattery()) },
{ "FastVolumeUp", TQt::Key_VolumeUp, TQT_SLOT(fastVolumeUp()) },
{ "FastVolumeDown", TQt::Key_VolumeDown, TQT_SLOT(fastVolumeDown()) },
{ "SlowVolumeUp", TQt::CTRL+TQt::Key_VolumeUp, TQT_SLOT(slowVolumeUp()) },
{ "SlowVolumeDown", TQt::CTRL+TQt::Key_VolumeDown, TQT_SLOT(slowVolumeDown()) },
{ "Mute", TDEShortcut("XF86AudioMute"), TQT_SLOT(mute()) },
{ "BrightnessUp", TDEShortcut("XF86MonBrightnessUp"), TQT_SLOT(brightnessUp()) },
{ "BrightnessDown", TDEShortcut("XF86MonBrightnessDown"), TQT_SLOT(brightnessDown()) }
};
ga = new TDEGlobalAccel(this, "miloGenericAccel"); ga = new TDEGlobalAccel(this, "miloGenericAccel");
@ -113,7 +119,7 @@ bool GenericMonitor::init()
ga->readSettings(); ga->readSettings();
ga->updateConnections(); ga->updateConnections();
kmixClient = new DCOPRef("kmix", "Mixer0"); kmixClient = new DCOPRef("kmix", "kmix");
kmixWindow = new DCOPRef("kmix", "kmix-mainwindow#1"); kmixWindow = new DCOPRef("kmix", "kmix-mainwindow#1");
tdepowersave = new DCOPRef("tdepowersave", "tdepowersaveIface"); tdepowersave = new DCOPRef("tdepowersave", "tdepowersaveIface");
@ -123,114 +129,72 @@ bool GenericMonitor::init()
void GenericMonitor::reconfigure(TDEConfig *config) void GenericMonitor::reconfigure(TDEConfig *config)
{ {
config->setGroup("generic monitor"); config->setGroup("generic monitor");
m_volumeDeviceIdx = config->readNumEntry("volumeDeviceIdx", -1);
m_muteDeviceIdx = config->readNumEntry("muteDeviceIdx", m_volumeDeviceIdx);
m_extraDeviceIdx = config->readNumEntry("extraDeviceIdx", -1);
m_volumeStepFast = config->readNumEntry("volumeStepFast", 10); m_volumeStepFast = config->readNumEntry("volumeStepFast", 10);
m_volumeStepSlow = config->readNumEntry("volumeStepSlow", 1); m_volumeStepSlow = config->readNumEntry("volumeStepSlow", 1);
m_enabled = config->readBoolEntry("enabled", true); m_enabled = config->readBoolEntry("enabled", true);
} }
bool GenericMonitor::retrieveKmixDevices() bool GenericMonitor::retrieveVolume(int &volume)
{ {
if(m_volumeDeviceIdx != -1 && m_muteDeviceIdx != -1) DCOPReply reply = kmixClient->call("volume");
return true; // both indexes already set if (reply.isValid())
DCOPReply reply = kmixClient->call("masterDeviceIndex");
if (!reply.isValid())
{ // maybe the error occurred because kmix wasn't running
_interface->displayText(i18n("Starting KMix..."));
if (kapp->startServiceByDesktopName("kmix")==0) // trying to start kmix
{
reply = kmixClient->call("masterDeviceIndex");
if (reply.isValid())
kmixWindow->send("hide");
}
}
if (!reply.isValid())
{ {
kdDebug() << "KMilo: GenericMonitor could not access kmix/Mixer0 via dcop" volume = reply;
<< endl;
_interface->displayText(i18n("It seems that KMix is not running."));
return false;
} else {
if (m_volumeDeviceIdx == -1)
m_volumeDeviceIdx = reply;
if (m_muteDeviceIdx == -1)
m_muteDeviceIdx = m_volumeDeviceIdx; // this is the behaviour documented in README
return true; return true;
} }
// maybe the error occurred because kmix wasn't running. Try to start it
_interface->displayText(i18n("Starting KMix..."));
if (kapp->startServiceByDesktopName("kmix") == 0)
{
// trying again
reply = kmixClient->call("volume");
if (reply.isValid())
{
volume = reply;
kmixWindow->send("hide");
return true;
}
}
kdDebug() << "KMilo: GenericMonitor could not access kmix via dcop" << endl;
_interface->displayText(i18n("It seems that KMix is not running."));
return false;
} }
bool GenericMonitor::retrieveVolume() void GenericMonitor::volumeChange(int direction, int percentage)
{ {
bool kmix_error = false; int volume;
if (!direction || !retrieveVolume(volume))
if(!retrieveKmixDevices()) {
return false; return;
}
DCOPReply reply = kmixClient->call("absoluteVolume", m_volumeDeviceIdx);
if (reply.isValid())
m_volume = reply;
else
kmix_error = true;
if (kmix_error) // maybe the error occurred because kmix wasn't running if (direction > 0)
{ {
_interface->displayText(i18n("Starting KMix...")); volume += percentage;
if (kapp->startServiceByDesktopName("kmix")==0) // trying to start kmix if (volume > 100)
{ {
// trying again volume = 100;
reply = kmixClient->call("absoluteVolume", m_volumeDeviceIdx);
if (reply.isValid())
{
m_volume = reply;
kmix_error = false;
kmixWindow->send("hide");
}
} }
} }
else
if (kmix_error)
{ {
kdDebug() << "KMilo: GenericMonitor could not access kmix/Mixer0 via dcop" volume -= percentage;
<< endl; if (volume < 0)
_interface->displayText(i18n("It seems that KMix is not running.")); {
volume = 0;
return false; }
} else {
reply = kmixClient->call("absoluteVolumeMax", m_volumeDeviceIdx);
m_maxVolume = reply;
reply = kmixClient->call("absoluteVolumeMin", m_volumeDeviceIdx);
m_minVolume = reply;
return true;
} }
}
void GenericMonitor::volumeChange(int direction, int step) _interface->displayProgress(i18n("Volume"), volume);
{ kmixClient->send("setVolume", volume);
if (!retrieveVolume())
return;
/* Following snippet of code may seem to be overcomplicated, but it works for both devices with // if mute then unmute
* volume grain < 100 (32 tested) and devices with volume grain > 100 (256 tested) while preserving bool muted = false;
* accuracy for devices with fine grain and preserving usability for devices with rough grain. */ if (retrieveMute(muted) && muted)
int userVisibleVolume = tqRound(m_volume * 100.0 / (m_maxVolume - m_minVolume)); {
userVisibleVolume += direction * step; // add requested volume step kmixClient->send("setMute", false);
long previousVolume = m_volume; }
m_volume = tqRound(m_minVolume + userVisibleVolume * (m_maxVolume - m_minVolume) / 100.0);
if (m_volume == previousVolume) // if the change was rounded to zero
m_volume += direction;
if (m_volume > m_maxVolume)
m_volume = m_maxVolume;
if (m_volume < m_minVolume)
m_volume = m_minVolume;
displayVolume();
} }
void GenericMonitor::slowVolumeUp() { volumeChange( 1, m_volumeStepSlow); } void GenericMonitor::slowVolumeUp() { volumeChange( 1, m_volumeStepSlow); }
@ -238,90 +202,53 @@ void GenericMonitor::slowVolumeDown() { volumeChange(-1, m_volumeStepSlow); }
void GenericMonitor::fastVolumeUp() { volumeChange( 1, m_volumeStepFast); } void GenericMonitor::fastVolumeUp() { volumeChange( 1, m_volumeStepFast); }
void GenericMonitor::fastVolumeDown() { volumeChange(-1, m_volumeStepFast); } void GenericMonitor::fastVolumeDown() { volumeChange(-1, m_volumeStepFast); }
void GenericMonitor::displayVolume() bool GenericMonitor::retrieveMute(bool &muted)
{ {
_interface->displayProgress(i18n("Volume"), tqRound(m_volume * 100.0 / (m_maxVolume - m_minVolume))); DCOPReply reply = kmixClient->call("mute");
if (reply.isValid())
// If we got this far, the DCOP communication with kmix works,
// so we don't have to test the result.
// Also, device indexes are set to their proper values.
kmixClient->send("setAbsoluteVolume", m_volumeDeviceIdx, m_volume);
if(m_extraDeviceIdx != -1)
// for simplicity, use relative volume rather that absolute (extra precision is not needed here)
kmixClient->send("setVolume", m_extraDeviceIdx, tqRound(m_volume * 100.0 / (m_maxVolume - m_minVolume)));
// if mute then unmute
if (m_mute)
{ {
m_mute = false; muted = reply;
kmixClient->send("setMute", m_muteDeviceIdx, m_mute); return true;
} }
}
bool GenericMonitor::retrieveMute()
{
bool kmix_error = false;
if(!retrieveKmixDevices())
return false;
DCOPReply reply = kmixClient->call("mute", m_muteDeviceIdx); // maybe the error occurred because kmix wasn't running. Try to start it
if (reply.isValid()) _interface->displayText(i18n("Starting KMix..."));
m_mute = reply; if (kapp->startServiceByDesktopName("kmix") == 0)
else
kmix_error = true;
if (kmix_error)
{ {
// maybe the error occurred because kmix wasn't running // trying again
_interface->displayText(i18n("Starting KMix...")); reply = kmixClient->call("mute");
if (kapp->startServiceByDesktopName("kmix")==0) // trying to start kmix if (reply.isValid())
{
// trying again
reply = kmixClient->call("mute", m_muteDeviceIdx);
if (reply.isValid())
{
m_mute = reply;
kmix_error = false;
kmixWindow->send("hide");
}
} else
{ {
muted = reply;
kmixWindow->send("hide"); kmixWindow->send("hide");
kmix_error = true; return true;
} }
} }
kdDebug() << "KMilo: GenericMonitor could not access kmix via dcop" << endl;
if (kmix_error) _interface->displayText(i18n("It seems that KMix is not running."));
{ return false;
kdDebug() << "KMilo: GenericMonitor could not access kmix/Mixer0 via dcop"
<< endl;
_interface->displayText(i18n("It seems that KMix is not running."));
return false;
} else {
return true;
}
} }
void GenericMonitor::mute() void GenericMonitor::toggleMute()
{ {
if (!retrieveMute()) bool muted = false;
if (!retrieveMute(muted))
{
return; return;
}
m_mute = !m_mute; muted = !muted;
TQString muteText; TQString muteText;
if (m_mute) if (muted)
{ {
muteText = i18n("Mute on"); muteText = i18n("System muted");
} else { }
muteText = i18n("Mute off"); else
{
muteText = i18n("System unmuted");
} }
kmixClient->send("setMute", m_muteDeviceIdx, m_mute); kmixClient->send("setMute", muted);
if(m_extraDeviceIdx != -1)
kmixClient->send("setMute", m_extraDeviceIdx, m_mute);
_interface->displayText(muteText); _interface->displayText(muteText);
} }
@ -367,12 +294,12 @@ void GenericMonitor::brightnessChange(int direction, int step)
} }
} }
int GenericMonitor::progress() const int GenericMonitor::progress() const
{ {
return m_progress; return m_progress;
} }
Monitor::DisplayType GenericMonitor::poll() Monitor::DisplayType GenericMonitor::poll()
{ {
return m_displayType; return m_displayType;
} }

@ -36,15 +36,6 @@
namespace KMilo { namespace KMilo {
// now the key data (from kkeyserver_x11.h and $TQTDIR/include/tqnamespace.h)
struct ShortcutInfo
{
const char* name;
uint symbol;
const char *slot;
};
class GenericMonitor : public Monitor class GenericMonitor : public Monitor
{ {
Q_OBJECT Q_OBJECT
@ -64,7 +55,7 @@ public slots:
void slowVolumeDown(); void slowVolumeDown();
void fastVolumeUp(); void fastVolumeUp();
void fastVolumeDown(); void fastVolumeDown();
void mute(); void toggleMute();
void brightnessUp(); void brightnessUp();
void brightnessDown(); void brightnessDown();
void launchMail(); void launchMail();
@ -80,11 +71,9 @@ public slots:
void pmBattery(); void pmBattery();
private: private:
bool retrieveKmixDevices(); void volumeChange(int direction, int percentage);
void volumeChange(int direction, int step); bool retrieveMute(bool &muted);
bool retrieveMute(); bool retrieveVolume(int &volume);
bool retrieveVolume();
void displayVolume();
void brightnessChange(int direction, int step); void brightnessChange(int direction, int step);
void launch(TQString configKey, TQString defaultApplication); void launch(TQString configKey, TQString defaultApplication);
@ -94,14 +83,9 @@ private:
DCOPRef *kmixClient, *kmixWindow, *tdepowersave; DCOPRef *kmixClient, *kmixWindow, *tdepowersave;
int m_progress; int m_progress;
long m_volume;
bool m_mute;
long m_maxVolume, m_minVolume;
// following properties are read from config file: // following properties are read from config file:
int m_volumeStepFast, m_volumeStepSlow; int m_volumeStepFast, m_volumeStepSlow;
int m_volumeDeviceIdx, m_muteDeviceIdx, m_extraDeviceIdx;
bool m_enabled; bool m_enabled;
Monitor::DisplayType m_displayType; Monitor::DisplayType m_displayType;

Loading…
Cancel
Save