You are not logged in.

#1 2009-03-11 02:36:04

genisis300
Member
From: Uk
Registered: 2008-01-15
Posts: 284

python systray problem

Hi All,
i made a really simple battery monitor when i was using open box.
i've been trying to get ready for it to be released for other people to use however i seem to have a slight problem.

when i was using trayer under openbox it worked fine but now i'm using gnome the tray icon doesn't appear.

the project is hosted here
http://code.google.com/p/batterymon/

there are no error messages from the console and the script seems to be working.

Any ideas
Regards
Matthew


"is adult entertainment killing our children or is killing our children entertaining adults?" Marilyn Manson

Offline

#2 2009-03-12 21:14:27

kumyco
Member
From: somewhere
Registered: 2008-06-23
Posts: 153
Website

Re: python systray problem

looking at the svn version, you need to change

basepath= os.path.join(sys.path[0], sys.argv[0])

to

basepath= os.path.dirname(sys.argv[0])

the former just creates the absolute path for the script

also, i'd put those variables in the class since they're not used anywhere else

Offline

#3 2009-03-12 22:47:16

genisis300
Member
From: Uk
Registered: 2008-01-15
Posts: 284

Re: python systray problem

thanks i'll try that.
regards
Matthew


"is adult entertainment killing our children or is killing our children entertaining adults?" Marilyn Manson

Offline

#4 2009-03-12 22:51:48

genisis300
Member
From: Uk
Registered: 2008-01-15
Posts: 284

Re: python systray problem

ok just tried chaing the base path and still. i pointed it to somewhere else and the program complained of not being able to load the icons which is what i expected. is there something special about the systray under gnome?


"is adult entertainment killing our children or is killing our children entertaining adults?" Marilyn Manson

Offline

#5 2009-03-12 22:55:28

genisis300
Member
From: Uk
Registered: 2008-01-15
Posts: 284

Re: python systray problem

i'll put the code here so it's easier to look at. Should have probably done that to start with roll

#!/usr/bin/env python
#
#       batman.py
#       
#       Copyright 2008 Matthew Horsell <matthew.horsell@googlemail.com>
#       
#       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.
#       
#       This program is distributed in the hope that it will be useful,
#       but WITHOUT ANY WARRANTY; without even the implied warranty of
#       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#       GNU General Public License for more details.
#       
#       You should have received a copy of the GNU General Public License
#       along with this program; if not, write to the Free Software
#       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
#       MA 02110-1301, USA.

import gtk
import gobject
import sys, os

basepath = os.path.dirname(sys.argv[0])
batpath="/sys/class/power_supply/"
interval=30000 

