Release prep...
[rox-lithium.git] / battery.py
blobb8a1cc6470ab8da67e9b370d6e1ce2f246ac90d2
1 """
2 battery.py - A Battery Status Monitor for ROX
3 (based largely on Baroque by Tilo Riemer)
4 """
6 ############################################################################
7 ##
8 ## $Id: baroque.py,v 1.13 2004/01/08 04:26:11 rds Exp $
9 ##
10 ## Copyright (C) 2002-2003 Rds <rds@rdsarts.com> and
11 ## Tilo Riemer <riemer@lincvs.org>
12 ## All rights reserved.
14 ## Baroque is a merge of BatMonitor and the old Baroque
16 ## Redistribution and use in source and binary forms, with or without
17 ## modification, are permitted provided that the following conditions
18 ## are met:
20 ## 1. Redistributions of source code must retain the above copyright
21 ## notice, this list of conditions and the following disclaimer.
22 ## 2. Redistributions in binary form must reproduce the above copyright
23 ## notice, this list of conditions and the following disclaimer in the
24 ## documentation and/or other materials provided with the distribution.
25 ## 3. The name of the author may not be used to endorse or promote products
26 ## derived from this software without specific prior written permission.
28 ## THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
29 ## IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
30 ## OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
31 ## IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
32 ## INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
33 ## NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
34 ## DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
35 ## THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36 ## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
37 ## THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 ###############################################################################
41 # standard library modules
42 import sys, os, time, gtk, gobject, rox
43 from rox import applet, filer, tasks
44 from rox.options import Option
46 # globals
47 APP_NAME = 'Lithium'
48 APP_DIR = rox.app_dir
49 APP_SIZE = [28, 28]
51 # Options.xml processing
52 from rox import Menu
53 rox.setup_app_options(APP_NAME, site='hayber.us')
54 Menu.set_save_name(APP_NAME, site='hayber.us')
56 #Options go here
57 WARN = Option('warn', True)
58 WARN_LEVEL = Option('warn_level', 10)
59 TIMER = Option('timeout', "1000")
60 THEME = Option('theme', 'Color')
62 #Enable notification of options changes
63 rox.app_options.notify()
65 BATT_TYPE = -1 # 0 = ACPI, 1 = APM
67 # notification
68 try:
69 HAVE_NOTIFY = False
70 import pynotify
71 if pynotify.init(APP_NAME):
72 HAVE_NOTIFY = True
73 except:
74 pass
78 # Initalize the battery object
79 try:
80 import acpi
81 BATTERY = acpi.Acpi()
82 BATT_TYPE = 0
83 OFFLINE = acpi.OFFLINE
84 except (ImportError, NotImplementedError, EnvironmentError):
85 try:
86 import pmu #for PowerMac support
87 BATTERY = pmu.Pmu()
88 BATT_TYPE = 1
89 OFFLINE = pmu.OFFLINE
90 except (ImportError, NotImplementedError, EnvironmentError):
91 try:
92 import apm
93 BATTERY = apm.Apm()
94 BATT_TYPE = 1
95 OFFLINE = apm.OFFLINE
96 except (ImportError, NotImplementedError, EnvironmentError):
97 rox.croak(_("Sorry, but we could not load a Power Management module. Your system is not configured with power management support."))
100 class Battery(applet.Applet):
101 """A Battery Status Monitor Applet"""
103 warned = False
104 msg = 0
105 vertical = False
107 def __init__(self, id):
108 """Initialize applet."""
109 applet.Applet.__init__(self, id)
111 # load the applet icon
112 self.image = gtk.Image()
113 self.load_icons()
114 self.pixbuf = self.images[0]
115 self.image.set_from_pixbuf(self.pixbuf)
116 self.resize_image(8)
117 self.add(self.image)
119 self.vertical = self.get_panel_orientation() in ('Right', 'Left')
120 if self.vertical:
121 self.set_size_request(8, -1)
122 else:
123 self.set_size_request(-1, 8)
125 # set the tooltip
126 self.tooltips = gtk.Tooltips()
128 # menus
129 self.build_appmenu()
131 # event handling
132 self.add_events(gtk.gdk.BUTTON_PRESS_MASK)
133 self.connect('button-press-event', self.button_press)
134 self.connect('size-allocate', self.resize)
135 self.connect('delete_event', self.quit)
136 rox.app_options.add_notify(self.get_options)
138 # user adjustable timer to control how often hardware is polled
139 self.timer = gobject.timeout_add(int(TIMER.int_value) * 100, self.update_display)
141 self.update_display()
142 self.update_tooltip()
143 self.show()
145 def load_icons(self):
146 """load the icons for the selected theme"""
147 theme = THEME.value
148 self.images = []
150 for name in [
151 'battery0',
152 'battery10', 'battery20', 'battery40', 'battery60',
153 'battery80', 'battery100',
154 'charging10', 'charging20', 'charging40', 'charging60',
155 'charging80', 'charging100',
157 self.images.append(gtk.gdk.pixbuf_new_from_file(os.path.join(rox.app_dir, 'themes', theme, name+'.svg')))
159 def notify(self, string):
160 if HAVE_NOTIFY:
161 n = pynotify.Notification(APP_NAME, string, 'battery-caution')
162 n.set_urgency(pynotify.URGENCY_CRITICAL)
163 n.attach_to_widget(self)
164 n.show()
165 else:
166 rox.info(string)
168 def update_display(self):
169 """Updates all the parts of our applet, and cleans it up if needed."""
170 BATTERY.update()
171 percent = BATTERY.percent()
173 if WARN.value == 'True':
174 if (BATTERY.charging_state() == OFFLINE and percent <= WARN_LEVEL.int_value):
175 if self.warned == False:
176 self.notify(_("Warning. Battery is currently at %d%%") % (BATTERY.percent(),))
177 self.warned = True
178 else:
179 self.warned = False
181 if percent == 0:
182 index = 0
183 elif percent < 20:
184 index = 1
185 elif percent < 40:
186 index = 2
187 elif percent < 60:
188 index = 3
189 elif percent < 80:
190 index = 4
191 elif percent < 100:
192 index = 5
193 else:
194 index = 6
196 if BATTERY.charging_state():
197 index += 6
199 pb = self.images[index]
200 self.pixbuf = pb
201 self.resize_image(self.size)
203 self.update_tooltip()
205 return 1 # to keep the timer going!
208 def update_tooltip(self):
209 self.tooltips.set_tip(self, self.status() + self.percent() + '%')
211 def status(self):
212 txt = _("Unknown")
213 BATTERY.update()
214 if BATTERY.charging_state() == 1:
215 txt = _("AC Online: ")
216 elif BATTERY.charging_state() == 2:
217 txt = _("Charging: ")
218 else:
219 # Discharing from the battery
220 if BATT_TYPE == 1:
221 temp2 = BATTERY.time()
222 temp = int(temp2 / 60)
223 temp2 -= (temp * 60)
224 if temp < 0:
225 txt = _("Calculating... ")
226 else:
227 txt = "%s (%d:%02d) " % (_("Battery"), temp, temp2)
228 else:
229 try:
230 temp = BATTERY.estimated_lifetime()
231 temp2 = int(60 * (temp - int(temp)))
232 txt = "%s (%d:%02d) " % (_("Battery"), temp, temp2)
233 except ValueError:
234 txt = _("Charging")
235 return txt
237 def percent(self):
238 return str(BATTERY.percent())
240 def resize(self, widget, rectangle):
241 """Called when the panel sends a size."""
242 if self.vertical:
243 size = rectangle[2] -2
244 else:
245 size = rectangle[3] -2
246 if size != self.size:
247 self.resize_image(size)
249 def resize_image(self, size):
250 """Resize the application image."""
251 scaled_pixbuf = self.pixbuf.scale_simple(size, size, gtk.gdk.INTERP_BILINEAR)
252 self.image.set_from_pixbuf(scaled_pixbuf)
253 self.size = size
255 def button_press(self, window, event):
256 """Handle mouse clicks by popping up the matching menu."""
257 # if event.button == 1:
258 # self.run_it()
259 # if event.button == 2:
260 # self.checkit()
261 if event.button == 3:
262 self.appmenu.popup(self, event, self.position_menu)
264 def get_panel_orientation(self):
265 """ Return panel orientation and margin for displaying a popup menu.
266 Position in ('Top', 'Bottom', 'Left', 'Right').
268 pos = self.socket.property_get('_ROX_PANEL_MENU_POS', 'STRING', False)
269 if pos: pos = pos[2]
270 if pos:
271 side, margin = pos.split(',')
272 margin = int(margin)
273 else:
274 side, margin = None, 2
275 return side
277 def get_options(self, widget=None, rebuild=False, response=False):
278 """Used as the notify callback when options change."""
279 if THEME.has_changed:
280 self.load_icons()
281 self.update_display()
283 if TIMER.has_changed:
284 if self.timer: gobject.source_remove(self.timer)
285 self.timer = gobject.timeout_add(int(TIMER.int_value) * 100, self.update_display)
287 def show_options(self, button=None):
288 """Open the options edit dialog."""
289 rox.edit_options()
291 def get_info(self):
292 """Display an InfoWin self."""
293 from rox import InfoWin
294 InfoWin.infowin(APP_NAME)
296 def build_appmenu(self):
297 """Build the right-click app menu."""
298 items = []
299 items.append(Menu.Action(_('Info...'), 'get_info', '', gtk.STOCK_DIALOG_INFO))
300 items.append(Menu.Action(_('Options...'), 'show_options', '', gtk.STOCK_PREFERENCES))
301 items.append(Menu.Separator())
302 items.append(Menu.Action(_('Close'), 'quit', '', gtk.STOCK_CLOSE))
303 self.appmenu = Menu.Menu('other', items)
304 self.appmenu.attach(self, self)
306 def quit(self, *args):
307 """Quit applet and close everything."""
308 if self.timer: gobject.source_remove(self.timer)
309 self.destroy()