diff options
Diffstat (limited to 'powermanager')
-rw-r--r-- | powermanager/TODO | 49 | ||||
-rwxr-xr-x | powermanager/g-p-m-restart | 6 | ||||
-rw-r--r-- | powermanager/gpmhelper.py | 147 | ||||
-rw-r--r-- | powermanager/guidance-power-manager.desktop | 35 | ||||
-rwxr-xr-x | powermanager/guidance-power-manager.py | 1134 | ||||
-rw-r--r-- | powermanager/guidance_power_manager_ui.py | 241 | ||||
-rw-r--r-- | powermanager/guidance_power_manager_ui.ui | 530 | ||||
-rw-r--r-- | powermanager/hal-test.py | 35 | ||||
-rw-r--r-- | powermanager/notify.py | 68 | ||||
-rw-r--r-- | powermanager/notify.ui | 75 | ||||
-rw-r--r-- | powermanager/powermanage.py | 606 | ||||
-rw-r--r-- | powermanager/powermanager_ui.ui | 924 | ||||
-rw-r--r-- | powermanager/recompile-ui-files | 6 | ||||
-rw-r--r-- | powermanager/tooltip.py | 57 | ||||
-rw-r--r-- | powermanager/tooltip.ui | 53 |
15 files changed, 3966 insertions, 0 deletions
diff --git a/powermanager/TODO b/powermanager/TODO new file mode 100644 index 0000000..bf6d671 --- /dev/null +++ b/powermanager/TODO @@ -0,0 +1,49 @@ +guidance-power-manager TODO: +------------------------------ +- [brightness preview], see below +- make power-manager non-blocking +- Wait with hibernate / suspending if the plug has just been pulled + Some batteries only report remaining_time correctly after 30 or so + seconds + + +DUNNO's: +--------- +- How to detect how long the machine is idle? +- How to perform actions that need root privileges (and are not available via HAL)? +- Should we notify when battery is fully charged? + +FIXED: +------- +- What is "blank"? "Screen Saver", "Blank Screen" or "Monitor off"? +- Handle CPU hotplugging gracefully (try switching off one CPU when g-p-m is running...) +- Make use of kstandardirs +- Add icons to contextmenu +- Remove brightness controls when not hasBrighness +- Remove battery-specifif items from tooltip when there's no battery +- Make settings dialogue not apply instantly (Save config only on OK and Apply) +- Add cpu frequency to tooltip +- Add icons to tooltip +- Make tooltip size properly +- battery hotplugging +- Implement switchToBattery(), collecting all stuff for onBattery + - notify + - blankscreensaveronly + - lowerbrightness + +- Implement switchToAC(), collecting stuff to run when plugged in: + - notify + - undo blankscreensaveronly + - up brightness +- Clicking onto the slider should move the handle to the closest tick, but how? +- support for second battery + +[brightness preview] +Currently there is only a brightness preview for the currently active scheme (_either_ mains or battery powered). +That means if you want to set the battery brightness when you are currently mains powered, you'll probably +move the battery slider, realise that there is no preview, go to the mains slider, move it till you found a nice +brightness level, then go back to the battery slider and set it there. Would be nicer to have a preview for both sliders: +Whenever you move to a new location, the brightness is adjusted. Has to be tested if it should be set back to +previous value after 5 seconds, or if it should remain till you either move the other slider or click save (assuming +explicit apply). + diff --git a/powermanager/g-p-m-restart b/powermanager/g-p-m-restart new file mode 100755 index 0000000..d957de1 --- /dev/null +++ b/powermanager/g-p-m-restart @@ -0,0 +1,6 @@ +#!/bin/bash +echo "stopping guidance-power-manager ..." +dcop `dcopfind -a "power-manager*"` MainApplication-Interface quit + +echo "starting guidance-power-manager ..." +guidance-power-manager.py & diff --git a/powermanager/gpmhelper.py b/powermanager/gpmhelper.py new file mode 100644 index 0000000..65094f7 --- /dev/null +++ b/powermanager/gpmhelper.py @@ -0,0 +1,147 @@ +#!/usr/bin/python +# -*- coding: UTF-8 -*- +""" +Copyright 2008 Sebastian Kügler, Canonical Ltd, Luka Renko + +Authors: + Andreas Wenning <[email protected]> + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +""" + +""" +A frontend to HAL's power features for KDE - Helper application +This application listens for HAL signals and issues dcop-calls to the +kde-power-manager that originally started it. To avoid the need for +kde-power-manager to shut it's helper down, this application +will automatically shut down if it's kde-power-manager isn't running. +""" + +import dbus, sys, time +from dbus.mainloop.glib import DBusGMainLoop +import gobject +from dcopext import DCOPClient, DCOPObj, DCOPApp + +class GPMHelper(): + def mother_alive(self): + """Check that our mother is still alive""" + found = False + for name in self.dcop.registeredApplications(): + name = str(name) + if name == self.motherName: + found = True + if not found: + """No mother; commit suicide""" + print "guidance-power-manager not alive; exiting" + loop.quit() + + """Called when signal is received""" + def signal_recv(self, *args): + if args[0] == "ButtonPressed": + if args[1] == "brightness-up": + if time.time()-0.02 <= self.last_brightness_up <= time.time(): + """Most likely an extra brightness-up call, discarding""" + print "Extra brightness-up call discarded" + return + try: + ok, foo = self.mother.brightnessUp() + if not ok: + print "brightnessUp-call failed" + return self.mother_alive() + self.last_brightness_up = time.time() + except: + print "brightnessUp-call failed" + return self.mother_alive() + elif args[1] == "brightness-down": + if time.time()-0.02 <= self.last_brightness_down <= time.time(): + """Most likely an extra brightness-down call, discarding""" + print "Extra brightness-down call discarded" + return + try: + ok, foo = self.mother.brightnessDown() + if not ok: + print "brightnessDown-call failed" + return self.mother_alive() + self.last_brightness_down = time.time() + except: + print "brightnessDown-call failed" + return self.mother_alive() + elif args[1] == "sleep": + if time.time()-1 <= self.last_sleep <= time.time(): + """Most likely an extra sleep-call, discarding""" + print "Extra sleep-call discarded" + return + try: + ok, foo = self.mother.suspend() + if not ok: + print "suspend-call failed" + return self.mother_alive() + self.last_sleep = time.time() + except: + print "suspend-call failed" + return self.mother_alive() + elif args[1] == "hibernate": + if time.time()-1 <= self.last_hibernate <= time.time(): + """Most likely an extra hibernate-call, discarding""" + print "Extra hibernate-call discarded" + return + try: + ok, foo = self.mother.hibernate() + if not ok: + print "hibernate-call failed" + return self.mother_alive() + self.last_hibernate = time.time() + except: + print "hibernate failed" + return self.mother_alive() + + def __init__(self): + """Connect to HAL""" + self.dbus_loop = DBusGMainLoop(set_as_default=True) + self.bus = dbus.SystemBus(mainloop=self.dbus_loop) + hal_manager_obj = self.bus.get_object("org.freedesktop.Hal",u'/org/freedesktop/Hal/Manager') + self.hal_manager = dbus.Interface(hal_manager_obj, "org.freedesktop.Hal.Manager") + + """Find button-devices and to connect to""" + button_devices = self.hal_manager.FindDeviceByCapability("button") + for device in button_devices: + self.bus.add_signal_receiver(self.signal_recv, + "Condition", + "org.freedesktop.Hal.Device", + "org.freedesktop.Hal", + device) + """Let's find our mother""" + self.dcop = DCOPClient() + self.dcop.attach() + found = False + for name in self.dcop.registeredApplications(): + name = str(name) + if name.startswith('guidance-'): + self.motherName = name + try: + self.mother = DCOPObj(name, self.dcop, 'power-manager') + found = True + except: + """Do nothing, catched by found=False""" + break + if not found: + """No mother; commit suicide""" + print "No guidance-power-manager is running" + sys.exit() + + """Some laptops issue double sleep/hibernate-calls, we need to discard one in that case""" + self.last_sleep = 0 + self.last_hibernate = 0 + + """And multiple brightness calls is also possible""" + self.last_brightness_up = 0 + self.last_brightness_down = 0 + +if __name__ == "__main__": + gpmh = GPMHelper() + loop = gobject.MainLoop() + loop.run() diff --git a/powermanager/guidance-power-manager.desktop b/powermanager/guidance-power-manager.desktop new file mode 100644 index 0000000..2fdaad0 --- /dev/null +++ b/powermanager/guidance-power-manager.desktop @@ -0,0 +1,35 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=Power Manager +Name[el]=Διαχειριστής ενέργειας +Name[es]=Administrador de energía +Name[et]=Toitehaldur +Name[it]=Gestore dell'energia +Name[ja]=電源管理 +Name[nl]=Energiebeheer +Name[pt]=Gestor de Energia +Name[pt_BR]=Gerenciador de Energia +Name[sr]=Управљач енергијом +Name[sr@Latn]=Upravljač energijom +Name[sv]=Energisparfunktion +Name[xx]=xxPower Managerxx +Comment=Power management applet +Comment[el]=Μικροεφαρμογή διαχείρισης ενέργειας +Comment[es]=Applet de administrador de potencia +Comment[et]=Toitehalduse aplett +Comment[it]=Applicazione per la gestione dell'energia +Comment[ja]=電源管理アプレット +Comment[nl]=Energiebeheer-applet +Comment[pt]='Applet' de gestão de energia +Comment[pt_BR]=Mini-aplicativo de gerenciamento de energia +Comment[sr]=Аплет за управљање енергијом +Comment[sr@Latn]=Aplet za upravljanje energijom +Comment[sv]=Miniprogram för energisparfunktion +Comment[xx]=xxPower management appletxx +Icon=guidance-power-manager +Exec=guidance-power-manager +Terminal=false +Type=Application +Categories=Qt;KDE; +OnlyShowIn=KDE; +X-DCOP-ServiceType=Unique diff --git a/powermanager/guidance-power-manager.py b/powermanager/guidance-power-manager.py new file mode 100755 index 0000000..41df5e8 --- /dev/null +++ b/powermanager/guidance-power-manager.py @@ -0,0 +1,1134 @@ +#!/usr/bin/python +# -*- coding: UTF-8 -*- +""" +Copyright 2006-2007 Sebastian Kügler, Canonical Ltd, Luka Renko + +Authors: + Sebastian Kügler <[email protected]> + Jonathan Riddell <[email protected]> + Luka Renko <[email protected]> + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +""" + +""" +A frontend to HAL's power features for KDE. +Supports screen brightness, battery level, plugged/unplugged notices, laptop lid closing actions +Specification at https://wiki.kubuntu.org/KubuntuPowerManagement + +Issues: + - We have to keep polling HAL rather than listening for signals because the Python DBUS bindings + don't have Qt mainloop integration + - Written in Python so will be slow to load up, will probably port to C++ Qt 4.2 in future + - Should also handle UPS and bluetooth batteries + - systray applet should be hidden if no battery, but then how do you suspend if no battery? + (ksmserver integration please) + - Needs lots more testing + - Use KUniqueApplication again as soon as dcop problem is sorted outc + - dcop calls need patch to dcopexport.py, already submitted upstream +""" + +import os +import sys +import subprocess +import dbus + +from qt import * +from kdecore import * +from kdeui import * + +from dcopext import DCOPClient, DCOPApp # used to lock the screen +from dcopexport import DCOPExObj + +from guidance_power_manager_ui import PowerManagerUI +from notify import NotifyWidget +from tooltip import ToolTip + +from powermanage import * + +POLL_INTERVAL = 5000 # in milliseconds + +class Notify(NotifyWidget): + """ Pop up a passive notication windows. """ + + def __init__(self,parent,msg,icon,caption=None): + NotifyWidget.__init__(self,parent,"notify") + self.setIcon(icon) + self.setText(msg) + if caption: + self.Caption(caption) + + def setIcon(self,pixmap): + """ Set an icon to be displayed in the notification. """ + if pixmap: + self.Icon.setPixmap(pixmap) + + def setCaption(self,caption): + """ Text to show in bold letters. """ + self.Caption.setText(QString("<b>")+caption+QString("</b>")) + + def setText(self,msg): + """" Set actual notification message. """ + self.Text.setText(msg) + + +class PowerManager(PowerManagerUI): + """ Our configuration dialog. """ + + def __init__ (self, parent, name): + PowerManagerUI.__init__(self, parent, name) + KGlobal.iconLoader().addAppDir("guidance") + + # The systray icon should show and hide the KDialogBase, not only this widget, + # therefore, it gets our parent as parent. + self.systray = KSystemTray(parent) + self.icon = "battery-charging-100" + self.systray.setPixmap(QPixmap(UserIcon(self.icon))) + self.connect(self.systray, SIGNAL("quitSelected()"), self.quit) + + # Configuration filename + self.config = KConfig("power-managerrc") + + self.powermanager = PowerManage() + + def prepare(self): + """ Prepare UI. """ + self._initBrightness() + self._initLid() + self._initBattery() + self.lastidlesec = 0 + + self._initConfigKeywords() + + self._initUI(self.parent()) + + self.configToUi() + + # Polling: evil. can't receive signals in python-dbus unless we have a glib mainloop, + # so we need to poll + self.pollTimer = QTimer(self) + self.connect(self.pollTimer, SIGNAL("timeout()"), self.poll) + self.pollTimer.start(POLL_INTERVAL) # 5 second poll, maybe make this configurable + self.poll(False) + + # check CPU freq policy and notify if it was changed + msg = self.checkCpuFreq() + if msg != "": + self.notify(msg) + + self.systray.show() + + def _initBrightness(self): + """ Check for brightness support and disable widgets if it's not there. """ + if not self.powermanager.hasBrightness: + self.PoweredBrightnessLabel.hide() + self.PoweredBrightnessSlider.hide() + self.BatteryBrightnessLabel.hide() + self.BatteryBrightnessSlider.hide() + + def _initLid(self): + """ Check for lid support and disable widgets if it's not there. """ + if not self.powermanager.hasLid: + self.LaptopLidRadios.setEnabled(False) + + def _initCB(self, combo, options, values): + """ Initialize QComboBox with proper values from provided options. """ + combo.clear() + for option in options: + combo.insertItem(values[option]) + + def _getCB(self, combo, options): + """ Get current item from QComboBox from config file (string) value. """ + try: + return options[combo.currentItem()] + except IndexError: + return "" + + def _setCB(self, combo, options, default, value): + """ Set current item in QComboBox from string value. """ + try: + num = options.index(value) + except ValueError: + num = default + pass + combo.setCurrentItem(num) + + def _getRB(self, radios, options): + """ Get current item from QRadioButton from config file (string) value. """ + try: + return options[radios.selectedId()] + except IndexError: + return "" + + def _setRB(self, radios, options, default, value): + """ Set current item in QRadioButton from string value. """ + try: + num = options.index(value) + except ValueError: + num = default + pass + radios.setButton(num) + + def _checkOldConfig(self, value, blank): + """ Convert old numerical values to keywords. """ + try: + num_val = int(value) + except ValueError: + return value + if blank: + if num_val == 0: return 'nothing' + if num_val == 1: return 'blank' + if num_val == 2: return 'suspend' + if num_val == 3: return 'hibernate' + if num_val == 4: return 'shutdown' + else: + if num_val == 0: return 'nothing' + if num_val == 1: return 'suspend' + if num_val == 2: return 'hibernate' + if num_val == 3: return 'shutdown' + return value + + + def _initConfigKeywords(self): + """ Define helper maps used with config file keywords. """ + # map action keyword to displayed name (l10n) + self.act_name = {} + self.act_name['nothing'] = i18n("Do nothing") + self.act_name['blank'] = i18n("Blank screen") + self.act_name['suspend'] = i18n("Suspend") + self.act_name['hibernate'] = i18n("Hibernate") + self.act_name['shutdown'] = i18n("Shutdown") + + # map action keyword to action methods + self.act_call = {} + self.act_call['nothing'] = None + self.act_call['blank'] = self.blankScreen + self.act_call['suspend'] = self.suspend + self.act_call['hibernate'] = self.hibernate + self.act_call['shutdown'] = self.shutdown + + # map action keyword to notification description (l10n) + self.act_notify = {} + self.act_notify['nothing'] = i18n("doing nothing") + self.act_notify['blank'] = i18n("blanking screen") + self.act_notify['suspend'] = i18n("suspending") + self.act_notify['hibernate'] = i18n("hibernating") + self.act_notify['shutdown'] = i18n("shutting down") + + # map action keyword to action icon used in notification window + self.act_icon = {} + self.act_icon['nothing'] = None + self.act_icon['blank'] = None + self.act_icon['suspend'] = SmallIcon("suspend") + self.act_icon['hibernate'] = SmallIcon("hibernate") + self.act_icon['shutdown'] = SmallIcon("exit") + + # map policy keyword to displayed name (l10n) + self.freq_name = {} + self.freq_name['dynamic'] = i18n("Dynamic") + self.freq_name['powersave'] = i18n("Powersave") + self.freq_name['performance'] = i18n("Performance") + + # map policy keyword to policy change methods + self.freq_call = {} + self.freq_call['dynamic'] = self.setCpuPolicyDynamic + self.freq_call['powersave'] = self.setCpuPolicyPowersave + self.freq_call['performance'] = self.setCpuPolicyPerformance + + + def _initUI(self, parent): + """ Build dynamic parts of the UI: context menu and tooltip. """ + self.canSuspend = self.powermanager.canSuspend and not self.config.readBoolEntry("disableSuspend", False) + self.canHibernate = self.powermanager.canHibernate and not self.config.readBoolEntry("disableHibernate", False) + + # Connect some signals. Updates in the dialogue apply instantly + self.connect(self.PoweredBrightnessSlider, SIGNAL("valueChanged(int)"), self.changePoweredBrightness) + self.connect(self.BatteryBrightnessSlider, SIGNAL("valueChanged(int)"), self.changeBatteryBrightness) + + #Add a blank tooltip, the tooltipgroup signals are then used for our KPassivePopup + toolTipGroup = QToolTipGroup(self.systray) + QToolTip.add(self.systray, "", toolTipGroup, "blah") + self.connect(toolTipGroup, SIGNAL("showTip(const QString&)"), self.showTip) + self.connect(toolTipGroup, SIGNAL("removeTip()"), self.hideTip) + + # Popup tooltip showing battery level + self.popup = KPassivePopup(self.systray) + + self.tooltip = ToolTip(self.popup) + + self._addBatteryWidgets() + + self._addCpuWidgets() + self.popup.setView(self.tooltip) + + # fill actions for LID + self.lid_act = ['nothing', 'blank', 'suspend', 'hibernate', 'shutdown'] + self.lid_act_def = 0 + # hide LID close actions that are not supported + if not self.canSuspend: + self.laptopClosedSuspend.hide() + if not self.canHibernate: + self.laptopClosedHibernate.hide() + + # fill in only CPU policies that are supported by HW + self.cb_freq = [] # list of supported cpu freq policies + self.cb_freq_def = 0 # always use first policy as default + if self.powermanager.hasCpuFreqGovernors: + self.cb_freq = self.powermanager.getSupportedCpuPolicies() + if len(self.cb_freq) > 0: + self._initCB(self.PoweredFreqCombo, self.cb_freq, self.freq_name) + self._initCB(self.BatteryFreqCombo, self.cb_freq, self.freq_name) + else: + self.PoweredFreqLabel.hide() + self.PoweredFreqCombo.hide() + self.BatteryFreqLabel.hide() + self.BatteryFreqCombo.hide() + + # fill actions in Idle/Critical battery combo boxes + self.cb_act = ['nothing'] # list of supported actions (keywords) + self.cb_act_def_critical = 0 # default action when critical battery + if self.canSuspend: + self.cb_act.append('suspend') + if self.canHibernate: + self.cb_act.append('hibernate') + self.cb_act_def_critical = len(self.cb_act) - 1 # hibernate + self.cb_act.append('shutdown') + if self.cb_act_def_critical == 0: + self.cb_act_def_critical = len(self.cb_act) - 1 # shutdown + self._initCB(self.PoweredIdleCombo, self.cb_act, self.act_name) + self._initCB(self.BatteryIdleCombo, self.cb_act, self.act_name) + self._initCB(self.BatteryCriticalCombo, self.cb_act, self.act_name) + + self.connect(self.PoweredIdleCombo,SIGNAL("activated(int)"),self.slotPoweredIdleActivated) + self.connect(self.BatteryIdleCombo,SIGNAL("activated(int)"),self.slotBatteryIdleActivated) + self.connect(self.BatteryCriticalCombo,SIGNAL("activated(int)"),self.slotBatteryCriticalActivated) + + # add suspend/hibernate to tray's context menu + menu = self.systray.contextMenu() + if self.canSuspend: + action = KAction( i18n("Suspend"), KShortcut(), self.suspend, + self.systray.actionCollection(), "suspend") + action.setIcon("suspend") + action.plug(menu) + if self.canHibernate: + action = KAction( i18n("Hibernate"), KShortcut(), self.hibernate, + self.systray.actionCollection(), "hibernate") + action.setIcon("hibernate") + action.plug(menu) + + # add list of governators + if self.powermanager.hasCpuFreqGovernors and len(self.cb_freq) > 0: + submenu = KPopupMenu(menu) + for policy in self.cb_freq: + action = KRadioAction(self.freq_name[policy], KShortcut(), + self.freq_call[policy], + self.systray.actionCollection(), policy) + action.setExclusiveGroup("freqs") + action.plug(submenu) + + policy = self.powermanager.getCpuPolicy() + if policy in self.cb_freq: + self.systray.actionCollection().action(policy).setChecked(True); + menu.insertItem(i18n("CPU policy"), submenu) + + + # KGlobalAccel crashes the application in pykde + # see http://mats.gmd.de/pipermail/pykde/2006-May/013224.html + #self.globalActions = KGlobalAccel(self) + #self.suspendShortcut = KShortcut("XF86Sleep") + #self.hibernateShortcut = KShortcut("XF86Standby") + #self.hshutdownShortcut = KShortcut("XF86PowerOff") + #self.globalActions.insert("suspend", i18n("Suspend"), i18n("what's this?"), self.suspendShortcut, #self.suspendShortcut, self.suspend) + #self.globalActions.updateConnections() + + def _initBattery(self): + """ Remove non-battery-related widgets if there's no battery bay. """ + if not self.powermanager.hasBattery: + # Disable the Batterybox in the config dialogue, + self.BatteryBox.setEnabled(False) + # And change the icon in the systray, remove the restore option + # This way, we're basically becoming a systray applet, you can + # hibernate and suspend from + self.systray.setPixmap(QPixmap(UserIcon(self.icon))) + if self.powermanager.hasAC: + self.wasOnBattery = self.powermanager.onBattery() + + def configToUi(self): + """ Setup the the values from the config file in the UI.""" + # brightness. + if self.powermanager.hasBrightness: + brightness_high = self.powermanager.brightness_levels + self.BatteryBrightnessSlider.setMaxValue(self.powermanager.brightness_levels-1) + self.PoweredBrightnessSlider.setMaxValue(self.powermanager.brightness_levels-1) + self.BatteryBrightnessSlider.setValue(self.config.readNumEntry("batteryBrightness", int(brightness_high/2))) #default middle + self.PoweredBrightnessSlider.setValue(self.config.readNumEntry("poweredBrightness", brightness_high)) #default highest + + tt_text = "Every step increases or decreases the brightness by %i%%" % int(100/brightness_high) + QToolTip.add(self.BatteryBrightnessSlider, tt_text) + QToolTip.add(self.PoweredBrightnessSlider, tt_text) + + self.lockScreenOnResume.setChecked(self.config.readBoolEntry("lockOnResume", True)) + + # Idletime-related configuration + self._setCB(self.PoweredIdleCombo, self.cb_act, 0, str(self.config.readEntry("poweredIdleAction"))) + self.PoweredIdleTime.setValue(self.config.readNumEntry("poweredIdleTime", 60)) + self._setCB(self.BatteryIdleCombo, self.cb_act, 0, str(self.config.readEntry("batteryIdleAction"))) + self.BatteryIdleTime.setValue(self.config.readNumEntry("batteryIdleTime", 10)) + + self._setCB(self.PoweredFreqCombo, self.cb_freq, self.cb_freq_def, str(self.config.readEntry("poweredFreqPolicy"))) + self._setCB(self.BatteryFreqCombo, self.cb_freq, self.cb_freq_def, str(self.config.readEntry("batteryFreqPolicy"))) + + self.BatteryIdleTime.setValue(self.config.readNumEntry("batteryIdleTime", 10)) # default Do nothing + # battery critical and lid actions. + self._setCB(self.BatteryCriticalCombo, self.cb_act, self.cb_act_def_critical, self._checkOldConfig(self.config.readEntry("batteryCriticalAction", ""), False)) + self._setRB(self.LaptopLidRadios, self.lid_act, self.lid_act_def, self._checkOldConfig(self.config.readEntry("laptopLidAction", ""), True)) + self.CriticalRemainTime.setValue(self.config.readNumEntry("criticalRemainTime", BATTERY_CRITICAL_MINUTES)) + self.criticalLevel = self.CriticalRemainTime.value() + + # Call some slots to disable various spinboxes if necessary + self.slotBatteryCriticalActivated() + self.slotPoweredIdleActivated() + self.slotBatteryIdleActivated() + + + def uiToConfig(self): + """ Read all values from the UI and write them to the config file. """ + self.config.writeEntry("poweredBrightness", self.PoweredBrightnessSlider.value()) + self.config.writeEntry("batteryBrightness", self.BatteryBrightnessSlider.value()) + + self.config.writeEntry("poweredIdleTime", self.PoweredIdleTime.value()) + self.config.writeEntry("poweredIdleAction", self._getCB(self.PoweredIdleCombo, self.cb_act)) + self.config.writeEntry("batteryIdleTime", self.BatteryIdleTime.value()) + self.config.writeEntry("batteryIdleAction", self._getCB(self.BatteryIdleCombo, self.cb_act)) + self.config.writeEntry("poweredFreqPolicy", self._getCB(self.PoweredFreqCombo, self.cb_freq)) + self.config.writeEntry("batteryFreqPolicy", self._getCB(self.BatteryFreqCombo, self.cb_freq)) + + self.config.writeEntry("batteryCriticalAction", self._getCB(self.BatteryCriticalCombo, self.cb_act)) + self.config.writeEntry("criticalRemainTime", self.CriticalRemainTime.value()) + + self.config.writeEntry("laptopLidAction", self._getRB(self.LaptopLidRadios, self.lid_act)) + self.config.writeEntry("lockOnResume", self.lockScreenOnResume.isChecked()) + + self.criticalLevel = self.CriticalRemainTime.value() + + self.config.sync() + + def quit(self): + """ Quit application. """ + kapp.quit() + + def showTip(self, text=""): + """ Pop up the tooltip showing battery data and CPU frequencies. """ + self.popup.show() + + + def showBrightnessPopup(self): + if self.powermanager.onBattery(): + value=self.BatteryBrightnessSlider.value()*100/self.BatteryBrightnessSlider.maxValue() + else: + value=self.PoweredBrightnessSlider.value()*100/self.PoweredBrightnessSlider.maxValue() + self.brightnessPopup = KPassivePopup.message('<b>Brightness:</b> '+str(value)+'%', self.systray) + """pop.setTimeout(3000)""" + self.brightnessPopup.show() + + def setBrightnessUp(self): + """Increments slider value by 10%""" + if self.powermanager.onBattery(): + self.BatteryBrightnessSlider.setValue(float(self.BatteryBrightnessSlider.value())+max(float(self.BatteryBrightnessSlider.maxValue())/float(10),1)) + else: + self.PoweredBrightnessSlider.setValue(float(self.PoweredBrightnessSlider.value())+max(float(self.PoweredBrightnessSlider.maxValue())/float(10),1)) + self.showBrightnessPopup() + + def setBrightnessDown(self): + """Decrements slider value by 10%""" + if self.powermanager.onBattery(): + self.BatteryBrightnessSlider.setValue(float(self.BatteryBrightnessSlider.value())-max(float(self.BatteryBrightnessSlider.maxValue())/float(10),1)) + else: + self.PoweredBrightnessSlider.setValue(float(self.PoweredBrightnessSlider.value())-max(float(self.PoweredBrightnessSlider.maxValue())/float(10),1)) + self.showBrightnessPopup() + + def getBrightness(self): + """Work with percentages - it's a bit nicer""" + if self.powermanager.onBattery(): + value=self.BatteryBrightnessSlider.value()*100/self.BatteryBrightnessSlider.maxValue() + else: + value=self.PoweredBrightnessSlider.value()*100/self.PoweredBrightnessSlider.maxValue() + return QString(str(value)) + + def hideTip(self): + """ Hide the tooltip.""" + self.popup.hide() + + def lockScreen(self): + """ locks the screen using kdesktop """ + # create a new DCOP-Client: + client = DCOPClient() + # connect the client to the local DCOP-server: + client.attach() + # create a DCOP-Application-Object to talk to kdesktop: + kdesktop = DCOPApp('kdesktop', client) + # call a DCOP-function: + try: + ok, foo = kdesktop.KScreensaverIface.lock() + except: + print "Unable to lock the screen. The KDE Screensaver does not seem to be running." + def suspend(self): + """ Lock the screen and initiate a suspend to RAM (S3). """ + if self.config.readBoolEntry("lockOnResume", True): + self.lockScreen() + try: + self.warningPopup.hide() + except AttributeError: + pass # No warningpopup, that's OK. + self.powermanager.suspend() + self.powermanager.resetIdleSeconds() + + def hibernate(self): + """ Lock the screen and initiate a suspend to disk (S4). """ + if self.config.readBoolEntry("lockOnResume", True): + self.lockScreen() + try: + self.warningPopup.hide() + except AttributeError: + pass # No warningpopup, that's OK. + self.powermanager.hibernate() + self.powermanager.resetIdleSeconds() + + def shutdown(self): + """ Perform system shutdown. """ + self.powermanager.shutdown() + + def setCpuPolicyDynamic(self): + """Change frequ for all cpu""" + self.powermanager.setCpuPolicy('dynamic') + self.notify(i18n("CPU frequency policy changed to %1.").arg(self.freq_name['dynamic'])) + + def setCpuPolicyPerformance(self): + """Change frequ for all cpu""" + self.powermanager.setCpuPolicy('performance') + self.notify(i18n("CPU frequency policy changed to %1.").arg(self.freq_name['performance'])) + + def setCpuPolicyPowersave(self): + """Change frequ for all cpu""" + self.powermanager.setCpuPolicy('powersave') + self.notify(i18n("CPU frequency policy changed to %1.").arg(self.freq_name['powersave'])) + + def trySuspend(self): + """ If supported, lock the screen and initiate a suspend to RAM (S3). """ + if self.canSuspend: + self.suspend() + else: + print "Warning: DCOP suspend() called, but not supported." + + def tryHibernate(self): + """ If supported, lock the screen and initiate a suspend to disk (S4). """ + if self.canHibernate: + self.hibernate() + else: + print "Warning: DCOP hibernate() called, but not supported." + + def blankScreen(self): + """ Lock and blank screen. """ + if self.config.readBoolEntry("lockOnResume", True): + self.lockScreen() + self.powermanager.blankScreen() + + def _getIcon(self): + """ Set systray icon depending on battery status/level. """ + if self.powermanager.hasBattery: + if self.batt_state == "not present": + self.icon = "ac-adapter" + if self.batt_state == "charged": + self.icon = "battery-charging-100" + elif self.batt_state == "discharging": + if self.batt_level >= 95: + self.icon = "battery-discharging-100" + elif self.batt_level < 95 and self.batt_level >= 85: + self.icon = "battery-discharging-090" + elif self.batt_level < 85 and self.batt_level >= 75: + self.icon = "battery-discharging-070" + elif self.batt_level < 75 and self.batt_level >= 60: + self.icon = "battery-discharging-060" + elif self.batt_level < 65 and self.batt_level >= 45: + self.icon = "battery-discharging-050" + elif self.batt_level < 45 and self.batt_level >= 30: + self.icon = "battery-discharging-040" + elif self.batt_level < 30 and self.batt_level >= 20: + self.icon = "battery-discharging-030" + elif self.batt_level < 20 and self.batt_level >= 10: + self.icon = "battery-discharging-020" + elif self.batt_level < 10 and self.batt_level >= 5: + self.icon = "battery-discharging-010" + else: + self.icon = "battery-discharging-000" + elif self.batt_state == "charging": + if self.batt_level >= 95: + self.icon = "battery-charging-100" + elif self.batt_level < 95 and self.batt_level >= 85: + self.icon = "battery-charging-090" + elif self.batt_level < 85 and self.batt_level >= 75: + self.icon = "battery-charging-070" + elif self.batt_level < 75 and self.batt_level >= 60: + self.icon = "battery-charging-060" + elif self.batt_level < 65 and self.batt_level >= 45: + self.icon = "battery-charging-050" + elif self.batt_level < 45 and self.batt_level >= 30: + self.icon = "battery-charging-040" + elif self.batt_level < 30 and self.batt_level >= 20: + self.icon = "battery-charging-030" + elif self.batt_level < 20 and self.batt_level >= 10: + self.icon = "battery-charging-020" + elif self.batt_level < 10 and self.batt_level >= 5: + self.icon = "battery-charging-010" + else: + self.icon = "battery-charging-000" + else: + self.icon = "ac-adapter" + return self.icon + + def getIcon(self): + """ Return current icon.""" + return UserIcon(self.icon) + + def setIcon(self): + """ Change the systray/tooltip icon.""" + oldIcon = self.icon + self.icon = self._getIcon() + if self.icon != oldIcon: + self.systray.setPixmap(QPixmap(UserIcon(self.icon))) + self.BattPixmap.setPixmap(QPixmap(UserIcon(self.icon))) + + def notify(self, msg, icon=None): + """ Send a notification popup. """ + if icon: + icon = QPixmap(icon) + else: + icon = QPixmap(SmallIcon("messagebox_info")) + try: + del self.warningPopup + except: + pass + self.warningPopup = KPassivePopup(self.systray) + label = Notify(self.warningPopup, msg, icon) + self.warningPopup.setView(label) + position = QPoint(5,5) + self.warningPopup.show(position) + + def poll(self,notify=True): + """ Check for changes in plugged in status, battery status and laptop lid closed status. """ + debug( "------------ POLL ---------------") + + self.powermanager.checkHAL() + # Battery stuff: + # check for last state, and run plugged / unplugged message if the state changed. + if self.powermanager.hasBattery: + plugged_num = 0 + self.batt_state = "not present" # unknown yet + self.batt_level = self.batt_remain = 0 + self.batt_rate = self.batt_charge = self.batt_full = 0 + for batt in self.powermanager.batteries: + state, level, remain, rate, current, full = self.powermanager.getBatteryState(batt) + self._updateBatteryWidget(batt, state, level, remain, rate) + + ## notify plugged/unplugged batteries + if state == "not present": + if self.powermanager.batteryIsPresent[batt]: + self.notify(i18n("The battery has been removed.")) + self.powermanager.batteryIsPresent[batt] = False + else: # battery present + if not self.powermanager.batteryIsPresent[batt]: + self.notify(i18n("The battery has been inserted.")) + self.powermanager.batteryIsPresent[batt] = True + + ## get cumulative charge levels/rate + self.batt_rate += rate + self.batt_charge += current + self.batt_full += full + + ## calculate overall level (average of present batteries) + self.batt_remain += remain + self.batt_level += level + plugged_num += 1 + + ## calculate overall state (charging/discharging/charged) + if state in ("charging","discharging"): + self.batt_state = state + elif not self.batt_state in ("charging, discharging"): + self.batt_state = state + + # if we know charge and full -> recalculate overall level + if self.batt_full > 0 and self.batt_charge > 0: + self.batt_level = 100 * self.batt_charge / self.batt_full + else: + # if more than one battery present, we need to calculate average level + if plugged_num > 1: + self.batt_level /= plugged_num + + # if rate is reported, calculate remaining time on our own + if self.batt_rate > 0: + if self.batt_state == "charging": + self.batt_remain = 3600 * (float(self.batt_full - self.batt_charge) / self.batt_rate) + if self.batt_state == "discharging": + self.batt_remain = 3600 * (float(self.batt_charge) / self.batt_rate) + + remain_h = self.batt_remain/3600 + remain_m = (self.batt_remain/60)%60 + + blabel = i18n("<b>Battery:</b>") + if self.batt_state == "charged": + blabel += i18n(" fully charged") + elif self.batt_state == "charging": + blabel += i18n(" %i:%02ih to charge" % (remain_h,remain_m)) + elif self.batt_state == "discharging": + blabel += i18n(" %i:%02ih remaining" % (remain_h,remain_m)) + self.BattMainLabel.setText(blabel) + + # update tray icon if needed + self.setIcon() + + # check battery state + self.checkBatteryCritical() + + # check Idletime + self.checkIdletime() + + # CPU stuff + self._updateCpuWidgets() + + if self.powermanager.hasBattery: + on_battery = self.powermanager.onBattery() + if self.powermanager.wasOnBattery != on_battery: + self.powermanager.wasOnBattery = on_battery + debug("poll: states differ") + if not on_battery: + debug("poll: Now on AC") + if notify: + self.powerHasBeenPlugged() + else: + debug("poll: Now on battery") + if notify: + self.powerHasBeenUnplugged() + else: + debug("poll: state is the same") + + # Lid stuff + if self.powermanager.hasLid: + if self.powermanager.getLidClosedState(): + if not self.powermanager.lidClosedState: + self.powermanager.lidClosedState = True + + action = self._getRB(self.LaptopLidRadios, self.lid_act) + if not self.act_name.has_key(action): + action = self.act_name[self.lid_act_def] + + if self.act_call[action] != None: + note = i18n("Laptop lid is closed, %1 now.").arg(self.act_notify[action]) + self.notify(note, self.act_icon[action]) + QTimer.singleShot(2000, self.act_call[action]) + else: + self.powermanager.lidClosedState = False + + def _addBatteryWidgets(self): + """ Adds progressbars to show battery status to the tooltip.""" + BattLayout = QHBoxLayout(None,0,6,"BattLayout") + + self.BattPixmap = QLabel(self.tooltip,"BattLabLayout") + self.BattPixmap.setSizePolicy(QSizePolicy(QSizePolicy.Fixed,QSizePolicy.Fixed,0,0,self.BattPixmap.sizePolicy().hasHeightForWidth())) + self.BattPixmap.setPixmap(QPixmap(UserIcon(self.icon))) + self.BattPixmap.setScaledContents(1) + BattLayout.addWidget(self.BattPixmap) + self.BattMainLabel = QLabel(self.tooltip,"BattMainLabel") + self.BattMainLabel.setText(i18n("<b>Battery:</b>")) + BattLayout.addWidget(self.BattMainLabel) + + # Add to tooltip + self.tooltip.layout().addLayout(BattLayout) + + # Create a progressbar and a label for every battery found, and add it to tooltip + self.BattLabel = {} + self.BattLayout = {} + self.BattProgress = {} + i = 1 + for batt in self.powermanager.batteries: + self.BattLayout[batt] = QHBoxLayout(None,0,6,"BattBarLayout") + self.BattLabel[batt] = QLabel(self.tooltip,"BattLabel") + if len(self.powermanager.batteries) > 1: + self.BattLabel[batt].setText(i18n("Battery %i" % i)) + self.BattLayout[batt].addWidget(self.BattLabel[batt]) + self.BattProgress[batt] = KProgress(self.tooltip,"BattProgress") + self.BattProgress[batt].setMinimumSize(QSize(200,0)) + self.BattLayout[batt].addWidget(self.BattProgress[batt]) + self.tooltip.layout().addLayout(self.BattLayout[batt]) + i += 1 + + + def _updateBatteryWidget(self, batt, state, level, remain, rate): + """ Retrieve battery information and update the related widgets accordingly. """ + self.BattProgress[batt].setEnabled(True) + self.BattProgress[batt].setTotalSteps(100) + self.BattProgress[batt].setProgress(level) + if state == "not present": + self.BattProgress[batt].setFormat(i18n("not present")) + elif state == "charging": + self.BattProgress[batt].setFormat(i18n("Charging (%p%)")) + elif state == "discharging": + if rate > 0: + showrate = rate/1000 + self.BattProgress[batt].setFormat(i18n("Discharging (%p%)") + " - %.d W" % showrate) + else: + self.BattProgress[batt].setFormat(i18n("Discharging (%p%)")) + else: + self.BattProgress[batt].setFormat("%p%") + + def _addCpuWidgets(self): + """ Adds progressbars to show CPU frequencies to the tooltip.""" + if not SHOW_CPUFREQ: + return + if len(self.powermanager.cpus) == 0: + return + + LabelLayout = QHBoxLayout(None,0,6,"layout5") + + self.CpuPixmap = QLabel(self.tooltip,"CpuPixmap") + self.CpuPixmap.setSizePolicy(QSizePolicy(QSizePolicy.Fixed,QSizePolicy.Fixed,0,0,self.CpuPixmap.sizePolicy().hasHeightForWidth())) + self.CpuPixmap.setPixmap(QPixmap(UserIcon("processor"))) + self.CpuPixmap.setScaledContents(1) + LabelLayout.addWidget(self.CpuPixmap) + self.CpuMainLabel = QLabel(self.tooltip,"CpuMainLabel") + self.CpuMainLabel.setText(i18n("<b>CPU Frequency:</b>")) + LabelLayout.addWidget(self.CpuMainLabel) + + # Add to tooltip + self.tooltip.layout().addLayout(LabelLayout) + + # Create a progressbar and a label for every CPU found, and add it to tooltip + self.CpuLabel = {} + self.CpuLayout = {} + self.CpuProgress = {} + i = 1 + for cpu in self.powermanager.cpus: + self.CpuLayout[cpu] = QHBoxLayout(None,0,6,"layout2") + self.CpuLabel[cpu] = QLabel(self.tooltip,"CpuLabel") + if len(self.powermanager.cpus) > 1: + self.CpuLabel[cpu].setText(i18n("Processor %i" % i)) + self.CpuLayout[cpu].addWidget(self.CpuLabel[cpu]) + self.CpuProgress[cpu] = KProgress(self.tooltip,"CpuProgress") + self.CpuProgress[cpu].setFormat("%v MHz") + self.CpuLayout[cpu].addWidget(self.CpuProgress[cpu]) + self.tooltip.layout().addLayout(self.CpuLayout[cpu]) + i += 1 + + def slotPoweredIdleActivated(self, index=False): + """ Signal slot for activated powered idle action. """ + if not index: + index = self.PoweredIdleCombo.currentItem() + self.PoweredIdleTime.setEnabled(index != 0) + + def slotBatteryIdleActivated(self, index=False): + """ Signal slot for activated battery idle action. """ + if not index: + index = self.BatteryIdleCombo.currentItem() + self.BatteryIdleTime.setEnabled(index != 0) + + def slotBatteryCriticalActivated(self, index=False): + """ Signal slot for activated battery critical action. """ + if not index: + index = self.BatteryCriticalCombo.currentItem() + self.CriticalRemainTime.setEnabled(index != 0) + + def _updateCpuWidgets(self): + """ Retrieve CPU freq information and update the related widgets accordingly. """ + if not SHOW_CPUFREQ: + return + if len(self.powermanager.cpus) == 0: + return + + clabel = i18n("<b>CPU Frequency:</b>") + " " + policy = self.powermanager.getCpuPolicy() + if self.freq_name.has_key(policy): + clabel += self.freq_name[policy] # get l10n name + else: + clabel += policy + self.CpuMainLabel.setText(clabel) + + for cpu in self.powermanager.cpus: + cpustate = self.powermanager.getCpuState(cpu) + if not cpustate['online']: + self.CpuProgress[cpu].setEnabled(False) + else: + self.CpuProgress[cpu].setEnabled(True) + self.CpuProgress[cpu].setTotalSteps(cpustate['max']) + self.CpuProgress[cpu].setProgress(cpustate['cur']) + if policy != "": + self.systray.actionCollection().action(policy).setChecked(True) + if policy in self.cb_freq: + self.systray.actionCollection().action(policy).setChecked(True) + + def changePoweredBrightness(self, level=None): + """ Mains-powered brigthness slider has been moved. """ + # Check if the state applies and adjust brightness immediately. + if not self.powermanager.onBattery() and self.powermanager.hasBrightness: + if not level: + level = self.PoweredBrightnessSlider.value() + self.powermanager.adjustBrightness(level) + + def changeBatteryBrightness(self, level=None): + """ Battery-powered brigthness slider has been moved. """ + # Check if the state applies and adjust brightness immediately. + if self.powermanager.onBattery() and self.powermanager.hasBrightness: + if not level: + level = self.BatteryBrightnessSlider.value() + self.powermanager.adjustBrightness(level) + + + + + def checkCpuFreq(self): + """ Adjust CPU frequency policy according to current state """ + if not self.powermanager.hasCpuFreqGovernors: + return "" + + if self.powermanager.onBattery(): + policy = str(self.config.readEntry("batteryFreqPolicy")) + else: + policy = str(self.config.readEntry("poweredFreqPolicy")) + if policy == "": + policy = 'dynamic' + + # check if specified policy is supported by HW + if not policy in self.cb_freq: + print "Warning: policy from config file not supported: ", policy + return "" + + current_policy = self.powermanager.getCpuPolicy() + if current_policy != policy: + debug("Switching CPU policy from %s to %s." % (current_policy, policy)) + self.powermanager.setCpuPolicy(policy) + return i18n("CPU frequency policy changed to %1.").arg(self.freq_name[policy]) + elif current_policy == 'dynamic': + debug("Dynamic policy -> update policy (conservative/ondemand)") + self.powermanager.setCpuPolicy(policy) + + debug("CPU policy will stay %s" % current_policy) + return "" + + def powerHasBeenUnplugged(self): + """ Actions to perform when the plug has been pulled.""" + if self.powermanager.hasBrightness: + self.powermanager.adjustBrightness(self.BatteryBrightnessSlider.value()) + self.powermanager.setPowerSave(True) + self.checkBatteryCritical() + self.changeBatteryBrightness() + self.powermanager.setScreensaverBlankOnly(True) + self.powermanager.resetIdleSeconds() + msg = self.checkCpuFreq() + if self.powermanager.hasAC: + self.notify(i18n("The AC adapter has been unplugged, switching to battery mode.")+"\n"+msg, self.getIcon()) + + def powerHasBeenPlugged(self): + """ Actions to perform when AC adapter has been plugged in. """ + if self.powermanager.hasBrightness: + self.powermanager.adjustBrightness(self.PoweredBrightnessSlider.value()) + self.powermanager.setPowerSave(False) + self.changePoweredBrightness() + self.powermanager.setScreensaverBlankOnly(False) + msg = self.checkCpuFreq() + self.powermanager.resetIdleSeconds() + self.notify(i18n("The AC adapter has been plugged in, switching to AC mode.")+"\n"+msg, self.getIcon()) + + def checkBatteryCritical(self): + """ Check for warning and critical battery label and notify-warn or + initiate the configured action. """ + + if not self.powermanager.hasBattery: + return + + if self.batt_state == "discharging": + currentLevel = int(self.batt_remain/60) + + warningLevel = self.criticalLevel + 5 # warn five minutes before critical + criticalLevel = self.criticalLevel + + debug("CurrentBat: %i, WarningBat: %i, CriticalBat: %i" % (currentLevel, warningLevel, criticalLevel)) + # We only want to suspend if the chargelevel is above a certain threshold, + # it sometimes takes some time for HAL to report remaining time correctly + if currentLevel <= criticalLevel and self.batt_level < CHARGE_LEVEL_THRESHOLD: + if not self.powermanager.criticalBatteryState and self.powermanager.onBattery(): + self.powermanager.criticalBatteryState = True + + action = str(self.config.readEntry("batteryCriticalAction")) + if not self.act_name.has_key(action): + action = self.act_name[self.cb_act_def_critical] + + note = i18n("You are about to run out of battery power, %1 now.").arg(self.act_notify[action]) + self.notify(note, self.act_icon[action]) + if self.act_call[action] != None: + QTimer.singleShot(2000, self.act_call[action]) + else: + self.powermanager.criticalBatteryState = False + if currentLevel <= warningLevel and self.batt_level < CHARGE_LEVEL_THRESHOLD: + if not self.powermanager.warningBatteryState: + self.powermanager.warningBatteryState = True + self.notify(i18n("You are low on battery power."), self.getIcon()) + else: + self.powermanager.warningBatteryState = False + + def checkIdletime(self): + """ Reads the idle time and does some action. """ + idlesec = round(self.powermanager.getIdleSeconds()/60, 2) + if self.powermanager.onBattery(): + idleTime = self.config.readNumEntry("batteryIdleTime", 10) + action = str(self.config.readEntry("batteryIdleAction")) + else: + idleTime = self.config.readNumEntry("poweredIdleTime", 60) + action = str(self.config.readEntry("poweredIdleAction")) + if not self.act_name.has_key(action): + action = 'nothing' + + if idlesec - self.lastidlesec > 100: + debug("last: %u" % (idlesec - self.lastidlesec)) + return # probably bogus idleseconds right after suspend + self.lastidlesec = idlesec + if self.act_call[action] == None: + return # doing nothing anyway + if idlesec > idleTime: + note = i18n("System idle for at least %1 minutes, %2 now.").arg(idleTime).arg(self.act_notify[action]) + self.notify(note, self.act_icon[action]) + QTimer.singleShot(2000, self.act_call[action]) + + + +def doDcop(kapp): + """ Register kvandale in dcop, so it can be controlled from outside. """ + my_dcop = kapp.dcopClient() + #my_dcop.attach() + #my_dcop.registerAs("power-manager") + + +class DcopIface (DCOPExObj): + """ Add some interface so we can use powermanager from the outside. """ + def __init__ (self, app, id='power-manager'): + DCOPExObj.__init__ (self, id) + # addMethod (<signature>, <Python method>) + #self.addMethod ('QString getQuery()', gvd.getZoekbegrip) + + # PM related. + self.addMethod ('void suspend ()', app.trySuspend) + self.addMethod ('void hibernate ()', app.tryHibernate) + self.addMethod ('void shutdown ()', app.shutdown) + + # UI related. + self.addMethod ('void showTip ()', app.showTip) + #self.addMethod ('void show ()', app.parent().show) + #self.addMethod ('void hide ()', app.parent().hide) + + #self.addMethod ('void plugged ()', app.powerHasBeenPlugged) + #self.addMethod ('void unplugged ()', app.powerHasBeenUnplugged) + self.addMethod ('bool onBattery ()', app.powermanager.onBattery) + + self.addMethod('void brightnessUp ()', app.setBrightnessUp) + self.addMethod('void brightnessDown ()', app.setBrightnessDown) + self.addMethod('QString getBrightness ()', app.getBrightness) + + #self.addMethod ('QString getCurrentResult()', gvd.getRawResult) + + +class PowermanagerApp(KDialogBase): + """ The KDialog providing the OK, Apply and Cancel buttons.""" + + def __init__(self,parent=None,name=None): + """ Initialise dialog and set mainwidget. """ + KGlobal.locale().insertCatalogue("guidance") + KGlobal.iconLoader().addAppDir("guidance") + + # We would like to use a KUniqueApplication, but that breaks dcop due to some + # strange bug. The following line is the revenge code for this bug, it is + # intentionally ugly. + if len(os.popen("dcop |grep guidance-").readlines()) > 1: + print "There is already an instance of power manager running. Exiting." + sys.exit(0) + + # Which buttons do we want? + KDialogBase.__init__(self,KJanusWidget.Swallow,i18n("Power Manager"), + KDialogBase.Ok|KDialogBase.Apply|KDialogBase.Cancel|KDialogBase.User1, KDialogBase.Close) + self.pmwidget = PowerManager(self,name) + self.setButtonText(KDialogBase.User1, i18n("About")) + + if not self.pmwidget.powermanager.isLaptop(): + print "This is not a laptop, quitting ... " + sys.exit(1) + + self.pmwidget.prepare() + + self.setMainWidget(self.pmwidget) + self.aboutus = KAboutApplication(self) + + def slotOk(self): + """ The OK button has been pressed, save configuration and pass on do whatever + needs to be done by KDialog. """ + self.pmwidget.uiToConfig() + self.pmwidget.checkCpuFreq() + KDialogBase.slotOk(self) + + def slotApply(self): + """ The Apply button has been pressed, save configuration and pass on do whatever + needs to be done by KDialog. """ + self.pmwidget.uiToConfig() + self.pmwidget.checkCpuFreq() + KDialogBase.slotApply(self) + + def slotCancel(self): + """ The Cancel button has been pressed, reset some values and hide dialogue. """ + # In case brightness has changed, we reset it to the configured value. + if self.pmwidget.powermanager.hasBrightness: + brightness_high = self.pmwidget.powermanager.brightness_levels + if not self.pmwidget.powermanager.onBattery(): + level = self.pmwidget.config.readNumEntry("poweredBrightness", brightness_high) + else: + level = self.pmwidget.config.readNumEntry("batteryBrightness", int(brightness_high/2)) + self.pmwidget.powermanager.adjustBrightness(level) + self.pmwidget.configToUi() + KDialogBase.slotCancel(self) + + def slotUser1(self): + self.aboutus.show() + +# There's a bug in KUniqueApplication that shows the pid in the dcop name, +# this fugly hack works around it. +class PMApp(KApplication): + + def name(self): + return "power-manager" + + +if __name__ == "__main__": + aboutdata = KAboutData("guidance", "Power Manager", "0.8.0", + "Handles battery, display and suspend modes for your computer.", KAboutData.License_GPL, + "(C) 2006-2007 Sebastian Kügler, Canonical Ltd, Luka Renko", + None, None, "[email protected]") + aboutdata.addAuthor("Sebastian Kügler", "Developer", "[email protected]","http://vizZzion.org") + aboutdata.addAuthor("Jonathan Riddell", "Developer", "[email protected]") + aboutdata.addAuthor("Luka Renko", "Developer", "[email protected]") + aboutdata.setProgramLogo(QImage("power-manager.png")) + KCmdLineArgs.init(sys.argv, aboutdata) + #kapp = KUniqueApplication(True, True, False) + #kapp = KApplication() + kapp = PMApp(True, True) + mainWindow = PowermanagerApp(None, "main window") + doDcop(kapp) + dcop_iface = DcopIface(mainWindow.pmwidget) + """Start helper module / button listener""" + try: + helperPid = os.spawnl(os.P_NOWAIT, os.path.dirname(__file__)+'/gpmhelper.py', 'gpmhelper.py') + except: + """Non-fatal if this fails""" + print "Unable to start button-listener" + + kapp.exec_loop() + + """Kill helper module / button listener""" + os.system('kill '+str(helperPid)) diff --git a/powermanager/guidance_power_manager_ui.py b/powermanager/guidance_power_manager_ui.py new file mode 100644 index 0000000..13cbc7c --- /dev/null +++ b/powermanager/guidance_power_manager_ui.py @@ -0,0 +1,241 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'guidance_power_manager_ui.ui' +# +# Created: Thu Apr 10 00:50:39 2008 +# by: The PyQt User Interface Compiler (pyuic) 3.17.4 +# +# WARNING! All changes made in this file will be lost! + + +import sys +from qt import * +from kdecore import KCmdLineArgs, KApplication +from kdecore import i18n +from kdeui import * + + + +class PowerManagerUI(QWidget): + def __init__(self,parent = None,name = None,fl = 0): + QWidget.__init__(self,parent,name,fl) + + if not name: + self.setName("PowerManagerUI") + + self.setMouseTracking(1) + + PowerManagerUILayout = QVBoxLayout(self,11,6,"PowerManagerUILayout") + + self.GeneralSettingsBox = QGroupBox(self,"GeneralSettingsBox") + self.GeneralSettingsBox.setColumnLayout(0,Qt.Vertical) + self.GeneralSettingsBox.layout().setSpacing(6) + self.GeneralSettingsBox.layout().setMargin(11) + GeneralSettingsBoxLayout = QVBoxLayout(self.GeneralSettingsBox.layout()) + GeneralSettingsBoxLayout.setAlignment(Qt.AlignTop) + + self.lockScreenOnResume = QCheckBox(self.GeneralSettingsBox,"lockScreenOnResume") + GeneralSettingsBoxLayout.addWidget(self.lockScreenOnResume) + PowerManagerUILayout.addWidget(self.GeneralSettingsBox) + + self.MainsPoweredBox = QGroupBox(self,"MainsPoweredBox") + self.MainsPoweredBox.setSizePolicy(QSizePolicy(QSizePolicy.Preferred,QSizePolicy.Fixed,0,0,self.MainsPoweredBox.sizePolicy().hasHeightForWidth())) + self.MainsPoweredBox.setColumnLayout(0,Qt.Vertical) + self.MainsPoweredBox.layout().setSpacing(6) + self.MainsPoweredBox.layout().setMargin(11) + MainsPoweredBoxLayout = QVBoxLayout(self.MainsPoweredBox.layout()) + MainsPoweredBoxLayout.setAlignment(Qt.AlignTop) + + layout17 = QHBoxLayout(None,0,6,"layout17") + + self.PoweredBrightnessLabel = QLabel(self.MainsPoweredBox,"PoweredBrightnessLabel") + layout17.addWidget(self.PoweredBrightnessLabel) + + self.PoweredBrightnessSlider = QSlider(self.MainsPoweredBox,"PoweredBrightnessSlider") + self.PoweredBrightnessSlider.setMouseTracking(1) + self.PoweredBrightnessSlider.setAcceptDrops(1) + self.PoweredBrightnessSlider.setMaxValue(7) + self.PoweredBrightnessSlider.setLineStep(1) + self.PoweredBrightnessSlider.setPageStep(1) + self.PoweredBrightnessSlider.setOrientation(QSlider.Horizontal) + self.PoweredBrightnessSlider.setTickmarks(QSlider.Both) + self.PoweredBrightnessSlider.setTickInterval(0) + layout17.addWidget(self.PoweredBrightnessSlider) + MainsPoweredBoxLayout.addLayout(layout17) + + layout13 = QHBoxLayout(None,0,6,"layout13") + spacer12_3_2_2 = QSpacerItem(200,20,QSizePolicy.Expanding,QSizePolicy.Minimum) + layout13.addItem(spacer12_3_2_2) + + self.PoweredIdleLabel = QLabel(self.MainsPoweredBox,"PoweredIdleLabel") + layout13.addWidget(self.PoweredIdleLabel) + + self.PoweredIdleTime = QSpinBox(self.MainsPoweredBox,"PoweredIdleTime") + layout13.addWidget(self.PoweredIdleTime) + + self.PoweredIdleCombo = QComboBox(0,self.MainsPoweredBox,"PoweredIdleCombo") + layout13.addWidget(self.PoweredIdleCombo) + MainsPoweredBoxLayout.addLayout(layout13) + + layout13_2_2 = QHBoxLayout(None,0,6,"layout13_2_2") + spacer12_3_2_2_3_2 = QSpacerItem(200,20,QSizePolicy.Expanding,QSizePolicy.Minimum) + layout13_2_2.addItem(spacer12_3_2_2_3_2) + + self.PoweredFreqLabel = QLabel(self.MainsPoweredBox,"PoweredFreqLabel") + layout13_2_2.addWidget(self.PoweredFreqLabel) + + self.PoweredFreqCombo = QComboBox(0,self.MainsPoweredBox,"PoweredFreqCombo") + layout13_2_2.addWidget(self.PoweredFreqCombo) + MainsPoweredBoxLayout.addLayout(layout13_2_2) + PowerManagerUILayout.addWidget(self.MainsPoweredBox) + + self.BatteryBox = QGroupBox(self,"BatteryBox") + self.BatteryBox.setSizePolicy(QSizePolicy(QSizePolicy.Preferred,QSizePolicy.Fixed,0,0,self.BatteryBox.sizePolicy().hasHeightForWidth())) + self.BatteryBox.setColumnLayout(0,Qt.Vertical) + self.BatteryBox.layout().setSpacing(6) + self.BatteryBox.layout().setMargin(11) + BatteryBoxLayout = QVBoxLayout(self.BatteryBox.layout()) + BatteryBoxLayout.setAlignment(Qt.AlignTop) + + layout16 = QHBoxLayout(None,0,6,"layout16") + + self.BatteryBrightnessLabel = QLabel(self.BatteryBox,"BatteryBrightnessLabel") + layout16.addWidget(self.BatteryBrightnessLabel) + + self.BatteryBrightnessSlider = QSlider(self.BatteryBox,"BatteryBrightnessSlider") + self.BatteryBrightnessSlider.setMouseTracking(1) + self.BatteryBrightnessSlider.setMaxValue(7) + self.BatteryBrightnessSlider.setPageStep(1) + self.BatteryBrightnessSlider.setOrientation(QSlider.Horizontal) + self.BatteryBrightnessSlider.setTickmarks(QSlider.Both) + layout16.addWidget(self.BatteryBrightnessSlider) + BatteryBoxLayout.addLayout(layout16) + + layout14 = QGridLayout(None,1,1,0,6,"layout14") + + self.BatteryIdleCombo = QComboBox(0,self.BatteryBox,"BatteryIdleCombo") + + layout14.addWidget(self.BatteryIdleCombo,1,4) + + self.BatteryIdleLabel = QLabel(self.BatteryBox,"BatteryIdleLabel") + + layout14.addWidget(self.BatteryIdleLabel,1,2) + + self.BatteryCriticalCombo = QComboBox(0,self.BatteryBox,"BatteryCriticalCombo") + + layout14.addWidget(self.BatteryCriticalCombo,0,4) + + self.BatteryCriticalLabel = QLabel(self.BatteryBox,"BatteryCriticalLabel") + + layout14.addMultiCellWidget(self.BatteryCriticalLabel,0,0,1,2) + + self.BatteryIdleTime = QSpinBox(self.BatteryBox,"BatteryIdleTime") + + layout14.addWidget(self.BatteryIdleTime,1,3) + + self.CriticalRemainTime = QSpinBox(self.BatteryBox,"CriticalRemainTime") + + layout14.addWidget(self.CriticalRemainTime,0,3) + spacer12_3 = QSpacerItem(28,20,QSizePolicy.Expanding,QSizePolicy.Minimum) + layout14.addItem(spacer12_3,0,0) + spacer12_3_2 = QSpacerItem(50,20,QSizePolicy.Expanding,QSizePolicy.Minimum) + layout14.addMultiCell(spacer12_3_2,1,1,0,1) + BatteryBoxLayout.addLayout(layout14) + + layout13_2 = QHBoxLayout(None,0,6,"layout13_2") + spacer12_3_2_2_3 = QSpacerItem(200,20,QSizePolicy.Expanding,QSizePolicy.Minimum) + layout13_2.addItem(spacer12_3_2_2_3) + + self.BatteryFreqLabel = QLabel(self.BatteryBox,"BatteryFreqLabel") + layout13_2.addWidget(self.BatteryFreqLabel) + + self.BatteryFreqCombo = QComboBox(0,self.BatteryBox,"BatteryFreqCombo") + layout13_2.addWidget(self.BatteryFreqCombo) + BatteryBoxLayout.addLayout(layout13_2) + PowerManagerUILayout.addWidget(self.BatteryBox) + + self.LaptopLidRadios = QButtonGroup(self,"LaptopLidRadios") + self.LaptopLidRadios.setSizePolicy(QSizePolicy(QSizePolicy.Preferred,QSizePolicy.Fixed,0,0,self.LaptopLidRadios.sizePolicy().hasHeightForWidth())) + self.LaptopLidRadios.setFrameShape(QButtonGroup.GroupBoxPanel) + self.LaptopLidRadios.setColumnLayout(0,Qt.Vertical) + self.LaptopLidRadios.layout().setSpacing(5) + self.LaptopLidRadios.layout().setMargin(11) + LaptopLidRadiosLayout = QHBoxLayout(self.LaptopLidRadios.layout()) + LaptopLidRadiosLayout.setAlignment(Qt.AlignTop) + + self.laptopClosedNone = QRadioButton(self.LaptopLidRadios,"laptopClosedNone") + LaptopLidRadiosLayout.addWidget(self.laptopClosedNone) + + self.laptopClosedBlank = QRadioButton(self.LaptopLidRadios,"laptopClosedBlank") + LaptopLidRadiosLayout.addWidget(self.laptopClosedBlank) + + self.laptopClosedSuspend = QRadioButton(self.LaptopLidRadios,"laptopClosedSuspend") + LaptopLidRadiosLayout.addWidget(self.laptopClosedSuspend) + + self.laptopClosedHibernate = QRadioButton(self.LaptopLidRadios,"laptopClosedHibernate") + LaptopLidRadiosLayout.addWidget(self.laptopClosedHibernate) + + self.laptopClosedShutdown = QRadioButton(self.LaptopLidRadios,"laptopClosedShutdown") + LaptopLidRadiosLayout.addWidget(self.laptopClosedShutdown) + spacer12_2 = QSpacerItem(213,20,QSizePolicy.Expanding,QSizePolicy.Minimum) + LaptopLidRadiosLayout.addItem(spacer12_2) + PowerManagerUILayout.addWidget(self.LaptopLidRadios) + spacer11 = QSpacerItem(31,80,QSizePolicy.Minimum,QSizePolicy.Expanding) + PowerManagerUILayout.addItem(spacer11) + + self.languageChange() + + self.resize(QSize(505,374).expandedTo(self.minimumSizeHint())) + self.clearWState(Qt.WState_Polished) + + + def languageChange(self): + self.setCaption(i18n("PowerManagerUI")) + self.GeneralSettingsBox.setTitle(i18n("General Settings")) + self.lockScreenOnResume.setText(i18n("Lock screen on resume")) + self.MainsPoweredBox.setTitle(i18n("Mains Powered")) + self.PoweredBrightnessLabel.setText(i18n("Brightness")) + QWhatsThis.add(self.PoweredBrightnessSlider,i18n("With this slider you can set the brightness when the system is plugged into the socket outlet")) + self.PoweredIdleLabel.setText(i18n("When the system is idle for more than")) + self.PoweredIdleTime.setPrefix(QString.null) + self.PoweredIdleTime.setSuffix(i18n(" min")) + QWhatsThis.add(self.PoweredIdleTime,i18n("To prevent data loss or other damage, you can have the system suspend or hibernate, so you don't run accidentally out of battery power. Configure the number of minutes below which the machine will run the configured action.")) + self.PoweredFreqLabel.setText(i18n("CPU frequency scaling policy")) + self.BatteryBox.setTitle(i18n("Battery Powered")) + self.BatteryBrightnessLabel.setText(i18n("Brightness")) + QWhatsThis.add(self.BatteryBrightnessSlider,i18n("This slider controls the brightness when the system runs on batteries")) + self.BatteryIdleLabel.setText(i18n("When the system is idle for more than")) + self.BatteryCriticalLabel.setText(i18n("When battery remaining time drops below")) + self.BatteryIdleTime.setPrefix(QString.null) + self.BatteryIdleTime.setSuffix(i18n(" min")) + QWhatsThis.add(self.BatteryIdleTime,i18n("To prevent data loss or other damage, you can have the system suspend or hibernate, so you don't run accidentally out of battery power. Configure the number of minutes below which the machine will run the configured action.")) + self.CriticalRemainTime.setPrefix(QString.null) + self.CriticalRemainTime.setSuffix(i18n(" min")) + QWhatsThis.add(self.CriticalRemainTime,i18n("To prevent data loss or other damage, you can have the system suspend or hibernate, so you don't run accidentally out of battery power. Configure the number of minutes below which the machine will run the configured action.")) + self.BatteryFreqLabel.setText(i18n("CPU frequency scaling policy")) + self.LaptopLidRadios.setTitle(i18n("When Laptop Lid Closed")) + self.laptopClosedNone.setText(i18n("Do nothing")) + self.laptopClosedBlank.setText(i18n("Lock screen")) + self.laptopClosedSuspend.setText(i18n("Suspend")) + QToolTip.add(self.laptopClosedSuspend,i18n("Suspend to Memory")) + QWhatsThis.add(self.laptopClosedSuspend,i18n("Suspend is a sleep state, the system will consume only very little energy when suspended")) + self.laptopClosedHibernate.setText(i18n("Hibernate")) + QToolTip.add(self.laptopClosedHibernate,i18n("Suspend to Disk")) + QWhatsThis.add(self.laptopClosedHibernate,i18n("Hibernate or \"Suspend to Disk\" is a deep sleepstate, allowing the system to power off completely")) + self.laptopClosedShutdown.setText(i18n("Shutdown")) + QToolTip.add(self.laptopClosedShutdown,i18n("Halt the machine")) + + +if __name__ == "__main__": + appname = "" + description = "" + version = "" + + KCmdLineArgs.init (sys.argv, appname, description, version) + a = KApplication () + + QObject.connect(a,SIGNAL("lastWindowClosed()"),a,SLOT("quit()")) + w = PowerManagerUI() + a.setMainWidget(w) + w.show() + a.exec_loop() diff --git a/powermanager/guidance_power_manager_ui.ui b/powermanager/guidance_power_manager_ui.ui new file mode 100644 index 0000000..77aa884 --- /dev/null +++ b/powermanager/guidance_power_manager_ui.ui @@ -0,0 +1,530 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>PowerManagerUI</class> +<widget class="QWidget"> + <property name="name"> + <cstring>PowerManagerUI</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>505</width> + <height>374</height> + </rect> + </property> + <property name="caption"> + <string>PowerManagerUI</string> + </property> + <property name="mouseTracking"> + <bool>true</bool> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QGroupBox"> + <property name="name"> + <cstring>GeneralSettingsBox</cstring> + </property> + <property name="title"> + <string>General Settings</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox"> + <property name="name"> + <cstring>lockScreenOnResume</cstring> + </property> + <property name="text"> + <string>Lock screen on resume</string> + </property> + </widget> + </vbox> + </widget> + <widget class="QGroupBox"> + <property name="name"> + <cstring>MainsPoweredBox</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="title"> + <string>Mains Powered</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout17</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>PoweredBrightnessLabel</cstring> + </property> + <property name="text"> + <string>Brightness</string> + </property> + </widget> + <widget class="QSlider"> + <property name="name"> + <cstring>PoweredBrightnessSlider</cstring> + </property> + <property name="mouseTracking"> + <bool>true</bool> + </property> + <property name="acceptDrops"> + <bool>true</bool> + </property> + <property name="maxValue"> + <number>7</number> + </property> + <property name="lineStep"> + <number>1</number> + </property> + <property name="pageStep"> + <number>1</number> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="tickmarks"> + <enum>Both</enum> + </property> + <property name="tickInterval"> + <number>0</number> + </property> + <property name="whatsThis" stdset="0"> + <string>With this slider you can set the brightness when the system is plugged into the socket outlet</string> + </property> + </widget> + </hbox> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout13</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer> + <property name="name"> + <cstring>spacer12_3_2_2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>200</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QLabel"> + <property name="name"> + <cstring>PoweredIdleLabel</cstring> + </property> + <property name="text"> + <string>When the system is idle for more than</string> + </property> + </widget> + <widget class="QSpinBox"> + <property name="name"> + <cstring>PoweredIdleTime</cstring> + </property> + <property name="prefix"> + <string></string> + </property> + <property name="suffix"> + <string> min</string> + </property> + <property name="whatsThis" stdset="0"> + <string>To prevent data loss or other damage, you can have the system suspend or hibernate, so you don't run accidentally out of battery power. Configure the number of minutes below which the machine will run the configured action.</string> + </property> + </widget> + <widget class="QComboBox"> + <property name="name"> + <cstring>PoweredIdleCombo</cstring> + </property> + </widget> + </hbox> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout13_2_2</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer> + <property name="name"> + <cstring>spacer12_3_2_2_3_2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>200</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QLabel"> + <property name="name"> + <cstring>PoweredFreqLabel</cstring> + </property> + <property name="text"> + <string>CPU frequency scaling policy</string> + </property> + </widget> + <widget class="QComboBox"> + <property name="name"> + <cstring>PoweredFreqCombo</cstring> + </property> + </widget> + </hbox> + </widget> + </vbox> + </widget> + <widget class="QGroupBox"> + <property name="name"> + <cstring>BatteryBox</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="title"> + <string>Battery Powered</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout16</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>BatteryBrightnessLabel</cstring> + </property> + <property name="text"> + <string>Brightness</string> + </property> + </widget> + <widget class="QSlider"> + <property name="name"> + <cstring>BatteryBrightnessSlider</cstring> + </property> + <property name="mouseTracking"> + <bool>true</bool> + </property> + <property name="maxValue"> + <number>7</number> + </property> + <property name="pageStep"> + <number>1</number> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="tickmarks"> + <enum>Both</enum> + </property> + <property name="whatsThis" stdset="0"> + <string>This slider controls the brightness when the system runs on batteries</string> + </property> + </widget> + </hbox> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout14</cstring> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QComboBox" row="1" column="4"> + <property name="name"> + <cstring>BatteryIdleCombo</cstring> + </property> + </widget> + <widget class="QLabel" row="1" column="2"> + <property name="name"> + <cstring>BatteryIdleLabel</cstring> + </property> + <property name="text"> + <string>When the system is idle for more than</string> + </property> + </widget> + <widget class="QComboBox" row="0" column="4"> + <property name="name"> + <cstring>BatteryCriticalCombo</cstring> + </property> + </widget> + <widget class="QLabel" row="0" column="1" rowspan="1" colspan="2"> + <property name="name"> + <cstring>BatteryCriticalLabel</cstring> + </property> + <property name="text"> + <string>When battery remaining time drops below</string> + </property> + </widget> + <widget class="QSpinBox" row="1" column="3"> + <property name="name"> + <cstring>BatteryIdleTime</cstring> + </property> + <property name="prefix"> + <string></string> + </property> + <property name="suffix"> + <string> min</string> + </property> + <property name="whatsThis" stdset="0"> + <string>To prevent data loss or other damage, you can have the system suspend or hibernate, so you don't run accidentally out of battery power. Configure the number of minutes below which the machine will run the configured action.</string> + </property> + </widget> + <widget class="QSpinBox" row="0" column="3"> + <property name="name"> + <cstring>CriticalRemainTime</cstring> + </property> + <property name="prefix"> + <string></string> + </property> + <property name="suffix"> + <string> min</string> + </property> + <property name="whatsThis" stdset="0"> + <string>To prevent data loss or other damage, you can have the system suspend or hibernate, so you don't run accidentally out of battery power. Configure the number of minutes below which the machine will run the configured action.</string> + </property> + </widget> + <spacer row="0" column="0"> + <property name="name"> + <cstring>spacer12_3</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>28</width> + <height>20</height> + </size> + </property> + </spacer> + <spacer row="1" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>spacer12_3_2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>50</width> + <height>20</height> + </size> + </property> + </spacer> + </grid> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout13_2</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer> + <property name="name"> + <cstring>spacer12_3_2_2_3</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>200</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QLabel"> + <property name="name"> + <cstring>BatteryFreqLabel</cstring> + </property> + <property name="text"> + <string>CPU frequency scaling policy</string> + </property> + </widget> + <widget class="QComboBox"> + <property name="name"> + <cstring>BatteryFreqCombo</cstring> + </property> + </widget> + </hbox> + </widget> + </vbox> + </widget> + <widget class="QButtonGroup"> + <property name="name"> + <cstring>LaptopLidRadios</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShape"> + <enum>GroupBoxPanel</enum> + </property> + <property name="title"> + <string>When Laptop Lid Closed</string> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="spacing"> + <number>5</number> + </property> + <widget class="QRadioButton"> + <property name="name"> + <cstring>laptopClosedNone</cstring> + </property> + <property name="text"> + <string>Do nothing</string> + </property> + </widget> + <widget class="QRadioButton"> + <property name="name"> + <cstring>laptopClosedBlank</cstring> + </property> + <property name="text"> + <string>Lock screen</string> + </property> + </widget> + <widget class="QRadioButton"> + <property name="name"> + <cstring>laptopClosedSuspend</cstring> + </property> + <property name="text"> + <string>Suspend</string> + </property> + <property name="toolTip" stdset="0"> + <string>Suspend to Memory</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Suspend is a sleep state, the system will consume only very little energy when suspended</string> + </property> + </widget> + <widget class="QRadioButton"> + <property name="name"> + <cstring>laptopClosedHibernate</cstring> + </property> + <property name="text"> + <string>Hibernate</string> + </property> + <property name="toolTip" stdset="0"> + <string>Suspend to Disk</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Hibernate or "Suspend to Disk" is a deep sleepstate, allowing the system to power off completely</string> + </property> + </widget> + <widget class="QRadioButton"> + <property name="name"> + <cstring>laptopClosedShutdown</cstring> + </property> + <property name="text"> + <string>Shutdown</string> + </property> + <property name="toolTip" stdset="0"> + <string>Halt the machine</string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer12_2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>213</width> + <height>20</height> + </size> + </property> + </spacer> + </hbox> + </widget> + <spacer> + <property name="name"> + <cstring>spacer11</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>31</width> + <height>80</height> + </size> + </property> + </spacer> + </vbox> +</widget> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/powermanager/hal-test.py b/powermanager/hal-test.py new file mode 100644 index 0000000..f9ef90c --- /dev/null +++ b/powermanager/hal-test.py @@ -0,0 +1,35 @@ +import dbus + +bus = dbus.SystemBus() +hal_manager_obj = bus.get_object("org.freedesktop.Hal", "/org/freedesktop/Hal/Manager") +hal_manager = dbus.Interface(hal_manager_obj, "org.freedesktop.Hal.Manager") +#device_names = hal_manager.GetAllDevices() + +ac = hal_manager.FindDeviceByCapability("ac_adapter") + +#all_devices = hal_manager.GetAllDevices() + +#for n in device_names: print n +#obj = bus.get_object("org.freedesktop.Hal", u'/org/freedesktop/Hal/devices/acpi_AC') +#obj.GetAllProperties() + +name = ac[0] +device_dbus_obj = bus.get_object("org.freedesktop.Hal" ,ac[0]) +properties = device_dbus_obj.GetAllProperties(dbus_interface="org.freedesktop.Hal.Device") + +try: + parent_name = properties["info.parent"] +except KeyError: + # no parent, must be parent of virtual_root + parent_name = "/" +except TypeError: + print "Error: no properties for device %s"%name + #continue +print properties['ac_adapter.present'] +#for p in properties: +# print p, " :: ", properties[p] +if properties['ac_adapter.present']: + print "plugged in" +else: + print "unplugged" + diff --git a/powermanager/notify.py b/powermanager/notify.py new file mode 100644 index 0000000..869f064 --- /dev/null +++ b/powermanager/notify.py @@ -0,0 +1,68 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'notify.ui' +# +# Created: Thu Apr 10 00:50:39 2008 +# by: The PyQt User Interface Compiler (pyuic) 3.17.4 +# +# WARNING! All changes made in this file will be lost! + + +import sys +from qt import * +from kdecore import KCmdLineArgs, KApplication +from kdecore import i18n +from kdeui import * + + +class NotifyWidget(QWidget): + def __init__(self,parent = None,name = None,fl = 0): + QWidget.__init__(self,parent,name,fl) + + if not name: + self.setName("NotifyWidgetUI") + + self.setSizePolicy(QSizePolicy(QSizePolicy.MinimumExpanding,QSizePolicy.MinimumExpanding,0,0,self.sizePolicy().hasHeightForWidth())) + self.setBaseSize(QSize(0,0)) + + NotifyWidgetUILayout = QGridLayout(self,1,1,11,6,"NotifyWidgetUILayout") + + self.Icon = QLabel(self,"Icon") + self.Icon.setSizePolicy(QSizePolicy(QSizePolicy.Fixed,QSizePolicy.Fixed,0,0,self.Icon.sizePolicy().hasHeightForWidth())) + self.Icon.setScaledContents(1) + + NotifyWidgetUILayout.addMultiCellWidget(self.Icon,0,1,0,0) + + self.Text = QLabel(self,"Text") + + NotifyWidgetUILayout.addWidget(self.Text,1,1) + + self.Caption = QLabel(self,"Caption") + + NotifyWidgetUILayout.addWidget(self.Caption,0,1) + + self.languageChange() + + self.resize(QSize(151,60).expandedTo(self.minimumSizeHint())) + self.clearWState(Qt.WState_Polished) + + + def languageChange(self): + self.setCaption(i18n("Form3")) + self.Text.setText(QString.null) + self.Caption.setText(i18n("<b>Powermanager:</b>")) + + +if __name__ == "__main__": + appname = "" + description = "" + version = "" + + KCmdLineArgs.init (sys.argv, appname, description, version) + a = KApplication () + + QObject.connect(a,SIGNAL("lastWindowClosed()"),a,SLOT("quit()")) + w = NotifyWidget() + a.setMainWidget(w) + w.show() + a.exec_loop() diff --git a/powermanager/notify.ui b/powermanager/notify.ui new file mode 100644 index 0000000..ebf2950 --- /dev/null +++ b/powermanager/notify.ui @@ -0,0 +1,75 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>NotifyWidget</class> +<widget class="QWidget"> + <property name="name"> + <cstring>NotifyWidgetUI</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>151</width> + <height>60</height> + </rect> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>3</hsizetype> + <vsizetype>3</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="baseSize"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + <property name="caption"> + <string>Form3</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel" row="0" column="0" rowspan="2" colspan="1"> + <property name="name"> + <cstring>Icon</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>0</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="pixmap"> + <pixmap></pixmap> + </property> + <property name="scaledContents"> + <bool>true</bool> + </property> + </widget> + <widget class="QLabel" row="1" column="1"> + <property name="name"> + <cstring>Text</cstring> + </property> + <property name="text"> + <string></string> + </property> + </widget> + <widget class="QLabel" row="0" column="1"> + <property name="name"> + <cstring>Caption</cstring> + </property> + <property name="text"> + <string><b>Powermanager:</b></string> + </property> + </widget> + </grid> +</widget> +<pixmapfunction>QPixmap</pixmapfunction> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/powermanager/powermanage.py b/powermanager/powermanage.py new file mode 100644 index 0000000..db62e8c --- /dev/null +++ b/powermanager/powermanage.py @@ -0,0 +1,606 @@ +#!/usr/bin/python +# -*- coding: UTF-8 -*- +########################################################################### +# Copyright (C) 2006 by Sebastian Kügler +# <[email protected]> +# +# Copyright: See COPYING file that comes with this distribution +# +########################################################################### +# An API for changing the powerstate of a notebook + +import dbus +import dbus.glib +import os, time +from dcopext import DCOPClient, DCOPApp # Used for kscreensaver +import xf86misc + +DEBUG = False + +def debug(msg): + """ Print debug message to terminal. """ + if DEBUG: + print msg + +# Default values for actions when battery runs out. +BATTERY_CRITICAL_MINUTES=5 + +# Only do an emergency suspend if charge level percentage is below ... +CHARGE_LEVEL_THRESHOLD = 10 + +isroot = os.environ["USER"] == "root" + +# Send suspend / hibernate commands to HAL or use Sx_COMMANDS +SUSPEND_USE_HAL = True + +# Show the cpu frequency widgets in the tooltip? +SHOW_CPUFREQ = True + + +# Command to initiate suspend-to-disk when not using HAL +S4_COMMAND = "/usr/local/bin/hibernate" +# Command to initiate suspend-to-ram when not using HAL +S3_COMMAND = "/usr/local/bin/s2ram" + +# Override isLaptop method +#IS_LAPTOP = True + +def _readValue(filename, line=0): + """ Reads a single value from the first line of a file. """ + fhandle = open(filename) + value = fhandle.readlines()[line][:-1] + fhandle.close() + return value + +class PowerManage: + """ Class providing low-level power managerment functionality. """ + + def __init__(self): + # (En|Dis)able using hdparm to set disk timeout + self.USE_HDPARM = True + # (En|Dis)able using laptop_mode to make the disk spin up less often + self.USE_LAPTOP_MODE = True + # (En|Dis)able using cpufreq to control cpu frequency scaling + self.USE_CPUFREQ = True + # (En|Dis)able using wireless adapter powermanagement (causes lag in network connection) + self.USE_WI_PM = True + # (En|Dis)able using display powermanagement + self.USE_DPMS = True + # (En|Dis)able using display brightness switching + self.USE_DISPLAY = True + # (En|Dis)able screensaver blankonly + self.SCREENSAVER_BLANKONLY = True + + + try: + xg = xf86misc.XF86Server() + self.xscreen = xg.getDefaultScreen() + except xf86misc.XF86Error: + print "Problem connecting to X server for idletime detection." + # Currently only used in the test method + self.display_dark = 0.5 + self.display_light = 1 + + # Some status initialisations + self.lowBatteryState = False + self.warningBatteryState = False + self.criticalBatteryState = False + + self.criticalBatteryState = False + self.lidClosedState = False + + # What does HAL support on this machine + self.hasBrightness = False + self.hasAC = False + self.hasLid = False + self.hasBattery = False + self.hasCpuFreqGovernors = False + + # Used to track if the previous check reported a battery to determine + # if we want to fire a notice "battery removed|plugged in" + self.wasOnBattery = False + self._initHAL() + self._initBrightness() + self._initBattery() + self._initAc() + self._initLid() + self._checkSuspend() + self._checkCpuCapabilities() + self._findDisks() + + def checkHAL(self): + """ Handle HAL and DBus restarts """ + try: + self.hal_manager.FindDeviceByCapability("") + except dbus.DBusException, e: + if str(e) == 'org.freedesktop.DBus.Error.Disconnected: Connection is closed' \ + or str(e) == 'org.freedesktop.DBus.Error.Disconnected: Connection was disconnected before a reply was received': + # DBus doesn't support on-the-fly restart + print "connection with DBus lost, please restart the display manager" + return + + if os.system("ps aux|grep [h]ald-runner") == 0: + print "connection with HAL lost, trying to reconnect" + self._initHAL() + self._initBrightness() + self._initBattery() + self._initAc() + self._initLid() + self._checkSuspend() + self._checkCpuCapabilities() + else: + print "HAL is not running" + + def isLaptop(self): + """ Detect if system is laptop. """ + try: + return IS_LAPTOP + except NameError: + pass + self.computerObject = self.bus.get_object("org.freedesktop.Hal", + u'/org/freedesktop/Hal/devices/computer') + properties = self.computerObject.GetAllProperties(dbus_interface="org.freedesktop.Hal.Device") + # formfactor sometimes (ppc) also reports "unknown" for laptops + # workaround: consider laptop anything with primary battery (see LP #64053) + return properties["system.formfactor"] == "laptop" or self.hasBattery + + def _findDisks(self): + """ Scan /sys/block for non-removable and non-ramdisks, used for hdparm actions, + currently not implemented in the powermanager frontend. """ + self.disks = [] + blk_path = "/sys/block/" + for d in os.listdir(blk_path): + # No RAM disks, no DM-RAID + if d.startswith("ram") or d.startswith("dm"): + continue + fhandle = open(blk_path+d+"/removable") + if fhandle.readlines()[0][:-1] == "0": + self.disks.append(d) + debug("Detected disks: "+" ".join(self.disks)) + + def onBattery(self): + """ Find out if we're on AC or on battery using HAL. """ + if not self.hasAC: + print "No AC adapter found - assume that we are on batteries." + return False + properties = self.acObject.GetAllProperties(dbus_interface="org.freedesktop.Hal.Device") + if properties.has_key("ac_adapter.present"): + return not properties['ac_adapter.present'] + else: + print "Error: ac_adapter has no property \"present\"" + return False + + def _initBattery(self): + """ Looks for a battery in HAL. """ + batteryDevices = self.hal_manager.FindDeviceByCapability("battery") + self.batteries = {} + self.batteryIsPresent = {} + + numBatt = 0 + for batt in batteryDevices: + battObj = self.bus.get_object("org.freedesktop.Hal", batt) + properties = battObj.GetAllProperties(dbus_interface="org.freedesktop.Hal.Device") + if properties['battery.type'] != "primary": + continue + self.batteries[numBatt] = battObj + self.batteryIsPresent[numBatt] = properties['battery.present'] + numBatt += 1 + + if numBatt > 0: + self.hasBattery = True + else: + self.hasBattery = False + print "No battery found." + + def getBatteryState(self,batt): + """ Read battery status from HAL and return + (battery state, charge percentage, remaining seconds). + """ + try: + properties = self.batteries[batt].GetAllProperties(dbus_interface="org.freedesktop.Hal.Device") + except dbus.DBusException: + print "problem getting battery state from dbus." + return "not present", 0, 0, 0, 0, 0 + + if not properties['battery.present']: + return "not present", 0, 0, 0, 0, 0 + else: + current = full = level = remain = rate = 0 + if properties.has_key("battery.charge_level.current"): + current = properties["battery.charge_level.current"] + if properties.has_key("battery.charge_level.last_full"): + full = properties["battery.charge_level.last_full"] + + if properties["battery.rechargeable.is_charging"]: + state = "charging" + elif properties["battery.rechargeable.is_discharging"]: + if self.onBattery(): + state = "discharging" + else: + state = "charged" + elif not properties["battery.rechargeable.is_discharging"] \ + and not properties["battery.rechargeable.is_charging"]: + if current == 0: + state = "empty" + else: + state = "charged" + else: + print "Unknown battery state ..." + + # Sometimes, HAL doesn't report the percentage, but we can compute that ourselves anyway + if properties.has_key("battery.charge_level.percentage"): + level = properties["battery.charge_level.percentage"] + elif current > 0 and full > 0: + level = current / full + + if state in ("charging","discharging"): + if properties.has_key("battery.remaining_time"): + remain = properties["battery.remaining_time"] + if properties.has_key("battery.charge_level.rate"): + rate = properties["battery.charge_level.rate"] + + return state, level, remain, rate, current, full + + def showInfo(self): + """ Outputs some random information to show that it does not work yet. """ + print "OnBattery:", self.onBattery() + print "CPUs:", len(self.cpus) + + def _initHAL(self): + """ Initialise HAL client to be used later. """ + self.bus = dbus.SystemBus() + hal_manager_obj = self.bus.get_object("org.freedesktop.Hal", "/org/freedesktop/Hal/Manager") + self.hal_manager = dbus.Interface(hal_manager_obj, "org.freedesktop.Hal.Manager") + + def _initLid(self): + """ Find out if there's a Lid device. """ + lidDevice = self.hal_manager.FindDeviceStringMatch("button.type", "lid") + if len(lidDevice) >= 1: + self.hasLid = True + self.lidObject = self.bus.get_object("org.freedesktop.Hal" ,lidDevice[0]) + + def _initAc(self): + """ Search HAL for detecting if power is plugged in. """ + acDevice = self.hal_manager.FindDeviceByCapability("ac_adapter") + if len(acDevice) >= 1: + self.hasAC = True + self.acObject = self.bus.get_object("org.freedesktop.Hal" ,acDevice[0]) + + def _checkSuspend(self): + """ Ask HAL whether we can suspend / hibernate. """ + if SUSPEND_USE_HAL: + self.computerObject = self.bus.get_object("org.freedesktop.Hal", + u'/org/freedesktop/Hal/devices/computer') + properties = self.computerObject.GetAllProperties( + dbus_interface="org.freedesktop.Hal.Device") + self.canSuspend = properties["power_management.can_suspend"] + self.canHibernate = properties["power_management.can_hibernate"] + else: + self.canSuspend = self.canHibernate = True + + def _initBrightness(self): + """ Search HAL for a screen with brightness controls.""" + + brightnessDevice = self.hal_manager.FindDeviceByCapability("laptop_panel") + + if len(brightnessDevice) >= 1: + self.hasBrightness = True + self.brightnessObject = self.bus.get_object("org.freedesktop.Hal", brightnessDevice[0]) + self.brightness_properties = self.brightnessObject.GetAllProperties( + dbus_interface="org.freedesktop.Hal.Device") + try: + self.brightness_levels = self.brightness_properties[u'laptop_panel.num_levels'] + except KeyError,e: + self.hasBrightness = False + return 0 # Really don't know what to do here, but don't crash in any case. + try: + self.old_b = self.brightness_levels[-1] # Setting cached brightness value to brightest + except TypeError,e: + return 0 # Really don't know what to do here, but don't crash in any case. + + def getBrightness(self): + """ Read brightness from HAL. """ + if not self.hasBrightness: + debug("Brightness setting not supported.") + return + try: + b = self.brightnessObject.GetBrightness( + dbus_interface="org.freedesktop.Hal.Device.LaptopPanel") + except dbus.DBusException, e: + # Sometimes, right after resume, the HAL call + # fails, in that case, we return the last value + # and hope that it goes well next time. + print "Warning: in getBrightness(): ", e + # try and return the old brightness setting, but don't die in any case: + try: + return self.old_b + except AttributeError, errmsg: + return + self.old_b = b + return b + + def adjustBrightness(self, level): + """ Adjust the brightness via HAL. """ + if not self.hasBrightness: + debug("Brightness setting not supported.") + return + try: + self.brightnessObject.SetBrightness(level, + dbus_interface="org.freedesktop.Hal.Device.LaptopPanel") + except dbus.DBusException, e: + print e + + def _checkCpuCapabilities(self): + """ Find out the number of CPUs / cores, check which governors are avaible.""" + cpufreq_dir = "/sys/devices/system/cpu" + self.cpus = [] + for cpu in os.listdir(cpufreq_dir): + if cpu.startswith('cpu') and cpu != 'cpuidle': + self.cpus.append(cpu) + self.cpus.sort() + + # Map our policies to cpufreq governors. + self.cpu_policy = {} + self.cpu_policy['dynamic/ac'] = [] + self.cpu_policy['dynamic/battery'] = [] + self.cpu_policy['powersave'] = [] + self.cpu_policy['performance'] = [] + + try: + comp_obj = self.bus.get_object('org.freedesktop.Hal', '/org/freedesktop/Hal/devices/computer') + self.cpufreq = dbus.Interface(comp_obj, 'org.freedesktop.Hal.Device.CPUFreq') + self.governor_available = self.cpufreq.GetCPUFreqAvailableGovernors() + except dbus.DBusException: + return + self.hasCpuFreqGovernors = True + + if 'ondemand' in self.governor_available: + self.cpu_policy['dynamic/ac'].append('ondemand') + self.cpu_policy['dynamic/battery'].append('ondemand') + if 'conservative' in self.governor_available: + self.cpu_policy['dynamic/ac'].append('conservative') + self.cpu_policy['dynamic/battery'].insert(0,'conservative') + if 'userspace' in self.governor_available: + self.cpu_policy['dynamic/ac'].append('userspace') + self.cpu_policy['dynamic/battery'].append('userspace') + if 'powersave' in self.governor_available: + self.cpu_policy['powersave'].append('powersave') + if 'performance' in self.governor_available: + self.cpu_policy['performance'].append('performance') + + def getSupportedCpuPolicies(self): + """ Report a list of supported CPU policies """ + policies = [] + if len(self.cpu_policy['dynamic/ac']) > 0: + policies.append('dynamic') + if len(self.cpu_policy['powersave']) > 0: + policies.append('powersave') + if len(self.cpu_policy['performance']) > 0: + policies.append('performance') + return policies + + def getCpuPolicy(self): + """ Translate current CPU frequency governor into policy """ + if not self.USE_CPUFREQ or not self.hasCpuFreqGovernors: + return "" + gov = self.cpufreq.GetCPUFreqGovernor() + for policy in self.cpu_policy.keys(): + if gov in self.cpu_policy[policy]: + return policy.split('/')[0] # strip ac or battery off + return gov ## return as-is - no conversion + + def setCpuPolicy(self,policy): + """ Using cpufreq governors. Mode is powersave, dynamic or performance. We're assuming that + the available governors are the same for all CPUs. This method changes the cpufreq + governor on all CPUs to a certain policy.""" + if not self.USE_CPUFREQ or not self.hasCpuFreqGovernors: + return False + + if policy == "dynamic": + if self.onBattery(): + policy = "dynamic/battery" + else: + policy = "dynamic/ac" + + for gov in self.cpu_policy[policy]: + try: + self.cpufreq.SetCPUFreqGovernor(gov) + return True + except dbus.DBusException: + pass + return False # no of governor worked + + def cpuIsOnline(self,cpu): + """ Check if cpu is online. CPU0 is always online, CPU1 might be unplugged. Since + /sys/devices/system/cpu/$cpu/cpufreq is not readable for normal users, we just + check for the cpufreq subdir (which is where it's really needed anyway). + """ + if cpu == "cpu0": return True + else: return os.path.isdir("/sys/devices/system/cpu/"+cpu+"/cpufreq") + + def getCpuState(self,cpu): + """ Reads the status of a CPU from /sys. """ + state = {} + state['online'] = self.cpuIsOnline(cpu) + if not state['online']: + debug("getCpuState: "+cpu+" is offline") + return state + try: + state['cpu'] = cpu + state['cur'] = int(_readValue("/sys/devices/system/cpu/"+cpu+"/cpufreq/scaling_cur_freq"))/1000 + state['governor'] = _readValue("/sys/devices/system/cpu/"+cpu+"/cpufreq/scaling_governor") + state['driver'] = _readValue("/sys/devices/system/cpu/"+cpu+"/cpufreq/scaling_driver") + state['steps'] = [] + freqs = _readValue("/sys/devices/system/cpu/"+cpu+"/cpufreq/scaling_available_frequencies") + except IOError: + # CPUFREQ has gone away, let's disable it. + state['online'] = False + return state + for v in freqs.split(): + state['steps'].append(int(v)/1000) + state['max'] = max(state['steps']) + state['min'] = min(state['steps']) + debug(state) + return state + + def getLidClosedState(self): + """ Returns True if the lid is currently closed, or False if it isn't. """ + try: + properties = self.lidObject.GetAllProperties(dbus_interface="org.freedesktop.Hal.Device") + return properties["button.state.value"] + except (KeyError, dbus.DBusException): + return False + + def setPowerSave(self, state): + # No SetPowerSave in Ubuntu's HAL + try: + self.computerObject.SetPowerSave(state, + dbus_interface="org.freedesktop.Hal.Device.SystemPowerManagement") + except dbus.DBusException, e: + print "Warning: While setting SystemPowerManagement to ", state, ": ", + print e + + def blankScreen(self): + """ Call dpms to switch off the screen immediately. """ + os.system('xset dpms force standby') + + def setScreensaverBlankOnly(self,blankonly): + """ Switches a screensaver to blankonly, so cpu hungry screensavers will not drain the poor + battery.""" + # create a new DCOP-Client: + client = DCOPClient() + # connect the client to the local DCOP-server: + client.attach() + # create a DCOP-Application-Object to talk to amarok: + kdesktop = DCOPApp('kdesktop', client) + # call a DCOP-function: + ok, foo = kdesktop.KScreensaverIface.setBlankOnly(blankonly) + if not ok: + debug("Failed to set kdesktop screensaver to blankonly.") + return False + return True + + def getIdleSeconds(self): + """ Get idle seconds from X server. """ + return self.xscreen.getIdleSeconds() + + def resetIdleSeconds(self): + """ Reset idle seconds. """ + return self.xscreen.resetIdleSeconds() + + def test(self): + """ Try all kinds of stuff and see what breaks.""" + print "Trying to adjust brightness ..." + bright = self.getBrightness() + self.adjustBrightness(2) + time.sleep(1) + self.adjustBrightness(bright) + print " ... OK." + + if self.USE_CPUFREQ: + print "Reading speeds from cpufreq..." + for cpu in self.cpus: + print self.getCpuState(cpu) + print "Report supported cpufreq policies..." + for policy in self.cpu_policy.keys(): + print "Policy:", policy, "=", self.cpu_policy[policy] + + print "Trying all cpufreq policies ..." + orig_pol = self.getCpuPolicy() + for pol in self.cpu_policy.keys(): + print ". ", pol + self.setCpuPolicy(pol) + self.setCpuPolicy(orig_pol) + print "... OK." + else: + print "Skipping CPUFREQ: USE_CPUFREQ = False" + + if self.SCREENSAVER_BLANKONLY: + if self.setScreensaverBlankOnly(True): + debug("Manipulating screensaver seems to work well.") + else: + debug("Manipulating screensaver seems broken.") + + if isroot: + print "Trying to use Disk powermanagement and laptop_mode" + self.setDiskPM(True) + time.sleep(1) + self.setDiskPM(False) + print "...OK" + else: + print "Skipping DiskPM, not root." + + if self.hasLid: + if self.getLidClosedState(): + print "Lid is closed." + else: + print "Lid is currently open." + + def setDiskPM(self,on=True): + """ Switches on laptop_mode and sets disks to advanced powermanagement.""" + if self.USE_LAPTOP_MODE: + # Check if laptop_mode exists: + laptop_mode = "/proc/sys/vm/laptop_mode" + if not os.path.isfile(laptop_mode): + self.USE_LAPTOP_MODE = False + debug("Laptop mode not supported, no "+laptop_mode) + else: + fhandle = open(laptop_mode,"w") + if on: val = 1 + else: val = 0 + fhandle.write(str(val)) + fhandle.close() + + if self.USE_HDPARM: + # Set disks to advanced PM + for disk in self.disks: + if on: + # Switch on advanced powermanagement + cmd = "hdparm -B1 /dev/"+disk+" > /dev/null" + else: + # Switch off advanced powermanagement + cmd = "hdparm -B255 /dev/"+disk+" > /dev/null" + if os.system(cmd) != 0: + self.USE_HDPARM = False + print "Switching advanced powermanagement failed, not using hdparm anymore" + + def suspend(self): + """ Run a suspend command, either via HAL or script. """ + if SUSPEND_USE_HAL: + try: + self.computerObject.Suspend(0, dbus_interface="org.freedesktop.Hal.Device.SystemPowerManagement") + except dbus.DBusException: + pass #we get a DBusException: No reply within specified time + else: + self._sleepMode(S3_COMMAND) + + def hibernate(self): + """ Implements suspend to disk (S4). """ + if SUSPEND_USE_HAL: + try: + self.computerObject.Hibernate(dbus_interface="org.freedesktop.Hal.Device.SystemPowerManagement") + except dbus.DBusException: + pass #we get a DBusException: No reply within specified time + else: + self._sleepMode(S4_COMMAND) + + def _sleepMode(self, command): + """ Send the system into S3 or S4 not using HAL. """ + debug("Initiating a sleep cycle") + if os.system(command) != 0: + print "sleepmode failed. ("+command+")" + return False + debug("Everything is dandy") + return True + + def shutdown(self): + """ Shutdown the system via HAL. """ + self.computerObject.Shutdown(dbus_interface="org.freedesktop.Hal.Device.SystemPowerManagement") + + +if __name__ == "__main__": + """ Run some tests, used for debugging.""" + pman = PowerManage() + pman.showInfo() + pman.test() + diff --git a/powermanager/powermanager_ui.ui b/powermanager/powermanager_ui.ui new file mode 100644 index 0000000..1fc9cfb --- /dev/null +++ b/powermanager/powermanager_ui.ui @@ -0,0 +1,924 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>Powermanager</class> +<widget class="QDialog"> + <property name="name"> + <cstring>Powermanager</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>568</width> + <height>600</height> + </rect> + </property> + <property name="caption"> + <string>Powermanager</string> + </property> + <property name="sizeGripEnabled"> + <bool>true</bool> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>11</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="QTabWidget"> + <property name="name"> + <cstring>tabWidget</cstring> + </property> + <widget class="QWidget"> + <property name="name"> + <cstring>Widget8</cstring> + </property> + <attribute name="title"> + <string>Power Schemes</string> + </attribute> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QGroupBox"> + <property name="name"> + <cstring>PerformanceGroup</cstring> + </property> + <property name="title"> + <string>Performance</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout4</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>Brightness</string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer3</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>551</width> + <height>21</height> + </size> + </property> + </spacer> + </hbox> + </widget> + <widget class="QSlider"> + <property name="name"> + <cstring>PerrformanceBrightnessSlider</cstring> + </property> + <property name="maxValue"> + <number>10</number> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="tickmarks"> + <enum>Both</enum> + </property> + <property name="whatsThis" stdset="0"> + <string>Control the brightness setting in the active scheme</string> + </property> + </widget> + <widget class="Line"> + <property name="name"> + <cstring>line1</cstring> + </property> + <property name="frameShape"> + <enum>HLine</enum> + </property> + <property name="frameShadow"> + <enum>Sunken</enum> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout6</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel2</cstring> + </property> + <property name="text"> + <string>When system is inactive for</string> + </property> + </widget> + <widget class="QSpinBox"> + <property name="name"> + <cstring>PerformanceMinutesSpin</cstring> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel3</cstring> + </property> + <property name="text"> + <string>minutes ...</string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer4</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>311</width> + <height>21</height> + </size> + </property> + </spacer> + </hbox> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout3</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QRadioButton"> + <property name="name"> + <cstring>PerformanceNothing</cstring> + </property> + <property name="text"> + <string>Do nothing</string> + </property> + </widget> + <widget class="QRadioButton"> + <property name="name"> + <cstring>PerformanceFade</cstring> + </property> + <property name="text"> + <string>Fade display</string> + </property> + </widget> + <widget class="QRadioButton"> + <property name="name"> + <cstring>PerformanceSleepmode</cstring> + </property> + <property name="text"> + <string>Initiate sleepmode</string> + </property> + </widget> + <widget class="QComboBox"> + <item> + <property name="text"> + <string>Hibernate (S4)</string> + </property> + </item> + <item> + <property name="text"> + <string>Standby (S3)</string> + </property> + </item> + <property name="name"> + <cstring>PerformanceSleepmodeCombo</cstring> + </property> + </widget> + </hbox> + </widget> + </vbox> + </widget> + <widget class="QGroupBox"> + <property name="name"> + <cstring>AutomaticGroup</cstring> + </property> + <property name="title"> + <string>Automatic</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout4_3</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel1_3</cstring> + </property> + <property name="text"> + <string>Brightness</string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer3_3</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>551</width> + <height>21</height> + </size> + </property> + </spacer> + </hbox> + </widget> + <widget class="QSlider"> + <property name="name"> + <cstring>AutomaticBrightnessSlider</cstring> + </property> + <property name="maxValue"> + <number>10</number> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="tickmarks"> + <enum>Both</enum> + </property> + <property name="whatsThis" stdset="0"> + <string>Control the brightness setting in the active scheme</string> + </property> + </widget> + <widget class="Line"> + <property name="name"> + <cstring>line1_3</cstring> + </property> + <property name="frameShape"> + <enum>HLine</enum> + </property> + <property name="frameShadow"> + <enum>Sunken</enum> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout6_3</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel2_3</cstring> + </property> + <property name="text"> + <string>When system is inactive for</string> + </property> + </widget> + <widget class="QSpinBox"> + <property name="name"> + <cstring>AutomaticMinutesSpin</cstring> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel3_3</cstring> + </property> + <property name="text"> + <string>minutes ...</string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer4_3</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>311</width> + <height>21</height> + </size> + </property> + </spacer> + </hbox> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout3_3</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QRadioButton"> + <property name="name"> + <cstring>AutomaticNothing</cstring> + </property> + <property name="text"> + <string>Do nothing</string> + </property> + </widget> + <widget class="QRadioButton"> + <property name="name"> + <cstring>AutomaticFade</cstring> + </property> + <property name="text"> + <string>Fade display</string> + </property> + </widget> + <widget class="QRadioButton"> + <property name="name"> + <cstring>AutomaticSleepmode</cstring> + </property> + <property name="text"> + <string>Initiate sleepmode</string> + </property> + </widget> + <widget class="QComboBox"> + <item> + <property name="text"> + <string>Hibernate (S4)</string> + </property> + </item> + <item> + <property name="text"> + <string>Standby (S3)</string> + </property> + </item> + <property name="name"> + <cstring>AutomaticSleepmodeCombo</cstring> + </property> + </widget> + </hbox> + </widget> + </vbox> + </widget> + <widget class="QGroupBox"> + <property name="name"> + <cstring>PowersaveGroup</cstring> + </property> + <property name="title"> + <string>Powersave</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout4_2</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel1_2</cstring> + </property> + <property name="text"> + <string>Brightness</string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer3_2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>551</width> + <height>21</height> + </size> + </property> + </spacer> + </hbox> + </widget> + <widget class="QSlider"> + <property name="name"> + <cstring>PowersaveBrightnessSlider</cstring> + </property> + <property name="maxValue"> + <number>10</number> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="tickmarks"> + <enum>Both</enum> + </property> + <property name="whatsThis" stdset="0"> + <string>Control the brightness setting in the active scheme</string> + </property> + </widget> + <widget class="Line"> + <property name="name"> + <cstring>line1_2</cstring> + </property> + <property name="frameShape"> + <enum>HLine</enum> + </property> + <property name="frameShadow"> + <enum>Sunken</enum> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout6_2</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel2_2</cstring> + </property> + <property name="text"> + <string>When system is inactive for</string> + </property> + </widget> + <widget class="QSpinBox"> + <property name="name"> + <cstring>PowersaveMinutesSpin</cstring> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel3_2</cstring> + </property> + <property name="text"> + <string>minutes ...</string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer4_2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>311</width> + <height>21</height> + </size> + </property> + </spacer> + </hbox> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout3_2</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QRadioButton"> + <property name="name"> + <cstring>PowersaveNothing</cstring> + </property> + <property name="text"> + <string>Do nothing</string> + </property> + </widget> + <widget class="QRadioButton"> + <property name="name"> + <cstring>PowersaveFade</cstring> + </property> + <property name="text"> + <string>Fade display</string> + </property> + </widget> + <widget class="QRadioButton"> + <property name="name"> + <cstring>PowersaveSleepmode</cstring> + </property> + <property name="text"> + <string>Initiate sleepmode</string> + </property> + </widget> + <widget class="QComboBox"> + <item> + <property name="text"> + <string>Hibernate (S4)</string> + </property> + </item> + <item> + <property name="text"> + <string>Standby (S3)</string> + </property> + </item> + <property name="name"> + <cstring>PowersaveSleepmodeCombo</cstring> + </property> + </widget> + </hbox> + </widget> + </vbox> + </widget> + </vbox> + </widget> + <widget class="QWidget"> + <property name="name"> + <cstring>Widget9</cstring> + </property> + <attribute name="title"> + <string>Events</string> + </attribute> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer row="1" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>spacer9</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>520</width> + <height>260</height> + </size> + </property> + </spacer> + <spacer row="0" column="1"> + <property name="name"> + <cstring>spacer10</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>110</width> + <height>80</height> + </size> + </property> + </spacer> + <widget class="QLayoutWidget" row="0" column="0"> + <property name="name"> + <cstring>layout17</cstring> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QComboBox" row="1" column="1"> + <item> + <property name="text"> + <string>Do nothing</string> + </property> + </item> + <item> + <property name="text"> + <string>Switch to Performance</string> + </property> + </item> + <item> + <property name="text"> + <string>Switch to Automatic</string> + </property> + </item> + <item> + <property name="text"> + <string>Switch to Powersave</string> + </property> + </item> + <item> + <property name="text"> + <string>Suspend (S3)</string> + </property> + </item> + <item> + <property name="text"> + <string>Hibernate (S4)</string> + </property> + </item> + <property name="name"> + <cstring>ACPluggedinCombo</cstring> + </property> + </widget> + <widget class="QLayoutWidget" row="2" column="0"> + <property name="name"> + <cstring>layout16</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel7</cstring> + </property> + <property name="text"> + <string>When battery power is below</string> + </property> + </widget> + <widget class="QSpinBox"> + <property name="name"> + <cstring>BatteryLowPercentage</cstring> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel8</cstring> + </property> + <property name="text"> + <string>%</string> + </property> + </widget> + </hbox> + </widget> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>textLabel4</cstring> + </property> + <property name="text"> + <string>When AC adapter is removed</string> + </property> + </widget> + <widget class="QComboBox" row="2" column="1"> + <item> + <property name="text"> + <string>Do nothing</string> + </property> + </item> + <item> + <property name="text"> + <string>Switch to Performance</string> + </property> + </item> + <item> + <property name="text"> + <string>Switch to Automatic</string> + </property> + </item> + <item> + <property name="text"> + <string>Switch to Powersave</string> + </property> + </item> + <item> + <property name="text"> + <string>Suspend (S3)</string> + </property> + </item> + <item> + <property name="text"> + <string>Hibernate (S4)</string> + </property> + </item> + <property name="name"> + <cstring>BatteryLowCombo</cstring> + </property> + </widget> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>textLabel6</cstring> + </property> + <property name="text"> + <string>When AC adapter is plugged in</string> + </property> + </widget> + <widget class="QComboBox" row="3" column="1"> + <item> + <property name="text"> + <string>Do nothing</string> + </property> + </item> + <item> + <property name="text"> + <string>Switch to Performance</string> + </property> + </item> + <item> + <property name="text"> + <string>Switch to Automatic</string> + </property> + </item> + <item> + <property name="text"> + <string>Switch to Powersave</string> + </property> + </item> + <item> + <property name="text"> + <string>Suspend (S3)</string> + </property> + </item> + <item> + <property name="text"> + <string>Hibernate (S4)</string> + </property> + </item> + <property name="name"> + <cstring>LidCloseCombo</cstring> + </property> + </widget> + <widget class="QLabel" row="3" column="0"> + <property name="name"> + <cstring>textLabel5</cstring> + </property> + <property name="text"> + <string>When the lid is closed</string> + </property> + </widget> + <widget class="QComboBox" row="0" column="1"> + <item> + <property name="text"> + <string>Do nothing</string> + </property> + </item> + <item> + <property name="text"> + <string>Switch to Performance</string> + </property> + </item> + <item> + <property name="text"> + <string>Switch to Automatic</string> + </property> + </item> + <item> + <property name="text"> + <string>Switch to Powersave</string> + </property> + </item> + <item> + <property name="text"> + <string>Suspend (S3)</string> + </property> + </item> + <item> + <property name="text"> + <string>Hibernate (S4)</string> + </property> + </item> + <property name="name"> + <cstring>ACRemovedCombo</cstring> + </property> + </widget> + </grid> + </widget> + </grid> + </widget> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>Layout1</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="QPushButton"> + <property name="name"> + <cstring>buttonHelp</cstring> + </property> + <property name="text"> + <string>&Help</string> + </property> + <property name="accel"> + <string>F1</string> + </property> + <property name="autoDefault"> + <bool>true</bool> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>Horizontal Spacing2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QPushButton"> + <property name="name"> + <cstring>buttonOk</cstring> + </property> + <property name="text"> + <string>&OK</string> + </property> + <property name="accel"> + <string></string> + </property> + <property name="autoDefault"> + <bool>true</bool> + </property> + <property name="default"> + <bool>true</bool> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>buttonCancel</cstring> + </property> + <property name="text"> + <string>&Cancel</string> + </property> + <property name="accel"> + <string></string> + </property> + <property name="autoDefault"> + <bool>true</bool> + </property> + </widget> + </hbox> + </widget> + </vbox> +</widget> +<connections> + <connection> + <sender>buttonOk</sender> + <signal>clicked()</signal> + <receiver>Powermanager</receiver> + <slot>accept()</slot> + </connection> + <connection> + <sender>buttonCancel</sender> + <signal>clicked()</signal> + <receiver>Powermanager</receiver> + <slot>reject()</slot> + </connection> +</connections> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/powermanager/recompile-ui-files b/powermanager/recompile-ui-files new file mode 100644 index 0000000..170797c --- /dev/null +++ b/powermanager/recompile-ui-files @@ -0,0 +1,6 @@ +#!/bin/bash +pyuic -tr i18n tooltip.ui -o tooltip.py +pyuic -tr i18n guidance_power_manager_ui.ui -o guidance_power_manager_ui.py +pyuic -tr i18n notify.ui -o notify.py + + diff --git a/powermanager/tooltip.py b/powermanager/tooltip.py new file mode 100644 index 0000000..37b62f3 --- /dev/null +++ b/powermanager/tooltip.py @@ -0,0 +1,57 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'tooltip.ui' +# +# Created: Thu Apr 10 00:50:39 2008 +# by: The PyQt User Interface Compiler (pyuic) 3.17.4 +# +# WARNING! All changes made in this file will be lost! + + +import sys +from qt import * +from kdecore import KCmdLineArgs, KApplication +from kdecore import i18n +from kdeui import * + +from kdeui import * + +class ToolTip(QWidget): + def __init__(self,parent = None,name = None,fl = 0): + QWidget.__init__(self,parent,name,fl) + + if not name: + self.setName("ToolTip") + + self.setSizePolicy(QSizePolicy(QSizePolicy.MinimumExpanding,QSizePolicy.MinimumExpanding,0,0,self.sizePolicy().hasHeightForWidth())) + self.setMinimumSize(QSize(240,0)) + self.setBaseSize(QSize(200,0)) + + ToolTipLayout = QVBoxLayout(self,0,6,"ToolTipLayout") + + self.languageChange() + + self.resize(QSize(300,80).expandedTo(self.minimumSizeHint())) + self.clearWState(Qt.WState_Polished) + + + def languageChange(self): + self.setCaption(i18n("Form1")) + + + def ToolTip_destroyed(self,a0): + print "ToolTip.ToolTip_destroyed(QObject*): Not implemented yet" + +if __name__ == "__main__": + appname = "" + description = "" + version = "" + + KCmdLineArgs.init (sys.argv, appname, description, version) + a = KApplication () + + QObject.connect(a,SIGNAL("lastWindowClosed()"),a,SLOT("quit()")) + w = ToolTip() + a.setMainWidget(w) + w.show() + a.exec_loop() diff --git a/powermanager/tooltip.ui b/powermanager/tooltip.ui new file mode 100644 index 0000000..8d7640d --- /dev/null +++ b/powermanager/tooltip.ui @@ -0,0 +1,53 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>ToolTip</class> +<comment>Python:from kdeui import *</comment> +<widget class="QWidget"> + <property name="name"> + <cstring>ToolTip</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>300</width> + <height>80</height> + </rect> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>3</hsizetype> + <vsizetype>3</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>240</width> + <height>0</height> + </size> + </property> + <property name="baseSize"> + <size> + <width>200</width> + <height>0</height> + </size> + </property> + <property name="caption"> + <string>Form1</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + </vbox> +</widget> +<slots> + <slot>ToolTip_destroyed( QObject * )</slot> +</slots> +<pixmapfunction>QPixmap</pixmapfunction> +<layoutdefaults spacing="6" margin="11"/> +</UI> |