class systray:

    def alert( self, widget, data=None):
        stat            = self.status()
        perc            = self.percent()
        perc1=int(perc)
        dialog = gtk.MessageDialog(
        parent         = None,
        flags          = gtk.DIALOG_DESTROY_WITH_PARENT,
        type           = gtk.MESSAGE_INFO,
        buttons        = gtk.BUTTONS_OK,
        message_format = "Battery Status "+stat +"\n" +"Current Charge " +str(perc1) +"%" +"\n"+"Battery level is low please plug in your mains adaptor")
        dialog.set_title('Batman')
        dialog.connect('response', self.show_hide)
        dialog.show()
        
    def __init__(self):
        self.test= gtk.StatusIcon()
        self.test.set_from_file(basepath+"icons/battery_full.png")
        self.test.set_blinking(False)
        self.test.connect("activate", self.activate)
        self.test.connect("popup_menu", self.popup)
        self.test.set_visible(True)
        gobject.timeout_add(interval,self.update)
        gtk.main()

    def status(self):
        FILE=open(batpath+"BAT0/status","r")
        CMD=FILE.read()
        FILE.close
        return CMD

    def percent(self):
        FILE=open(batpath+"BAT0/charge_full","r")
        MAX=FILE.read()
        FILE.close
        FILE=open(batpath+"BAT0/charge_now","r")
        NOW=FILE.read()
        FILE.close
        
        per=(float(NOW) / float(MAX) * 100)
        return (per)

    def activate( self, widget, data=None):
        stat            = self.status()
        perc            = self.percent()
        perc1=int(perc)
        dialog = gtk.MessageDialog(
        parent         = None,
        flags          = gtk.DIALOG_DESTROY_WITH_PARENT,
        type           = gtk.MESSAGE_INFO,
        buttons        = gtk.BUTTONS_OK,
        message_format = "Battery Status "+stat +"\n" +"Current Charge " +str(perc1) +"%")
        dialog.set_title('Batman')
        dialog.connect('response', self.show_hide)
        dialog.show()
    
    def  show_hide(self, widget,response_id, data= None):
        if response_id == gtk.RESPONSE_YES:
            widget.hide()
        else:
            widget.hide()
           

    # destroyer callback
    def  destroyer(self, widget,response_id, data= None):
        if response_id == gtk.RESPONSE_OK:
            gtk.main_quit()
        else:
            widget.hide()
            
    def popup(self, button, widget, data=None):
        dialog = gtk.MessageDialog(
        parent         = None,
        flags          = gtk.DIALOG_DESTROY_WITH_PARENT,
        type           = gtk.MESSAGE_INFO,
        buttons        = gtk.BUTTONS_OK_CANCEL,
        message_format = "Do you want to close me?")
        dialog.set_title('Batman')
        dialog.connect('response', self.destroyer)
        dialog.show()
    
    def update(self):
        CMD=self.status()
        per=self.percent()
        per1=int(per)
        self.test.set_tooltip("Battery status "+ CMD + "Current charge " + str(per1) + "%")

        if CMD.strip() =="Full":
            self.test.set_from_file(basepath+"icons/battery_full.png")
            gobject.timeout_add(interval,self.update)
            return()

        if CMD.strip()=="Charging":
            self.test.set_from_file(basepath+"icons/battery_power.png")
            gobject.timeout_add(interval,self.update)
            return()

        if CMD.strip()=="Discharging":
                if round(per) <= 100.0:
                    self.test.set_from_file(basepath+"icons/battery_full.png")
                    self.test.set_blinking(False)    

                if round(per) <= 87.0:
                    self.test.set_from_file(basepath+"icons/battery_7.png")
                    
                if round(per) <= 75.0:
                    self.test.set_from_file(basepath+"icons/battery_6.png")
                    
                if round(per) <= 62.0:
                    self.test.set_from_file(basepath+"icons/battery_5.png")
                    
                if round(per) <= 50.0:
                    self.test.set_from_file(basepath+"icons/battery_4.png")
                    
                if round(per) <= 37.0:
                    self.test.set_from_file(basepath+"icons/battery_3.png")
                    
                if round(per) <= 25.0:
                    self.test.set_from_file(basepath+"icons/battery_2.png")
                
                if round(per) <= 12.0:
                    self.test.set_from_file(basepath+"icons/battery_1.png")

                if round(per) <= 8.0:
                    self.test.set_from_file(basepath+"icons/battery_empty!.png")

                if round(per) <= 5.0:
                    self.test.set_from_file(basepath+"icons/battery_empty.png")
                    self.test.set_blinking(True)
                    self.alert(self)
                gobject.timeout_add(interval,self.update)
    
    
if __name__ == "__main__":
    tray=systray()

"is adult entertainment killing our children or is killing our children entertaining adults?" Marilyn Manson

Offline

#6 2009-03-12 23:28:07

ibrahim
Member
Registered: 2006-02-18
Posts: 53

Re: python systray problem

I didn't really check it out in depth but the following gets the icon to display

28: basepath = os.path.abspath(os.path.dirname(__file__))
51: self.test.set_from_file(os.path.join(basepath,"icons/battery_full.png"))

Not related to the systray issue but I don't have /sys/class/power_supply/BAT0 but /sys/class/power_supply/BAT1. You should probably look at some way of determing the filename

Offline

#7 2009-03-13 00:05:12

kumyco
Member
From: somewhere
Registered: 2008-06-23
Posts: 153
Website

