00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "halpower.h"
00022
00023 #include <QtDBus/QDBusReply>
00024
00025 #include <kdebug.h>
00026
00027 #include "halsuspendjob.h"
00028
00029 #include <solid/deviceinterface.h>
00030 #include <solid/acadapter.h>
00031 #include <solid/battery.h>
00032 #include <solid/button.h>
00033 #include <solid/genericinterface.h>
00034
00035 HalPower::HalPower(QObject *parent, const QStringList & )
00036 : PowerManager(parent),
00037 m_halComputer("org.freedesktop.Hal",
00038 "/org/freedesktop/Hal/devices/computer",
00039 "org.freedesktop.Hal.Device",
00040 QDBusConnection::systemBus()),
00041 m_halPowerManagement("org.freedesktop.Hal",
00042 "/org/freedesktop/Hal/devices/computer",
00043 "org.freedesktop.Hal.Device.SystemPowerManagement",
00044 QDBusConnection::systemBus()),
00045 m_halCpuFreq("org.freedesktop.Hal",
00046 "/org/freedesktop/Hal/devices/computer",
00047 "org.freedesktop.Hal.Device.CPUFreq",
00048 QDBusConnection::systemBus()),
00049 m_halManager("org.freedesktop.Hal",
00050 "/org/freedesktop/Hal/Manager",
00051 "org.freedesktop.Hal.Manager",
00052 QDBusConnection::systemBus())
00053 {
00054 connect(Solid::DeviceNotifier::instance(), SIGNAL(deviceRemoved(const QString &)),
00055 this, SLOT(slotDeviceRemoved(const QString &)));
00056 connect(Solid::DeviceNotifier::instance(), SIGNAL(deviceAdded(const QString &)),
00057 this, SLOT(slotDeviceAdded(const QString &)));
00058
00059 m_pluggedAdapterCount = 0;
00060 computeAcAdapters();
00061
00062 computeBatteries();
00063 updateBatteryStats();
00064
00065 computeButtons();
00066 }
00067
00068 HalPower::~HalPower()
00069 {
00070 qDeleteAll(m_acAdapters);
00071 qDeleteAll(m_batteries);
00072 qDeleteAll(m_buttons);
00073 }
00074
00075 QStringList HalPower::supportedSchemes() const
00076 {
00077 return QStringList() << "performance" << "powersaving";
00078 }
00079
00080 QString HalPower::schemeDescription(const QString &schemeName) const
00081 {
00082 if (schemeName=="performance")
00083 {
00084 return "Use all the performances of the system";
00085 }
00086 else if (schemeName=="powersaving")
00087 {
00088 return "Try to keep as much power as possible to improve battery life";
00089 }
00090 else
00091 {
00092 return QString();
00093 }
00094
00095 return QString();
00096 }
00097
00098 QString HalPower::scheme() const
00099 {
00100
00101 return QString();
00102 }
00103
00104 bool HalPower::setScheme(const QString &name)
00105 {
00106 bool powersave;
00107
00108 if (name=="powersaving")
00109 {
00110 powersave = true;
00111 }
00112 else if (name=="performance")
00113 {
00114 powersave = false;
00115 }
00116 else
00117 {
00118 return false;
00119 }
00120
00121 QDBusReply<int> reply = m_halPowerManagement.call("SetPowerSave", powersave);
00122
00123 if (reply.isValid())
00124 {
00125 int code = reply;
00126 return code==0;
00127 }
00128 else
00129 {
00130 return false;
00131 }
00132 }
00133
00134 Solid::Control::PowerManager::BatteryState HalPower::batteryState() const
00135 {
00136 if (m_batteries.size()==0)
00137 {
00138 return Solid::Control::PowerManager::NoBatteryState;
00139 }
00140 else if (m_currentBatteryCharge <= m_criticalBatteryCharge)
00141 {
00142 return Solid::Control::PowerManager::Critical;
00143 }
00144 else if (m_currentBatteryCharge <= m_lowBatteryCharge)
00145 {
00146 return Solid::Control::PowerManager::Low;
00147 }
00148 else if (m_currentBatteryCharge <= m_warningBatteryCharge)
00149 {
00150 return Solid::Control::PowerManager::Warning;
00151 }
00152 else
00153 {
00154 return Solid::Control::PowerManager::Normal;
00155 }
00156 }
00157
00158 int HalPower::batteryChargePercent() const
00159 {
00160 if (!m_maxBatteryCharge) return 0;
00161
00162 return (m_currentBatteryCharge *100)/m_maxBatteryCharge;
00163 }
00164
00165 int HalPower::batteryRemainingTime() const
00166 {
00167 return m_estimatedBatteryTime;
00168 }
00169
00170 Solid::Control::PowerManager::AcAdapterState HalPower::acAdapterState() const
00171 {
00172 if (m_acAdapters.size()==0)
00173 {
00174 return Solid::Control::PowerManager::UnknownAcAdapterState;
00175 }
00176 else if (m_pluggedAdapterCount==0)
00177 {
00178 return Solid::Control::PowerManager::Unplugged;
00179 }
00180 else
00181 {
00182 return Solid::Control::PowerManager::Plugged;
00183 }
00184 }
00185
00186 Solid::Control::PowerManager::SuspendMethods HalPower::supportedSuspendMethods() const
00187 {
00188 Solid::Control::PowerManager::SuspendMethods supported = Solid::Control::PowerManager::UnknownSuspendMethod;
00189
00190 QDBusReply<bool> reply = m_halComputer.call("GetPropertyBoolean", "power_management.can_suspend");
00191
00192 if (reply.isValid())
00193 {
00194 bool can_suspend = reply;
00195 if (can_suspend)
00196 {
00197 supported |= Solid::Control::PowerManager::ToRam;
00198 }
00199 }
00200 else
00201 {
00202 kDebug() << reply.error().name() << ": " << reply.error().message();
00203 }
00204
00205 reply = m_halComputer.call("GetPropertyBoolean", "power_management.can_hibernate");
00206
00207 if (reply.isValid())
00208 {
00209 bool can_hibernate = reply;
00210 if (can_hibernate)
00211 {
00212 supported |= Solid::Control::PowerManager::ToDisk;
00213 }
00214 }
00215 else
00216 {
00217 kDebug() << reply.error().name() << ": " << reply.error().message();
00218 }
00219
00220 return supported;
00221 }
00222
00223 KJob *HalPower::suspend(Solid::Control::PowerManager::SuspendMethod method) const
00224 {
00225 return new HalSuspendJob(m_halPowerManagement,
00226 method, supportedSuspendMethods());
00227 }
00228
00229 Solid::Control::PowerManager::CpuFreqPolicies HalPower::supportedCpuFreqPolicies() const
00230 {
00231 QDBusReply<QStringList> reply = m_halCpuFreq.call("GetCPUFreqAvailableGovernors");
00232
00233 if (!reply.isValid())
00234 {
00235 return Solid::Control::PowerManager::UnknownCpuFreqPolicy;
00236 }
00237 else
00238 {
00239 QStringList governors = reply;
00240 Solid::Control::PowerManager::CpuFreqPolicies policies = Solid::Control::PowerManager::UnknownCpuFreqPolicy;
00241
00242 foreach (const QString& governor, governors)
00243 {
00244 if (governor == "ondemand")
00245 {
00246 policies|= Solid::Control::PowerManager::OnDemand;
00247 }
00248 else if (governor == "userspace")
00249 {
00250 policies|= Solid::Control::PowerManager::Userspace;
00251 }
00252 else if (governor == "powersave")
00253 {
00254 policies|= Solid::Control::PowerManager::Powersave;
00255 }
00256 else if (governor == "performance")
00257 {
00258 policies|= Solid::Control::PowerManager::Performance;
00259 }
00260 else if (governor == "conservative")
00261 {
00262 policies|= Solid::Control::PowerManager::Conservative;
00263 }
00264 else
00265 {
00266 kWarning() << "Unknown governor: " << governor ;
00267 }
00268 }
00269
00270 return policies;
00271 }
00272 }
00273
00274 Solid::Control::PowerManager::CpuFreqPolicy HalPower::cpuFreqPolicy() const
00275 {
00276 QDBusReply<QString> reply = m_halCpuFreq.call("GetCPUFreqGovernor");
00277
00278 if (!reply.isValid())
00279 {
00280 return Solid::Control::PowerManager::UnknownCpuFreqPolicy;
00281 }
00282 else
00283 {
00284 QString governor = reply;
00285
00286 if (governor == "ondemand")
00287 {
00288 return Solid::Control::PowerManager::OnDemand;
00289 }
00290 else if (governor == "userspace")
00291 {
00292 return Solid::Control::PowerManager::Userspace;
00293 }
00294 else if (governor == "powersave")
00295 {
00296 return Solid::Control::PowerManager::Powersave;
00297 }
00298 else if (governor == "performance")
00299 {
00300 return Solid::Control::PowerManager::Performance;
00301 }
00302 else if (governor == "conservative")
00303 {
00304 return Solid::Control::PowerManager::Conservative;
00305 }
00306 else
00307 {
00308 return Solid::Control::PowerManager::UnknownCpuFreqPolicy;
00309 }
00310 }
00311 }
00312
00313 bool HalPower::setCpuFreqPolicy(Solid::Control::PowerManager::CpuFreqPolicy newPolicy)
00314 {
00315 QString governor;
00316
00317 switch(newPolicy)
00318 {
00319 case Solid::Control::PowerManager::OnDemand:
00320 governor = "ondemand";
00321 break;
00322 case Solid::Control::PowerManager::Userspace:
00323 governor = "userspace";
00324 break;
00325 case Solid::Control::PowerManager::Powersave:
00326 governor = "powersave";
00327 break;
00328 case Solid::Control::PowerManager::Performance:
00329 governor = "performance";
00330 break;
00331 case Solid::Control::PowerManager::Conservative:
00332 governor = "conservative";
00333 break;
00334 default:
00335 return false;
00336 }
00337
00338 QDBusReply<int> reply = m_halCpuFreq.call("SetCPUFreqGovernor", governor);
00339
00340 if (reply.isValid())
00341 {
00342 int code = reply;
00343 return code==0;
00344 }
00345 else
00346 {
00347 return false;
00348 }
00349 }
00350
00351 bool HalPower::canDisableCpu(int ) const
00352 {
00353 return false;
00354 }
00355
00356 bool HalPower::setCpuEnabled(int , bool )
00357 {
00358 return false;
00359 }
00360
00361 Solid::Control::PowerManager::BrightnessControlsList HalPower::brightnessControlsAvailable()
00362 {
00363 Solid::Control::PowerManager::BrightnessControlsList deviceList;
00364 foreach(const QString &name, m_halManager.call("FindDeviceByCapability", "laptop_panel").arguments().at(0).toStringList())
00365 {
00366 deviceList.insert(name, Solid::Control::PowerManager::Screen);
00367 }
00368 foreach(const QString &name, m_halManager.call("FindDeviceByCapability", "keyboard_backlight").arguments().at(0).toStringList())
00369 {
00370 deviceList.insert(name, Solid::Control::PowerManager::Keyboard);
00371 }
00372 return deviceList;
00373 }
00374
00375 float HalPower::brightness(const QString &device)
00376 {
00377 float brightness;
00378 if(m_halManager.call("FindDeviceByCapability", "laptop_panel").arguments().at(0).toStringList().contains(device))
00379 {
00380 QDBusInterface deviceInterface("org.freedesktop.Hal", device, "org.freedesktop.Hal.Device.LaptopPanel", QDBusConnection::systemBus());
00381 brightness = deviceInterface.call("GetBrightness").arguments().at(0).toDouble();
00382 if(deviceInterface.lastError().isValid())
00383 {
00384 return 0;
00385 }
00386 else
00387 {
00388 QDBusInterface propertyInterface("org.freedesktop.Hal", device, "org.freedesktop.Hal.Device", QDBusConnection::systemBus());
00389 int levels = propertyInterface.call("GetProperty", "laptop_panel.num_levels").arguments().at(0).toInt();
00390 return (float)(100*(brightness/(levels-1)));
00391 }
00392 }
00393 if(m_halManager.call("FindDeviceByCapability", "keyboard_backlight").arguments().at(0).toStringList().contains(device))
00394 {
00395 QDBusInterface deviceInterface("org.freedesktop.Hal", device, "org.freedesktop.Hal.Device.KeyboardBacklight", QDBusConnection::systemBus());
00396 brightness = deviceInterface.call("GetBrightness").arguments().at(0).toDouble();
00397 if(deviceInterface.lastError().isValid())
00398 {
00399 return 0;
00400 }
00401 else
00402 {
00403 QDBusInterface propertyInterface("org.freedesktop.Hal", device, "org.freedesktop.Hal.Device", QDBusConnection::systemBus());
00404 int levels = propertyInterface.call("GetProperty", "keyboard_backlight.num_levels").arguments().at(0).toInt();
00405 return (float)(100*(brightness/(levels-1)));
00406 }
00407 }
00408 return 0;
00409 }
00410
00411 bool HalPower::setBrightness(float brightness, const QString &device)
00412 {
00413 if(m_halManager.call("FindDeviceByCapability", "laptop_panel").arguments().at(0).toStringList().contains(device))
00414 {
00415 QDBusInterface propertyInterface("org.freedesktop.Hal", device, "org.freedesktop.Hal.Device", QDBusConnection::systemBus());
00416 int levels = propertyInterface.call("GetProperty", "laptop_panel.num_levels").arguments().at(0).toInt();
00417 QDBusInterface deviceInterface("org.freedesktop.Hal", device, "org.freedesktop.Hal.Device.LaptopPanel", QDBusConnection::systemBus());
00418 deviceInterface.call("SetBrightness", qRound((levels-1)*(brightness/100.0)));
00419 if(!deviceInterface.lastError().isValid())
00420 {
00421 emit(brightnessChanged(brightness));
00422 return true;
00423 }
00424 }
00425 if(m_halManager.call("FindDeviceByCapability", "keyboard_backlight").arguments().at(0).toStringList().contains(device))
00426 {
00427 QDBusInterface propertyInterface("org.freedesktop.Hal", device, "org.freedesktop.Hal.Device", QDBusConnection::systemBus());
00428 int levels = propertyInterface.call("GetProperty", "keyboard_backlight.num_levels").arguments().at(0).toInt();
00429 QDBusInterface deviceInterface("org.freedesktop.Hal", device, "org.freedesktop.Hal.Device.KeyboardBacklight", QDBusConnection::systemBus());
00430 deviceInterface.call("SetBrightness", qRound((levels-1)*(brightness/100.0)));
00431 if(!deviceInterface.lastError().isValid())
00432 {
00433 emit(brightnessChanged(brightness));
00434 return true;
00435 }
00436 }
00437 return false;
00438 }
00439
00440 void HalPower::computeAcAdapters()
00441 {
00442 QList<Solid::Device> adapters
00443 = Solid::Device::listFromType(Solid::DeviceInterface::AcAdapter);
00444
00445 foreach (Solid::Device adapter, adapters)
00446 {
00447 m_acAdapters[adapter.udi()] = new Solid::Device(adapter);
00448 connect(m_acAdapters[adapter.udi()]->as<Solid::AcAdapter>(), SIGNAL(plugStateChanged(bool, const QString &)),
00449 this, SLOT(slotPlugStateChanged(bool)));
00450
00451 if (m_acAdapters[adapter.udi()]->as<Solid::AcAdapter>()!=0
00452 && m_acAdapters[adapter.udi()]->as<Solid::AcAdapter>()->isPlugged())
00453 {
00454 m_pluggedAdapterCount++;
00455 }
00456 }
00457 }
00458
00459 void HalPower::computeBatteries()
00460 {
00461 QList<Solid::Device> batteries
00462 = Solid::Device::listFromQuery("Battery.type == 'PrimaryBattery'");
00463
00464 foreach (Solid::Device battery, batteries)
00465 {
00466 m_batteries[battery.udi()] = new Solid::Device(battery);
00467 connect(m_batteries[battery.udi()]->as<Solid::Battery>(), SIGNAL(chargePercentChanged(int, const QString &)),
00468 this, SLOT(updateBatteryStats()));
00469 connect(m_batteries[battery.udi()]->as<Solid::GenericInterface>(), SIGNAL(propertyChanged(const QMap<QString,int> &)),
00470 this, SLOT(slotBatteryPropertyChanged(const QMap<QString,int> &)));
00471 }
00472
00473 updateBatteryStats();
00474 }
00475
00476 void HalPower::computeButtons()
00477 {
00478 QList<Solid::Device> buttons
00479 = Solid::Device::listFromType(Solid::DeviceInterface::Button);
00480
00481 foreach (Solid::Device button, buttons)
00482 {
00483 m_buttons[button.udi()] = new Solid::Device(button);
00484 connect(m_buttons[button.udi()]->as<Solid::Button>(), SIGNAL(pressed(Solid::Button::ButtonType, const QString &)),
00485 this, SLOT(slotButtonPressed(Solid::Button::ButtonType)));
00486 }
00487 }
00488
00489 void HalPower::updateBatteryStats()
00490 {
00491 m_currentBatteryCharge = 0;
00492 m_maxBatteryCharge = 0;
00493 m_warningBatteryCharge = 0;
00494 m_lowBatteryCharge = 0;
00495 m_criticalBatteryCharge = 0;
00496 m_estimatedBatteryTime = 0;
00497
00498 foreach (Solid::Device *d, m_batteries)
00499 {
00500 Solid::GenericInterface *interface = d->as<Solid::GenericInterface>();
00501
00502 if (interface == 0) continue;
00503
00504 m_currentBatteryCharge+= interface->property("battery.charge_level.current").toInt();
00505 m_maxBatteryCharge+= interface->property("battery.charge_level.last_full").toInt();
00506 m_warningBatteryCharge+= interface->property("battery.charge_level.warning").toInt();
00507 m_lowBatteryCharge+= interface->property("battery.charge_level.low").toInt();
00508 m_estimatedBatteryTime+= interface->property("battery.remaining_time").toInt() * 1000;
00509 }
00510
00511 m_criticalBatteryCharge = m_lowBatteryCharge/2;
00512 }
00513
00514 void HalPower::slotPlugStateChanged(bool newState)
00515 {
00516 if (newState)
00517 {
00518 if(m_pluggedAdapterCount == 0)
00519 {
00520 emit acAdapterStateChanged(Solid::Control::PowerManager::Plugged);
00521 }
00522 m_pluggedAdapterCount++;
00523 }
00524 else
00525 {
00526 if(m_pluggedAdapterCount == 1)
00527 {
00528 emit acAdapterStateChanged(Solid::Control::PowerManager::Unplugged);
00529 }
00530 m_pluggedAdapterCount--;
00531 }
00532 }
00533
00534 void HalPower::slotButtonPressed(Solid::Button::ButtonType type)
00535 {
00536 Solid::Button *button = qobject_cast<Solid::Button *>(sender());
00537
00538 if (button == 0) return;
00539
00540 switch(type)
00541 {
00542 case Solid::Button::PowerButton:
00543 emit buttonPressed(Solid::Control::PowerManager::PowerButton);
00544 break;
00545 case Solid::Button::SleepButton:
00546 emit buttonPressed(Solid::Control::PowerManager::SleepButton);
00547 break;
00548 case Solid::Button::LidButton:
00549 if (button->stateValue())
00550 {
00551 emit buttonPressed(Solid::Control::PowerManager::LidClose);
00552 }
00553 else
00554 {
00555 emit buttonPressed(Solid::Control::PowerManager::LidOpen);
00556 }
00557 break;
00558 default:
00559 kWarning() << "Unknown button type" ;
00560 break;
00561 }
00562 }
00563
00564 void HalPower::slotDeviceAdded(const QString &udi)
00565 {
00566 Solid::Device *device = new Solid::Device(udi);
00567 if (device->is<Solid::AcAdapter>())
00568 {
00569 m_acAdapters[udi] = device;
00570 connect(m_acAdapters[udi]->as<Solid::AcAdapter>(), SIGNAL(plugStateChanged(bool, const QString &)),
00571 this, SLOT(slotPlugStateChanged(bool)));
00572
00573 if (m_acAdapters[udi]->as<Solid::AcAdapter>()!=0
00574 && m_acAdapters[udi]->as<Solid::AcAdapter>()->isPlugged())
00575 {
00576 m_pluggedAdapterCount++;
00577 }
00578 }
00579 else if (device->is<Solid::Battery>())
00580 {
00581 m_batteries[udi] = device;
00582 connect(m_batteries[udi]->as<Solid::Battery>(), SIGNAL(chargePercentChanged(int, const QString &)),
00583 this, SLOT(updateBatteryStats()));
00584 connect(m_batteries[udi]->as<Solid::GenericInterface>(), SIGNAL(propertyChanged(const QMap<QString,int> &)),
00585 this, SLOT(slotBatteryPropertyChanged(const QMap<QString,int> &)));
00586 }
00587 else if (device->is<Solid::Button>())
00588 {
00589 m_buttons[udi] = device;
00590 connect(m_buttons[udi]->as<Solid::Button>(), SIGNAL(pressed(int, const QString &)),
00591 this, SLOT(slotButtonPressed(int)));
00592 }
00593 else
00594 {
00595 delete device;
00596 }
00597 }
00598
00599 void HalPower::slotDeviceRemoved(const QString &udi)
00600 {
00601 Solid::Device *device = 0;
00602
00603 device = m_acAdapters.take(udi);
00604
00605 if (device!=0)
00606 {
00607 delete device;
00608
00609 m_pluggedAdapterCount = 0;
00610
00611 foreach (Solid::Device *d, m_acAdapters)
00612 {
00613 if (d->as<Solid::AcAdapter>()!=0
00614 && d->as<Solid::AcAdapter>()->isPlugged())
00615 {
00616 m_pluggedAdapterCount++;
00617 }
00618 }
00619
00620 return;
00621 }
00622
00623 device = m_batteries.take(udi);
00624
00625 if (device!=0)
00626 {
00627 delete device;
00628 updateBatteryStats();
00629 return;
00630 }
00631
00632 device = m_buttons.take(udi);
00633
00634 if (device!=0)
00635 {
00636 delete device;
00637 return;
00638 }
00639 }
00640
00641 void HalPower::slotBatteryPropertyChanged(const QMap<QString,int> &changes)
00642 {
00643
00644
00645
00646
00647 if (changes.contains("battery.remaining_time")) {
00648 updateBatteryStats();
00649 emit batteryRemainingTimeChanged(batteryRemainingTime());
00650 }
00651 }
00652
00653 #include "halpower.moc"