To finish our work we need to define the handlers for every event we have defined at the "GTK widgets" section or with the glade.XML method. For this task, the pyGTK reference manual (see bibliography) is a must see. We need to know the arguments of the handler method for every signal and every event we are catching.
# callback for update the info on the applet periodically def update_info(self,widget,event): info = self.read_proc_info(); self.tooltips.set_tip(self.ev_box, info + " " + info); # callback to create the context menu with 'about' and 'preferences' def button_press(self,widget,event): if event.type == gtk.gdk.BUTTON_PRESS and event.button == 3: self.create_menu() def about_info(self,event,data=None): about = gnome.ui.About("CPU performance stats applet","0.1","GPL","Applet to check throttling and performance states",["Arturo Gonzalez"],["Arturo Gonzalez"],"Arturo Gonzalez",self.logo_pixbuf) about.show() def properties(self,event,data=None): self.preferences.show()
This is the callback that should be used in case we need to update some info on the applet from time to time. The important here is the return value of the method. A return value of 0 implies that we want to stop checking the system for changes. If we want to go on checking, we must return a value of 1.
def timeout_callback(self,event): self.read_proc_info() ##### here you should update the widgets contents. ##### ##### look at the code of the example section ##### ##### to see an approach to this task ##### return 1 # this function update the info extracted from /proc/acpi def read_proc_info(self): # cpu power in mhz if (os.path.isfile("/proc/cpuinfo")): f_proc = open("/proc/cpuinfo") for line in f_proc: try: line.index("cpu MHz") self.info = line.strip().replace(" ","").split(":") except ValueError: pass else: self.checks # throttling support if (os.path.isfile("/proc/acpi/processor/CPU0/throttling")): f_throt = open("/proc/acpi/processor/CPU0/throttling","r") cont = 1 for line in f_throt: if cont == 1: tmp = re.split('\W+',line) self.throttling_states = int(tmp) else: # search for * and print self.info try: line.index("*") tmp = line.strip().replace(" ","").replace("*","").split(":") self.info = tmp self.info = str(100 - int(tmp[:-1])) + "%" print self.info #print self.info break except ValueError: pass cont = cont + 1 f_throt.close() else: self.info = "" self.info = "" # power support if (os.path.isfile("/proc/acpi/processor/CPU0/power")): f_per = open("/proc/acpi/processor/CPU0/power","r") cont = 1 for line in f_per: if cont == 1: tmp = re.split('\W+',line) self.active_cpu_state = tmp else: try: line.index("*") self.info = line.strip().replace(" ","").replace("*","").split(":") #print self.info break except ValueError: pass cont = cont + 1 f_per.close() else: self.info = "" # 2.6 sys filesystem if (os.path.isfile("/sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors")): f_sys = open("/sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors") for line in f_sys: self.governors = re.split(" ", line) f_sys.close() else: self.governors = "" if (os.path.isfile("/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor")): f_sys = open("/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor") for line in f_sys: self.info = line.strip() f_sys.close() else: self.info = "" if (os.path.isfile("/sys/devices/system/cpu/cpu0/cpufreq/scaling_driver")): f_sys = open("/sys/devices/system/cpu/cpu0/cpufreq/scaling_driver") for line in f_sys: self.info = line.strip() f_sys.close() else: self.info = ""
These methods above are from the pycentrino applet 0.3 release, because they are much clearer that in previous versions. We have two main methods: The first one, timeout_callback() is the method called every second, as defined when calling gtk.timeout_add() in the __init__ method. The second one is a function to read from the /proc and/or /sys filesystems and update the content of the instance variable info. Finally, we'll have something like ["T0","0%","C1","powersave","centrino","1400.0"] in the variable.
Usually, your applet will be set up on an horizontal panel, but there are cases where you can be interested in placing it on a vertical one. So we need to take this into account when coding the __init__ method, and we also need to hook a callback to the "change-orient" signal, which is triggered when you move the applet from an horizontal panel to a vertical one (or vicerversa) or when you change your panel position, modifying its orientation. The code for this callback:
def change_orientation(self,arg1,data): self.orientation = self.applet.get_orient() # first remove the children of the current box for i in range(len(self.numbers)): self.box.remove(self.numbers[i]) # now remove the box itself self.big_evbox.remove(self.box) # time to create the new box if self.orientation == gnome.applet.ORIENT_UP or self.orientation == gnome.applet.ORIENT_DOWN: self.box = gtk.HBox() else: self.box = gtk.VBox() # and now fill it with the numbers for i in range(len(self.numbers)): self.box.pack_start(self.numbers[i]) # final steps self.big_evbox.add(self.box) self.box.show()
It's important to realize that deleting all objects inside the HBox or VBox before moving them to the new VBox or HBox is totally necessary. Finally, we only need to show the box.