Re: python systray problem

here is a partly cleaned up version

#!/usr/bin/env python
#
#       batman.py
#       
#       Copyright 2008 Matthew Horsell <matthew.horsell@googlemail.com>
#       
#       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.
#       
#       This program is distributed in the hope that it will be useful,
#       but WITHOUT ANY WARRANTY; without even the implied warranty of
#       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#       GNU General Public License for more details.
#       
#       You should have received a copy of the GNU General Public License
#       along with this program; if not, write to the Free Software
#       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
#       MA 02110-1301, USA.

import gtk
import gobject
import sys, os
VERSION="0.4.0"

#basepath="/home/matthew/Projects/batman/"

basepath = os.path.abspath(os.path.dirname(__file__))

batpath="/sys/class/power_supply/"
interval=30000
#batpath="/home/matthew/Projects/systray/"
class systray:

    def alert( self, widget, data=None):
        stat            = self.status()
        perc            = self.percent()
        dialog = gtk.MessageDialog(
        parent         = None,
        flags          = gtk.DIALOG_DESTROY_WITH_PARENT,
        type           = gtk.MESSAGE_INFO,
        buttons        = gtk.BUTTONS_OK,
        message_format = "Battery Status %s\nCurrent Charge %d\
          %%\nBattery level is low please plug in your mains adaptor"   \
          % (stat, perc)
        )
        dialog.set_title('Batterymon')
        dialog.connect('response', self.show_hide)
        dialog.show()
    
    def set_icon(self, name):
        print "%s/icons/battery_%s.png" % (basepath, name)
        self.test.set_from_file("%s/icons/battery_%s.png" % (basepath, name))
    
    def __init__(self):
        self.test= gtk.StatusIcon()
        self.set_icon("full")
        self.test.set_blinking(False)
        self.test.connect("activate", self.activate)
        self.test.connect("popup_menu", self.popup)
        self.test.set_visible(True)
        gobject.timeout_add(interval, self.update)
        gtk.main()

    def status(self):
        FILE=open(batpath+"BAT0/status","r")
        CMD=FILE.read()
        FILE.close
        return CMD

    def percent(self):
        
        FILE=open(batpath+"BAT0/charge_full","r")
        MAX=FILE.read()
        FILE.close
        FILE=open(batpath+"BAT0/charge_now","r")
        NOW=FILE.read()
        FILE.close
        
        # only the int value is ever used
        per = int(rount(float(NOW) / float(MAX) * 100))
        return (per)

    def activate( self, widget, data=None):
        stat            = self.status()
        perc            = self.percent()
        perc1=perc
        dialog = gtk.MessageDialog(
        parent         = None,
        flags          = gtk.DIALOG_DESTROY_WITH_PARENT,
        type           = gtk.MESSAGE_INFO,
        buttons        = gtk.BUTTONS_OK,
        message_format = "Battery Status %s\nCurrent Charge %d%%" % (stat, perc))
        dialog.set_title('Batterymon')
        dialog.connect('response', self.show_hide)
        dialog.show()
    
    def  show_hide(self, widget,response_id, data= None):
        if response_id == gtk.RESPONSE_YES:
            widget.hide()
        else:
            widget.hide()


    # destroyer callback
    def  destroyer(self, widget,response_id, data= None):
        if response_id == gtk.RESPONSE_OK:
            gtk.main_quit()
        else:
            widget.hide()
            
    def popup(self, button, widget, data=None):
        dialog = gtk.MessageDialog(
        parent         = None,
        flags          = gtk.DIALOG_DESTROY_WITH_PARENT,
        type           = gtk.MESSAGE_INFO,
        buttons        = gtk.BUTTONS_OK_CANCEL,
        message_format = "Do you want to close me?")
        dialog.set_title('Batterymon')
        dialog.connect('response', self.destroyer)
        dialog.show()
    
    def update(self):
        cmd = self.status().strip()
        per = int(round(self.percent()))
        self.test.set_tooltip("Battery status: %s | Current charge: %d%%" % (cmd, per))
        
        if cmd == "Full":
            self.set_icon("full")
            self.set_icon("power")
        elif cmd == "Discharging":
            if per > 87:
                self.set_icon("full")
                self.test.set_blinking(False)
            elif per > 75:
                self.set_icon("7")
            elif round(per) > 62:
                self.set_icon("6")
            elif per > 50:
                self.set_icon("5")
            elif per > 37:
                self.set_icon("4")
            elif per > 25:
                self.set_icon("3")
            elif per > 12:
                self.set_icon("2")
            elif per > 8:
                self.set_icon("1")
            elif per > 5:
                self.set_icon("empty!")
            else:
                self.set_icon("empty")
                self.test.set_blinking(True)
                self.alert(self)
        else:
            pass
            # should this cause an error?
    
    
