1 /* This file is part of the KDE project
2 Copyright (C) 2006 Kevin Ottens <ervin@kde.org>
3 Copyright (C) 2008 Dario Freddi <drf54321@gmail.com>
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License version 2 as published by the Free Software Foundation.
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 Boston, MA 02110-1301, USA.
23 #include <QtDBus/QDBusReply>
27 #include "halsuspendjob.h"
29 #include <solid/deviceinterface.h>
30 #include <solid/acadapter.h>
31 #include <solid/battery.h>
32 #include <solid/button.h>
33 #include <solid/genericinterface.h>
35 HalPower::HalPower(QObject
*parent
, const QStringList
& /*args */)
36 : PowerManager(parent
),
37 m_halComputer("org.freedesktop.Hal",
38 "/org/freedesktop/Hal/devices/computer",
39 "org.freedesktop.Hal.Device",
40 QDBusConnection::systemBus()),
41 m_halPowerManagement("org.freedesktop.Hal",
42 "/org/freedesktop/Hal/devices/computer",
43 "org.freedesktop.Hal.Device.SystemPowerManagement",
44 QDBusConnection::systemBus()),
45 m_halCpuFreq("org.freedesktop.Hal",
46 "/org/freedesktop/Hal/devices/computer",
47 "org.freedesktop.Hal.Device.CPUFreq",
48 QDBusConnection::systemBus()),
49 m_halManager("org.freedesktop.Hal",
50 "/org/freedesktop/Hal/Manager",
51 "org.freedesktop.Hal.Manager",
52 QDBusConnection::systemBus())
54 connect(Solid::DeviceNotifier::instance(), SIGNAL(deviceRemoved(const QString
&)),
55 this, SLOT(slotDeviceRemoved(const QString
&)));
56 connect(Solid::DeviceNotifier::instance(), SIGNAL(deviceAdded(const QString
&)),
57 this, SLOT(slotDeviceAdded(const QString
&)));
59 m_pluggedAdapterCount
= 0;
70 qDeleteAll(m_acAdapters
);
71 qDeleteAll(m_batteries
);
72 qDeleteAll(m_buttons
);
75 QStringList
HalPower::supportedSchemes() const
77 return QStringList() << "performance" << "powersaving";
80 QString
HalPower::schemeDescription(const QString
&schemeName
) const
82 if (schemeName
=="performance")
84 return "Use all the performances of the system";
86 else if (schemeName
=="powersaving")
88 return "Try to keep as much power as possible to improve battery life";
98 QString
HalPower::scheme() const
100 // FIXME: We miss an accessor in HAL to make scheme management useful
104 bool HalPower::setScheme(const QString
&name
)
108 if (name
=="powersaving")
112 else if (name
=="performance")
121 QDBusReply
<int> reply
= m_halPowerManagement
.call("SetPowerSave", powersave
);
134 Solid::Control::PowerManager::BatteryState
HalPower::batteryState() const
136 if (m_batteries
.size()==0)
138 return Solid::Control::PowerManager::NoBatteryState
;
140 else if (m_currentBatteryCharge
<= m_criticalBatteryCharge
)
142 return Solid::Control::PowerManager::Critical
;
144 else if (m_currentBatteryCharge
<= m_lowBatteryCharge
)
146 return Solid::Control::PowerManager::Low
;
148 else if (m_currentBatteryCharge
<= m_warningBatteryCharge
)
150 return Solid::Control::PowerManager::Warning
;
154 return Solid::Control::PowerManager::Normal
;
158 int HalPower::batteryChargePercent() const
160 if (!m_maxBatteryCharge
) return 0;
162 return (m_currentBatteryCharge
*100)/m_maxBatteryCharge
;
165 int HalPower::batteryRemainingTime() const
167 return m_estimatedBatteryTime
;
170 Solid::Control::PowerManager::AcAdapterState
HalPower::acAdapterState() const
172 if (m_acAdapters
.size()==0)
174 return Solid::Control::PowerManager::UnknownAcAdapterState
;
176 else if (m_pluggedAdapterCount
==0)
178 return Solid::Control::PowerManager::Unplugged
;
182 return Solid::Control::PowerManager::Plugged
;
186 Solid::Control::PowerManager::SuspendMethods
HalPower::supportedSuspendMethods() const
188 Solid::Control::PowerManager::SuspendMethods supported
= Solid::Control::PowerManager::UnknownSuspendMethod
;
190 QDBusReply
<bool> reply
= m_halComputer
.call("GetPropertyBoolean", "power_management.can_suspend");
194 bool can_suspend
= reply
;
197 supported
|= Solid::Control::PowerManager::ToRam
;
202 kDebug() << reply
.error().name() << ": " << reply
.error().message();
205 reply
= m_halComputer
.call("GetPropertyBoolean", "power_management.can_hibernate");
209 bool can_hibernate
= reply
;
212 supported
|= Solid::Control::PowerManager::ToDisk
;
217 kDebug() << reply
.error().name() << ": " << reply
.error().message();
223 KJob
*HalPower::suspend(Solid::Control::PowerManager::SuspendMethod method
) const
225 return new HalSuspendJob(m_halPowerManagement
,
226 method
, supportedSuspendMethods());
229 Solid::Control::PowerManager::CpuFreqPolicies
HalPower::supportedCpuFreqPolicies() const
231 QDBusReply
<QStringList
> reply
= m_halCpuFreq
.call("GetCPUFreqAvailableGovernors");
233 if (!reply
.isValid())
235 return Solid::Control::PowerManager::UnknownCpuFreqPolicy
;
239 QStringList governors
= reply
;
240 Solid::Control::PowerManager::CpuFreqPolicies policies
= Solid::Control::PowerManager::UnknownCpuFreqPolicy
;
242 foreach (const QString
& governor
, governors
)
244 if (governor
== "ondemand")
246 policies
|= Solid::Control::PowerManager::OnDemand
;
248 else if (governor
== "userspace")
250 policies
|= Solid::Control::PowerManager::Userspace
;
252 else if (governor
== "powersave")
254 policies
|= Solid::Control::PowerManager::Powersave
;
256 else if (governor
== "performance")
258 policies
|= Solid::Control::PowerManager::Performance
;
260 else if (governor
== "conservative")
262 policies
|= Solid::Control::PowerManager::Conservative
;
266 kWarning() << "Unknown governor: " << governor
;
274 Solid::Control::PowerManager::CpuFreqPolicy
HalPower::cpuFreqPolicy() const
276 QDBusReply
<QString
> reply
= m_halCpuFreq
.call("GetCPUFreqGovernor");
278 if (!reply
.isValid())
280 return Solid::Control::PowerManager::UnknownCpuFreqPolicy
;
284 QString governor
= reply
;
286 if (governor
== "ondemand")
288 return Solid::Control::PowerManager::OnDemand
;
290 else if (governor
== "userspace")
292 return Solid::Control::PowerManager::Userspace
;
294 else if (governor
== "powersave")
296 return Solid::Control::PowerManager::Powersave
;
298 else if (governor
== "performance")
300 return Solid::Control::PowerManager::Performance
;
302 else if (governor
== "conservative")
304 return Solid::Control::PowerManager::Conservative
;
308 return Solid::Control::PowerManager::UnknownCpuFreqPolicy
;
313 bool HalPower::setCpuFreqPolicy(Solid::Control::PowerManager::CpuFreqPolicy newPolicy
)
319 case Solid::Control::PowerManager::OnDemand
:
320 governor
= "ondemand";
322 case Solid::Control::PowerManager::Userspace
:
323 governor
= "userspace";
325 case Solid::Control::PowerManager::Powersave
:
326 governor
= "powersave";
328 case Solid::Control::PowerManager::Performance
:
329 governor
= "performance";
331 case Solid::Control::PowerManager::Conservative
:
332 governor
= "conservative";
338 QDBusReply
<int> reply
= m_halCpuFreq
.call("SetCPUFreqGovernor", governor
);
351 bool HalPower::canDisableCpu(int /*cpuNum */) const
356 bool HalPower::setCpuEnabled(int /*cpuNum */, bool /*enabled */)
361 Solid::Control::PowerManager::BrightnessControlsList
HalPower::brightnessControlsAvailable()
363 Solid::Control::PowerManager::BrightnessControlsList deviceList
;
364 foreach(const QString
&name
, m_halManager
.call("FindDeviceByCapability", "laptop_panel").arguments().at(0).toStringList())
366 deviceList
.insert(name
, Solid::Control::PowerManager::Screen
);
368 foreach(const QString
&name
, m_halManager
.call("FindDeviceByCapability", "keyboard_backlight").arguments().at(0).toStringList())
370 deviceList
.insert(name
, Solid::Control::PowerManager::Keyboard
);
375 float HalPower::brightness(const QString
&device
)
378 if(m_halManager
.call("FindDeviceByCapability", "laptop_panel").arguments().at(0).toStringList().contains(device
))
380 QDBusInterface
deviceInterface("org.freedesktop.Hal", device
, "org.freedesktop.Hal.Device.LaptopPanel", QDBusConnection::systemBus());
381 brightness
= deviceInterface
.call("GetBrightness").arguments().at(0).toDouble();
382 if(deviceInterface
.lastError().isValid())
388 QDBusInterface
propertyInterface("org.freedesktop.Hal", device
, "org.freedesktop.Hal.Device", QDBusConnection::systemBus());
389 int levels
= propertyInterface
.call("GetProperty", "laptop_panel.num_levels").arguments().at(0).toInt();
390 return (float)(100*(brightness
/(levels
-1)));
393 if(m_halManager
.call("FindDeviceByCapability", "keyboard_backlight").arguments().at(0).toStringList().contains(device
))
395 QDBusInterface
deviceInterface("org.freedesktop.Hal", device
, "org.freedesktop.Hal.Device.KeyboardBacklight", QDBusConnection::systemBus()); //TODO - I do not have a backlight enabled keyboard, so I'm guessing a bit here. Could someone please check this.
396 brightness
= deviceInterface
.call("GetBrightness").arguments().at(0).toDouble();
397 if(deviceInterface
.lastError().isValid())
403 QDBusInterface
propertyInterface("org.freedesktop.Hal", device
, "org.freedesktop.Hal.Device", QDBusConnection::systemBus());
404 int levels
= propertyInterface
.call("GetProperty", "keyboard_backlight.num_levels").arguments().at(0).toInt();
405 return (float)(100*(brightness
/(levels
-1)));
411 bool HalPower::setBrightness(float brightness
, const QString
&device
)
413 if(m_halManager
.call("FindDeviceByCapability", "laptop_panel").arguments().at(0).toStringList().contains(device
))
415 QDBusInterface
propertyInterface("org.freedesktop.Hal", device
, "org.freedesktop.Hal.Device", QDBusConnection::systemBus());
416 int levels
= propertyInterface
.call("GetProperty", "laptop_panel.num_levels").arguments().at(0).toInt();
417 QDBusInterface
deviceInterface("org.freedesktop.Hal", device
, "org.freedesktop.Hal.Device.LaptopPanel", QDBusConnection::systemBus());
418 deviceInterface
.call("SetBrightness", qRound((levels
-1)*(brightness
/100.0))); // .0? The right way? Feels hackish.
419 if(!deviceInterface
.lastError().isValid())
421 emit(brightnessChanged(brightness
));
425 if(m_halManager
.call("FindDeviceByCapability", "keyboard_backlight").arguments().at(0).toStringList().contains(device
))
427 QDBusInterface
propertyInterface("org.freedesktop.Hal", device
, "org.freedesktop.Hal.Device", QDBusConnection::systemBus());
428 int levels
= propertyInterface
.call("GetProperty", "keyboard_backlight.num_levels").arguments().at(0).toInt();
429 QDBusInterface
deviceInterface("org.freedesktop.Hal", device
, "org.freedesktop.Hal.Device.KeyboardBacklight", QDBusConnection::systemBus()); //TODO - I do not have a backlight enabled keyboard, so I'm guessing a bit here. Could someone please check this.
430 deviceInterface
.call("SetBrightness", qRound((levels
-1)*(brightness
/100.0)));
431 if(!deviceInterface
.lastError().isValid())
433 emit(brightnessChanged(brightness
));
440 void HalPower::computeAcAdapters()
442 QList
<Solid::Device
> adapters
443 = Solid::Device::listFromType(Solid::DeviceInterface::AcAdapter
);
445 foreach (Solid::Device adapter
, adapters
)
447 m_acAdapters
[adapter
.udi()] = new Solid::Device(adapter
);
448 connect(m_acAdapters
[adapter
.udi()]->as
<Solid::AcAdapter
>(), SIGNAL(plugStateChanged(bool, const QString
&)),
449 this, SLOT(slotPlugStateChanged(bool)));
451 if (m_acAdapters
[adapter
.udi()]->as
<Solid::AcAdapter
>()!=0
452 && m_acAdapters
[adapter
.udi()]->as
<Solid::AcAdapter
>()->isPlugged())
454 m_pluggedAdapterCount
++;
459 void HalPower::computeBatteries()
461 QList
<Solid::Device
> batteries
462 = Solid::Device::listFromQuery("Battery.type == 'PrimaryBattery'");
464 foreach (Solid::Device battery
, batteries
)
466 m_batteries
[battery
.udi()] = new Solid::Device(battery
);
467 connect(m_batteries
[battery
.udi()]->as
<Solid::Battery
>(), SIGNAL(chargePercentChanged(int, const QString
&)),
468 this, SLOT(updateBatteryStats()));
469 connect(m_batteries
[battery
.udi()]->as
<Solid::GenericInterface
>(), SIGNAL(propertyChanged(const QMap
<QString
,int> &)),
470 this, SLOT(slotBatteryPropertyChanged(const QMap
<QString
,int> &)));
473 updateBatteryStats();
476 void HalPower::computeButtons()
478 QList
<Solid::Device
> buttons
479 = Solid::Device::listFromType(Solid::DeviceInterface::Button
);
481 foreach (Solid::Device button
, buttons
)
483 m_buttons
[button
.udi()] = new Solid::Device(button
);
484 connect(m_buttons
[button
.udi()]->as
<Solid::Button
>(), SIGNAL(pressed(Solid::Button::ButtonType
, const QString
&)),
485 this, SLOT(slotButtonPressed(Solid::Button::ButtonType
)));
489 void HalPower::updateBatteryStats()
491 m_currentBatteryCharge
= 0;
492 m_maxBatteryCharge
= 0;
493 m_warningBatteryCharge
= 0;
494 m_lowBatteryCharge
= 0;
495 m_criticalBatteryCharge
= 0;
496 m_estimatedBatteryTime
= 0;
498 foreach (Solid::Device
*d
, m_batteries
)
500 Solid::GenericInterface
*interface
= d
->as
<Solid::GenericInterface
>();
502 if (interface
== 0) continue;
504 m_currentBatteryCharge
+= interface
->property("battery.charge_level.current").toInt();
505 m_maxBatteryCharge
+= interface
->property("battery.charge_level.last_full").toInt();
506 m_warningBatteryCharge
+= interface
->property("battery.charge_level.warning").toInt();
507 m_lowBatteryCharge
+= interface
->property("battery.charge_level.low").toInt();
508 m_estimatedBatteryTime
+= interface
->property("battery.remaining_time").toInt() * 1000;
511 m_criticalBatteryCharge
= m_lowBatteryCharge
/2;
514 void HalPower::slotPlugStateChanged(bool newState
)
518 if(m_pluggedAdapterCount
== 0)
520 emit
acAdapterStateChanged(Solid::Control::PowerManager::Plugged
);
522 m_pluggedAdapterCount
++;
526 if(m_pluggedAdapterCount
== 1)
528 emit
acAdapterStateChanged(Solid::Control::PowerManager::Unplugged
);
530 m_pluggedAdapterCount
--;
534 void HalPower::slotButtonPressed(Solid::Button::ButtonType type
)
536 Solid::Button
*button
= qobject_cast
<Solid::Button
*>(sender());
538 if (button
== 0) return;
542 case Solid::Button::PowerButton
:
543 emit
buttonPressed(Solid::Control::PowerManager::PowerButton
);
545 case Solid::Button::SleepButton
:
546 emit
buttonPressed(Solid::Control::PowerManager::SleepButton
);
548 case Solid::Button::LidButton
:
549 if (button
->stateValue())
551 emit
buttonPressed(Solid::Control::PowerManager::LidClose
);
555 emit
buttonPressed(Solid::Control::PowerManager::LidOpen
);
559 kWarning() << "Unknown button type" ;
564 void HalPower::slotDeviceAdded(const QString
&udi
)
566 Solid::Device
*device
= new Solid::Device(udi
);
567 if (device
->is
<Solid::AcAdapter
>())
569 m_acAdapters
[udi
] = device
;
570 connect(m_acAdapters
[udi
]->as
<Solid::AcAdapter
>(), SIGNAL(plugStateChanged(bool, const QString
&)),
571 this, SLOT(slotPlugStateChanged(bool)));
573 if (m_acAdapters
[udi
]->as
<Solid::AcAdapter
>()!=0
574 && m_acAdapters
[udi
]->as
<Solid::AcAdapter
>()->isPlugged())
576 m_pluggedAdapterCount
++;
579 else if (device
->is
<Solid::Battery
>())
581 m_batteries
[udi
] = device
;
582 connect(m_batteries
[udi
]->as
<Solid::Battery
>(), SIGNAL(chargePercentChanged(int, const QString
&)),
583 this, SLOT(updateBatteryStats()));
584 connect(m_batteries
[udi
]->as
<Solid::GenericInterface
>(), SIGNAL(propertyChanged(const QMap
<QString
,int> &)),
585 this, SLOT(slotBatteryPropertyChanged(const QMap
<QString
,int> &)));
587 else if (device
->is
<Solid::Button
>())
589 m_buttons
[udi
] = device
;
590 connect(m_buttons
[udi
]->as
<Solid::Button
>(), SIGNAL(pressed(int, const QString
&)),
591 this, SLOT(slotButtonPressed(int)));
599 void HalPower::slotDeviceRemoved(const QString
&udi
)
601 Solid::Device
*device
= 0;
603 device
= m_acAdapters
.take(udi
);
609 m_pluggedAdapterCount
= 0;
611 foreach (Solid::Device
*d
, m_acAdapters
)
613 if (d
->as
<Solid::AcAdapter
>()!=0
614 && d
->as
<Solid::AcAdapter
>()->isPlugged())
616 m_pluggedAdapterCount
++;
623 device
= m_batteries
.take(udi
);
628 updateBatteryStats();
632 device
= m_buttons
.take(udi
);
641 void HalPower::slotBatteryPropertyChanged(const QMap
<QString
,int> &changes
)
643 /* This slot catches property changes on battery devices. At
644 * the moment it is used to find out remaining time on batteries.
647 if (changes
.contains("battery.remaining_time")) {
648 updateBatteryStats();
649 emit
batteryRemainingTimeChanged(batteryRemainingTime());
653 #include "halpower.moc"