if __name__ == "__main__":
    
    tray=systray()

i added a set_icon method, which uses the correct path .. basename+"/"+"icons/..."
and the base set to cwd if the first method fails

EDIT: included ibrahim's method, much cleaner

Last edited by kumyco (2009-03-13 00:07:30)

Offline

#8 2009-03-13 00:24:15

genisis300
Member
From: Uk
Registered: 2008-01-15
Posts: 284

Re: python systray problem

i must have skipped the bit on elif i didn't know you could do that.

thats look alot better. and it has also fixed the problem.

Thanks smile


"is adult entertainment killing our children or is killing our children entertaining adults?" Marilyn Manson

Offline

#9 2009-03-13 00:29:48

genisis300
Member
From: Uk
Registered: 2008-01-15
Posts: 284

Re: python systray problem

i'll get to work on the bat0 problem. and some command line options for interval etc

Cheers
Matthew



One idea i had for the battery problem would be to run the command ls /sys/class/power_supply/ | grep BAT
and use the output for the battery.

The only problem i can see with this is if a unit has 2 batteries.

Last edited by genisis300 (2009-03-13 00:34:56)


"is adult entertainment killing our children or is killing our children entertaining adults?" Marilyn Manson

Offline

#10 2009-03-13 07:17:23

kumyco
Member
From: somewhere
Registered: 2008-06-23
Posts: 153
Website

Re: python systray problem

put batpath inside the systray class
have another class if you that manages polling etc, in the manager at startup it will get a directory listing
and grep(string matching, or regex) for BAT, take the first one as reference, and provide a list batteries detected
i don't think it would be good to have multiple batteries in the tray, maybe configuration or something

in the manager you'd poll, say, every 3 seconds and first you check /sys/class/power_supply/AC0/online and if it's online(1)
you just display the power icon, if not(0) then you display the battery status,
all the while you'd keep track the battery statuses as they'd be offered a list, maybe context menu

Offline

#11 2009-03-14 16:44:46

genisis300
Member
From: Uk
Registered: 2008-01-15
Posts: 284

Re: python systray problem

thanks. i will start getting some of these ideas coded in in the next few days.
thanks for the help with this. i have learnt a alot more about pythin since i wrote this program orignal. it wasn't going to be released originaly so i just got it working but i noticed there doesn't seem to be any really light battery monitors. hence the idea to release it.


"is adult entertainment killing our children or is killing our children entertaining adults?" Marilyn Manson

Offline

#12 2009-03-15 03:24:29

genisis300
Member
From: Uk
Registered: 2008-01-15
Posts: 284

Re: python systray problem

okay just a quick update.
I've now added some command line options (not 100% complete yet)
they incude -i to set the default interval in milliseconds
-t --theme to set a diffrent icon theme check out the default theme if your intersted i making your own icon sets

it should also pick up on the default battery number it was orignal set to BAT0 but as was pointed out some laptops use BAT1. let me know if you have any problems with this.

there is a tarbal on the project website it you would like to try it out.

i'm still in the process off improveing the code

again thanks for you help with this
Matthew


"is adult entertainment killing our children or is killing our children entertaining adults?" Marilyn Manson

Offline

Board footer

Powered by FluxBB