Thank you for reviewing this patch. However, after receiving feedback
from Py. I've modified some of its functionality. The two patches
attached implement that functionality. I've updated the parallel
thread "[DESIGN] Displaying the current status of system resources
(such as memory, cpu)" to augment further discussion on this.

--
Anish

On Sat, Jul 10, 2010 at 3:09 PM, Marco Pesenti Gritti <ma...@marcopg.org> wrote:
> On 10 Jul 2010, at 08:43, Anish Mangal <anishmangal2...@gmail.com> wrote:
>>> diff --git a/extensions/deviceicon/resources.py 
>>> b/extensions/deviceicon/resources.py
>>> new file mode 100644
>>> index 0000000..7503bef
>>> --- /dev/null
>>> +++ b/extensions/deviceicon/resources.py
>>> @@ -0,0 +1,188 @@
>>> +# Copyright (C) Anish Mangal <anishmangal2...@gmail.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 St, Fifth Floor, Boston, MA  02110-1301  
>>> USA
>>> +
>>> +from gettext import gettext as _
>>> +import logging
>>> +import os
>>> +
>>> +import gobject
>>> +import gtk
>>> +import gconf
>>> +
>>> +from sugar.graphics.tray import TrayIcon
>>> +from sugar.graphics.xocolor import XoColor
>>> +from sugar.graphics.palette import Palette
>>> +from sugar.graphics import style
>>> +
>>> +from jarabe.frame.frameinvoker import FrameWidgetInvoker
>>> +
>>> +class DeviceView(TrayIcon):
>>> +
>>> +    FRAME_POSITION_RELATIVE = 500
>>> +
>>> +    def __init__(self):
>>> +        client = gconf.client_get_default()
>>> +        color = XoColor(client.get_string('/desktop/sugar/user/color'))
>>> +        TrayIcon.__init__(self, icon_name='computer', xo_color=color)
>>> +        self.set_palette_invoker(FrameWidgetInvoker(self))
>>> +
>>> +    def create_palette(self):
>>> +        palette = ResourcePalette(_('System resources'))
>>> +        palette.set_group_id('frame')
>>> +        return palette
>>> +
>>> +class ResourcePalette(Palette):
>>> +
>>> +    def __init__(self, primary_text):
>>> +        Palette.__init__(self, label=primary_text)
>>> +
>>> +        self._popup_cb_id = self.connect('popup', self._popup_cb)
>>> +        self._popdown_cb_id = self.connect('popdown', self._popdown_cb)
>>> +
>>> +        self.vbox = gtk.VBox()
>>> +        self.set_content(self.vbox)
>>> +
>>> +        self._cpu_text = gtk.Label()
>>> +        self.vbox.pack_start(self._cpu_text, padding=style.DEFAULT_PADDING)
>>> +        self._cpu_text.show()
>>> +
>>> +        self._cpu_bar = gtk.ProgressBar()
>>> +        self._cpu_bar.set_size_request(
>>> +            style.zoom(style.GRID_CELL_SIZE * 4), -1)
>>> +        self.vbox.pack_start(self._cpu_bar, padding=style.DEFAULT_PADDING)
>>> +        self._cpu_bar.show()
>>> +
>>> +        self._memory_text = gtk.Label()
>>> +        self.vbox.pack_start(self._memory_text, 
>>> padding=style.DEFAULT_PADDING)
>>> +        self._memory_text.show()
>>> +
>>> +        self._memory_bar = gtk.ProgressBar()
>>> +        self._memory_bar.set_size_request(
>>> +            style.zoom(style.GRID_CELL_SIZE * 4), -1)
>>> +        self.vbox.pack_start(self._memory_bar, 
>>> padding=style.DEFAULT_PADDING)
>>> +        self._memory_bar.show()
>>> +
>>> +        self.vbox.show()
>>> +
>>> +        try:
>>> +            self._cpu_times = self._get_cpu_times_list()
>>> +        except Exception:
>>> +            logging.exception('An error ocurred while attempting to '
>>> +                'read /proc/stat')
>
> Which exceptions do you expect to happen and in which situations? Catch all 
> exceptions are generally a bad idea.
>
>
>>> +            self._remove_callbacks()
>>> +
>>> +    def _get_cpu_times_list(self):
>>> +        """Return various cpu times as read from /proc/stat
>>> +
>>> +        This method returns the following cpu times measured
>>> +        in jiffies (1/100 of a second for x86 systems)
>>> +        as an ordered list of numbers - [user, nice,
>>> +        system, idle, iowait] where,
>>> +
>>> +        user: normal processes executing in user mode
>>> +        nice: niced processes executing in user mode
>>> +        system: processes executing in kernel mode
>>> +        idle: twiddling thumbs
>>> +        iowait: waiting for I/O to complete
>>> +
>>> +        Note: For systems having 2 or more CPU's, the above
>>> +        numbers would be the cumulative sum of these times
>>> +        for all CPU's present in the system.
>>> +
>>> +        """
>>> +        return [int(count)
>>> +           for count in file('/proc/stat').readline().split()[1:6]]
>>> +
>>> +    def _percentage_cpu_available(self):
>>> +        """
>>> +        Return free CPU resources as a percentage
>>> +
>>> +        """
>>> +        _cpu_times_new = self._get_cpu_times_list()
>>> +        _cpu_times_current = [(new - old)
>>> +            for new, old in zip(_cpu_times_new, self._cpu_times)]
>>> +        user, nice, system, idle, iowait = _cpu_times_current
>>> +        cpu_free = (idle + iowait) * 100.0 / sum(_cpu_times_current)
>>> +        self._cpu_times = self._get_cpu_times_list()
>>> +        return cpu_free
>>> +
>>> +    def _percentage_memory_available(self):
>>> +        """
>>> +        Return free memory as a percentage
>>> +
>>> +        """
>>> +        for line in file('/proc/meminfo'):
>>> +            name, value, unit = line.split()[:3]
>>> +            if 'MemTotal:' == name:
>>> +                total = int(value)
>>> +            elif 'MemFree:' == name:
>>> +                free = int(value)
>>> +            elif 'Buffers:' == name:
>>> +                buffers = int(value)
>>> +            elif 'Cached:' == name:
>>> +                cached = int(value)
>>> +            elif 'Active:' == name:
>>> +                break
>>> +        return (free + buffers + cached) * 100.0 / total
>>> +
>>> +    def __timer_cb(self):
>>> +        try:
>>> +            cpu_free = self._percentage_cpu_available()
>>> +            memory_free = self._percentage_memory_available()
>>> +            self._cpu_text.set_label(_('CPU free: %d%%' % cpu_free))
>>> +            self._cpu_bar.set_fraction(cpu_free/100.0)
>
> Space around the operator
>
>>> +            self._memory_text.set_label(_('Memory free: %d%%' % 
>>> memory_free))
>>> +            self._memory_bar.set_fraction(memory_free/100.0)
>
> Same
>
>
>>> +            return True
>>> +        except Exception:
>>> +            logging.exception('An error ocurred while trying to '
>>> +                'retrieve resource usage statistics')
>>> +            self._remove_callbacks()
>>> +            return False
>
> Same here. Also the UI code should be moved outside the try so that we don't 
> cover errors in it.
>
>>>
>>> +    def _remove_callbacks(self):
>>> +        """
>>> +        Stop computing usage statistics and display and error message
>>> +        since we've hit an exception.
>>> +
>>> +        """
>>> +        self.disconnect(self._popup_cb_id)
>>> +        self.disconnect(self._popdown_cb_id)
>>> +
>>> +        # Use the existing _cpu_text label to display the error. Remove
>>> +        # everything else.
>>> +        self._cpu_text.set_size_request(
>>> +            style.zoom(style.GRID_CELL_SIZE * 4), -1)
>>> +        self._cpu_text.set_line_wrap(True)
>>> +        self._cpu_text.set_text(_('Cannot compute CPU and memory usage '
>>> +            'statistics!'))
>>> +        self.vbox.remove(self._cpu_bar)
>>> +        self.vbox.remove(self._memory_text)
>>> +        self.vbox.remove(self._memory_bar)
>
> This method does a lot more than disconnecting callbacks. The naming should 
> reflect that or the method should be split.
>
> Thanks!
> Marco
From 9f847e69dff5ee1f8c9b3df09f257e361e9fe562 Mon Sep 17 00:00:00 2001
From: anishmangal2002 <anishmangal2...@gmail.com>
Date: Thu, 29 Jul 2010 00:49:29 +0530
Subject: [PATCH] Add icons for memory and cpu resource indicator

This patch adds the following for svg icons for the memory and cpu
usage indicator frame icon.

computer-happy
computer-normal
computer-sad
computer-error

Signed-off-by: anishmangal2002 <anishmangal2...@gmail.com>
---
 icons/scalable/device/Makefile.am         |    4 ++++
 icons/scalable/device/computer-error.svg  |   11 +++++++++++
 icons/scalable/device/computer-happy.svg  |   11 +++++++++++
 icons/scalable/device/computer-normal.svg |   11 +++++++++++
 icons/scalable/device/computer-sad.svg    |   11 +++++++++++
 5 files changed, 48 insertions(+), 0 deletions(-)
 create mode 100644 icons/scalable/device/computer-error.svg
 create mode 100644 icons/scalable/device/computer-happy.svg
 create mode 100644 icons/scalable/device/computer-normal.svg
 create mode 100644 icons/scalable/device/computer-sad.svg

diff --git a/icons/scalable/device/Makefile.am b/icons/scalable/device/Makefile.am
index 28818ab..4ab0a56 100644
--- a/icons/scalable/device/Makefile.am
+++ b/icons/scalable/device/Makefile.am
@@ -38,6 +38,10 @@ icon_DATA =				\
 	battery-charging-100.svg	\
 	camera-external.svg		\
 	camera.svg			\
+	computer-error.svg              \
+	computer-happy.svg              \
+	computer-normal.svg             \
+	computer-sad.svg                \
 	computer.svg			\
 	computer-xo.svg			\
 	drive.svg			\
diff --git a/icons/scalable/device/computer-error.svg b/icons/scalable/device/computer-error.svg
new file mode 100644
index 0000000..ca280d3
--- /dev/null
+++ b/icons/scalable/device/computer-error.svg
@@ -0,0 +1,11 @@
+<?xml version="1.0" ?>
+<!-- Created with Inkscape (http://www.inkscape.org/) --><!DOCTYPE svg
+  PUBLIC '-//W3C//DTD SVG 1.1//EN'
+  'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd' [
+	<!ENTITY stroke_color "#010101">
+	<!ENTITY fill_color "#ffffff">
+]>
+<svg height="55" id="Layer_1" version="1.1" viewBox="0 0 55 55" width="55" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"; xmlns:svg="http://www.w3.org/2000/svg";><defs id="defs9"/><g id="computer" style="display:block">
+	<path d="m 51.322,41.549 h 0.002 l -0.022,-0.018 c -0.15,-0.109 -12.64,-7.878 -12.64,-7.878 V 9.734 c 0,-1.618 -1.31,-2.932 -2.929,-2.932 h -30.9 c -1.619,0 -2.931,1.314 -2.931,2.932 v 26.313 c 0,1.096 0.608,2.037 1.498,2.541 l -0.02,0.004 14.603,9.102 c 0.691,0.436 1.528,0.688 2.428,0.688 h 28.212 c 2.352,0 4.278,-1.733 4.278,-3.85 10e-4,-1.202 -0.618,-2.275 -1.579,-2.983 z" id="module-about_x5F_my_x5F_xo" style="fill:&fill_color;;stroke:&stroke_color;;stroke-width:3.48670006;stroke-linejoin:round"/>
+	<path d="m 7.604,13.446 c 0,-0.616 0.504,-1.12 1.12,-1.12 h 23.117 c 0.615,0 1.118,0.503 1.118,1.12 v 16.499 c 0,0.614 -0.503,1.122 -1.118,1.122 H 8.723 c -0.615,0 -1.12,-0.508 -1.12,-1.122 l 0.001,-16.499 0,0 z" id="path5" style="fill:&stroke_color;"/>
+</g><g id="g3651"><g id="g3603" transform="matrix(0.80645161,0,0,0.80645161,10.129032,3.6774194)"><path d="m 42,7 12,12 0,0" id="path3599" style="fill:none;stroke:&stroke_color;;stroke-width:3.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"/><path d="M 42,19 54,7" id="path3601" style="fill:none;stroke:&stroke_color;;stroke-width:3.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"/></g></g></svg>
\ No newline at end of file
diff --git a/icons/scalable/device/computer-happy.svg b/icons/scalable/device/computer-happy.svg
new file mode 100644
index 0000000..a3ca2fc
--- /dev/null
+++ b/icons/scalable/device/computer-happy.svg
@@ -0,0 +1,11 @@
+<?xml version="1.0" ?>
+<!-- Created with Inkscape (http://www.inkscape.org/) --><!DOCTYPE svg
+  PUBLIC '-//W3C//DTD SVG 1.1//EN'
+  'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd' [
+	<!ENTITY stroke_color "#ffffff">
+	<!ENTITY fill_color "#010101">
+]>
+<svg height="55" id="Layer_1" version="1.1" viewBox="0 0 55 55" width="55" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"; xmlns:svg="http://www.w3.org/2000/svg";><defs id="defs9"/><g id="computer" style="display:block">
+	<path d="m 51.322,41.549 h 0.002 l -0.022,-0.018 c -0.15,-0.109 -12.64,-7.878 -12.64,-7.878 V 9.734 c 0,-1.618 -1.31,-2.932 -2.929,-2.932 h -30.9 c -1.619,0 -2.931,1.314 -2.931,2.932 v 26.313 c 0,1.096 0.608,2.037 1.498,2.541 l -0.02,0.004 14.603,9.102 c 0.691,0.436 1.528,0.688 2.428,0.688 h 28.212 c 2.352,0 4.278,-1.733 4.278,-3.85 10e-4,-1.202 -0.618,-2.275 -1.579,-2.983 z" id="module-about_x5F_my_x5F_xo" style="fill:&stroke_color;;stroke:&fill_color;;stroke-width:3.48670006;stroke-linejoin:round"/>
+	<path d="m 7.604,13.446 c 0,-0.616 0.504,-1.12 1.12,-1.12 h 23.117 c 0.615,0 1.118,0.503 1.118,1.12 v 16.499 c 0,0.614 -0.503,1.122 -1.118,1.122 H 8.723 c -0.615,0 -1.12,-0.508 -1.12,-1.122 l 0.001,-16.499 0,0 z" id="path5" style="fill:&fill_color;"/>
+</g><g id="g3651"><path d="m 22,21.5 a 0.5,0.5 0 1 1 -1,0 0.5,0.5 0 1 1 1,0 z" id="path2825-3" style="fill:&stroke_color;;fill-opacity:1;stroke:&stroke_color;;stroke-width:3.5;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" transform="translate(-5.5,-5)"/><path d="m 22,21.5 a 0.5,0.5 0 1 1 -1,0 0.5,0.5 0 1 1 1,0 z" id="path2825-3-7" style="fill:&stroke_color;;fill-opacity:1;stroke:&stroke_color;;stroke-width:3.5;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" transform="translate(4.5,-5)"/><path d="m 21,20 0,1 0,0" id="path3643" style="fill:&stroke_color;;fill-opacity:1;stroke:&stroke_color;;stroke-width:3.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"/><path d="m -15.592733,28.013593 a 7,5 0 0 1 -12.796629,0.02882" id="path3649" style="fill:&fill_color;;fill-opacity:1;stroke:&stroke_color;;stroke-width:3.5;stroke-linecap:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" transform="translate(43,-4)"/><path d="m -22,29 c -2.062101,-0.0085 -3.533664,-7.690053 -5.201954,-8.902136 -1.657496,-1.20424 -9.38992,-0.202483 -10.01495,-2.153592 -0.6291,-1.963814 6.221713,-5.737072 6.858942,-7.698263 0.633106,-1.9485034 -2.709072,-8.9929164 -1.046602,-10.19028066 1.673296,-1.20516154 7.378894,4.14434776 9.441013,4.14434696 2.048777,-8e-7 7.715622,-5.3554444 9.368115,-4.14434746 1.663253,1.21898366 -1.661305,8.29841966 -1.024075,10.25961116 0.633108,1.948502 7.4775888,5.683069 6.8364154,7.628933 -0.6453487,1.958534 -8.4056374,0.984357 -10.0739264,2.196441 C -18.514517,21.344954 -19.95124,29.008487 -22,29 z" id="path3624" style="fill:&fill_color;;fill-opacity:1;stroke:none" transform="matrix(0.42707473,0,0,-0.42707473,57.395644,21.385167)"/></g></svg>
\ No newline at end of file
diff --git a/icons/scalable/device/computer-normal.svg b/icons/scalable/device/computer-normal.svg
new file mode 100644
index 0000000..144e123
--- /dev/null
+++ b/icons/scalable/device/computer-normal.svg
@@ -0,0 +1,11 @@
+<?xml version="1.0" ?>
+<!-- Created with Inkscape (http://www.inkscape.org/) --><!DOCTYPE svg
+  PUBLIC '-//W3C//DTD SVG 1.1//EN'
+  'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd' [
+	<!ENTITY stroke_color "#010101">
+	<!ENTITY fill_color "#ffffff">
+]>
+<svg height="55" id="Layer_1" version="1.1" viewBox="0 0 55 55" width="55" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"; xmlns:svg="http://www.w3.org/2000/svg";><defs id="defs9"/><g id="computer" style="display:block">
+	<path d="m 51.322,41.549 h 0.002 l -0.022,-0.018 c -0.15,-0.109 -12.64,-7.878 -12.64,-7.878 V 9.734 c 0,-1.618 -1.31,-2.932 -2.929,-2.932 h -30.9 c -1.619,0 -2.931,1.314 -2.931,2.932 v 26.313 c 0,1.096 0.608,2.037 1.498,2.541 l -0.02,0.004 14.603,9.102 c 0.691,0.436 1.528,0.688 2.428,0.688 h 28.212 c 2.352,0 4.278,-1.733 4.278,-3.85 10e-4,-1.202 -0.618,-2.275 -1.579,-2.983 z" id="module-about_x5F_my_x5F_xo" style="fill:&fill_color;;stroke:&stroke_color;;stroke-width:3.48670006;stroke-linejoin:round"/>
+	<path d="m 7.604,13.446 c 0,-0.616 0.504,-1.12 1.12,-1.12 h 23.117 c 0.615,0 1.118,0.503 1.118,1.12 v 16.499 c 0,0.614 -0.503,1.122 -1.118,1.122 H 8.723 c -0.615,0 -1.12,-0.508 -1.12,-1.122 l 0.001,-16.499 0,0 z" id="path5" style="fill:&stroke_color;"/>
+</g><g id="g3651"><path d="m 22,21.5 a 0.5,0.5 0 1 1 -1,0 0.5,0.5 0 1 1 1,0 z" id="path2825-3" style="fill:&fill_color;;fill-opacity:1;stroke:&fill_color;;stroke-width:3.5;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" transform="translate(-5.5,-5)"/><path d="m 22,21.5 a 0.5,0.5 0 1 1 -1,0 0.5,0.5 0 1 1 1,0 z" id="path2825-3-7" style="fill:&fill_color;;fill-opacity:1;stroke:&fill_color;;stroke-width:3.5;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" transform="translate(4.5,-5)"/><path d="m 21,20 0,1 0,0" id="path3643" style="fill:&fill_color;;fill-opacity:1;stroke:&fill_color;;stroke-width:3.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"/><path d="m 14,26 14,0" id="path3792" style="fill:none;stroke:&fill_color;;stroke-width:3.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"/></g></svg>
\ No newline at end of file
diff --git a/icons/scalable/device/computer-sad.svg b/icons/scalable/device/computer-sad.svg
new file mode 100644
index 0000000..5475bfa
--- /dev/null
+++ b/icons/scalable/device/computer-sad.svg
@@ -0,0 +1,11 @@
+<?xml version="1.0" ?>
+<!-- Created with Inkscape (http://www.inkscape.org/) --><!DOCTYPE svg
+  PUBLIC '-//W3C//DTD SVG 1.1//EN'
+  'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd' [
+	<!ENTITY stroke_color "#010101">
+	<!ENTITY fill_color "#ffffff">
+]>
+<svg height="55" id="Layer_1" version="1.1" viewBox="0 0 55 55" width="55" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"; xmlns:svg="http://www.w3.org/2000/svg";><defs id="defs9"/><g id="computer" style="display:block">
+	<path d="m 51.322,41.549 h 0.002 l -0.022,-0.018 c -0.15,-0.109 -12.64,-7.878 -12.64,-7.878 V 9.734 c 0,-1.618 -1.31,-2.932 -2.929,-2.932 h -30.9 c -1.619,0 -2.931,1.314 -2.931,2.932 v 26.313 c 0,1.096 0.608,2.037 1.498,2.541 l -0.02,0.004 14.603,9.102 c 0.691,0.436 1.528,0.688 2.428,0.688 h 28.212 c 2.352,0 4.278,-1.733 4.278,-3.85 10e-4,-1.202 -0.618,-2.275 -1.579,-2.983 z" id="module-about_x5F_my_x5F_xo" style="fill:&fill_color;;stroke:&stroke_color;;stroke-width:3.48670006;stroke-linejoin:round"/>
+	<path d="m 7.604,13.446 c 0,-0.616 0.504,-1.12 1.12,-1.12 h 23.117 c 0.615,0 1.118,0.503 1.118,1.12 v 16.499 c 0,0.614 -0.503,1.122 -1.118,1.122 H 8.723 c -0.615,0 -1.12,-0.508 -1.12,-1.122 l 0.001,-16.499 0,0 z" id="path5" style="fill:&stroke_color;"/>
+</g><g id="g3651"><path d="m 15.900362,16.499593 a 0.5,0.5 0 0 1 -1,0 0.5,0.5 0 1 1 1,0 z" id="path2825-3" style="fill:&fill_color;;fill-opacity:1;stroke:&fill_color;;stroke-width:3.5;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"/><path d="m 25.900362,16.499593 a 0.5,0.5 0 0 1 -1,0 0.5,0.5 0 1 1 1,0 z" id="path2825-3-7" style="fill:&fill_color;;fill-opacity:1;stroke:&fill_color;;stroke-width:3.5;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"/><path d="m 20.400362,19.999593 0,0.625 0,0" id="path3643" style="fill:&fill_color;;fill-opacity:1;stroke:&fill_color;;stroke-width:3.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"/><path d="m 26.807629,27.986 c -2.407267,-1.986407 -4.407267,-2.423907 -6.407267,-2.423907 -2,0 -4,0.4375 -6.389362,2.395087" id="path3649" style="fill:none;stroke:&fill_color;;stroke-width:3.5;stroke-linecap:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"/><path d="m 48,7 c 0,0 -4,6 -4,12 0,2 2.333333,3 4,3 1.666667,0 4,-1 4,-3 C 52,13 48,7 48,7 l 0,0" id="path3746" style="fill:&stroke_color;;fill-opacity:1;stroke:none"/></g></svg>
\ No newline at end of file
-- 
1.7.1

From 17708e9ca250f265bc0b4561515f0ac2758d00de Mon Sep 17 00:00:00 2001
From: anishmangal2002 <anishmangal2...@gmail.com>
Date: Fri, 2 Jul 2010 20:45:28 +0530
Subject: [PATCH] Add cpu and memory resource indicator to frame

This patch adds an icon to the frame, whose palette
menu displays the memory and cpu resources. For computing
free memory, the code reads the /proc/meminfo file (thanks
quozl) and for computing cpu usage, the code reads the
/proc/stat file.

The frame icon is updated after every 5 seconds if required.
Similarly, the palette menu entries are updated after every
5 seconds as well.

Signed-off-by: anishmangal2002 <anishmangal2...@gmail.com>
---
 extensions/deviceicon/Makefile.am  |    3 +-
 extensions/deviceicon/resources.py |  206 ++++++++++++++++++++++++++++++++++++
 2 files changed, 208 insertions(+), 1 deletions(-)
 create mode 100644 extensions/deviceicon/resources.py

diff --git a/extensions/deviceicon/Makefile.am b/extensions/deviceicon/Makefile.am
index 8a2e765..038c059 100644
--- a/extensions/deviceicon/Makefile.am
+++ b/extensions/deviceicon/Makefile.am
@@ -5,4 +5,5 @@ sugar_PYTHON = 		\
 	battery.py	\
 	network.py	\
 	speaker.py	\
-	volume.py
+	volume.py	\
+	resources.py
diff --git a/extensions/deviceicon/resources.py b/extensions/deviceicon/resources.py
new file mode 100644
index 0000000..331459d
--- /dev/null
+++ b/extensions/deviceicon/resources.py
@@ -0,0 +1,206 @@
+# Copyright (C) Anish Mangal <anishmangal2...@gmail.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 St, Fifth Floor, Boston, MA  02110-1301  USA
+
+from gettext import gettext as _
+import logging
+import os
+
+import gobject
+import gtk
+import gconf
+
+from sugar.graphics.tray import TrayIcon
+from sugar.graphics.xocolor import XoColor
+from sugar.graphics.palette import Palette
+from sugar.graphics import style
+
+_SYSTEM_MOODS = ['-sad', '-normal', '-happy']
+_ICON_NAME = 'computer'
+
+class DeviceView(TrayIcon):
+
+    FRAME_POSITION_RELATIVE = 500
+
+    def __init__(self):
+        client = gconf.client_get_default()
+        self._color = XoColor(client.get_string('/desktop/sugar/user/color'))
+        TrayIcon.__init__(self, icon_name=_ICON_NAME, xo_color=self._color)
+        self.create_palette()
+
+    def create_palette(self):
+        logging.debug('palette created')
+        self.palette = ResourcePalette(_('System resources'))
+        self.palette.set_group_id('frame')
+        self.palette.add_timer()
+        self.palette.connect('system-mood-changed',
+                self._system_mood_changed_cb)
+        return self.palette
+
+    def _system_mood_changed_cb(self, gobject, mood):
+        self.icon.props.icon_name = _ICON_NAME + mood
+
+class ResourcePalette(Palette):
+    __gsignals__ = {
+        'system-mood-changed': (gobject.SIGNAL_RUN_FIRST,
+                           gobject.TYPE_NONE,
+                           ([str]))
+    }
+
+    def __init__(self, primary_text):
+        Palette.__init__(self, label=primary_text)
+
+        self.vbox = gtk.VBox()
+        self.set_content(self.vbox)
+
+        self._cpu_text = gtk.Label()
+        self.vbox.pack_start(self._cpu_text, padding=style.DEFAULT_PADDING)
+        self._cpu_bar = gtk.ProgressBar()
+        self._cpu_bar.set_size_request(
+            style.zoom(style.GRID_CELL_SIZE * 4), -1)
+        self.vbox.pack_start(self._cpu_bar, padding=style.DEFAULT_PADDING)
+
+        self._memory_text = gtk.Label()
+        self.vbox.pack_start(self._memory_text, padding=style.DEFAULT_PADDING)
+        self._memory_bar = gtk.ProgressBar()
+        self._memory_bar.set_size_request(
+            style.zoom(style.GRID_CELL_SIZE * 4), -1)
+        self.vbox.pack_start(self._memory_bar, padding=style.DEFAULT_PADDING)
+
+        try:
+            self._cpu_times = self._get_cpu_times_list()
+        except IOError:
+            logging.exception('An error ocurred while attempting to '
+                'read /proc/stat')
+            self._stop_computing_statistics()
+
+        self.vbox.show()
+        self._cpu_text.show()
+        self._cpu_bar.show()
+        self._memory_text.show()
+        self._memory_bar.show()
+
+    def add_timer(self):
+        self._timer = gobject.timeout_add(5000, self.__timer_cb)
+
+    def _get_cpu_times_list(self):
+        """Return various cpu times as read from /proc/stat
+
+        This method returns the following cpu times measured
+        in jiffies (1/100 of a second for x86 systems)
+        as an ordered list of numbers - [user, nice,
+        system, idle, iowait] where,
+
+        user: normal processes executing in user mode
+        nice: niced processes executing in user mode
+        system: processes executing in kernel mode
+        idle: twiddling thumbs
+        iowait: waiting for I/O to complete
+
+        Note: For systems having 2 or more CPU's, the above
+        numbers would be the cumulative sum of these times
+        for all CPU's present in the system.
+
+        """
+        return [int(count)
+           for count in file('/proc/stat').readline().split()[1:6]]
+
+    def _percentage_cpu_available(self):
+        """
+        Return free CPU resources as a percentage
+
+        """
+        _cpu_times_new = self._get_cpu_times_list()
+        _cpu_times_current = [(new - old)
+            for new, old in zip(_cpu_times_new, self._cpu_times)]
+        user, nice, system, idle, iowait = _cpu_times_current
+        cpu_free = (idle + iowait) * 100.0 / sum(_cpu_times_current)
+        self._cpu_times = self._get_cpu_times_list()
+        return cpu_free
+
+    def _percentage_memory_available(self):
+        """
+        Return free memory as a percentage
+
+        """
+        for line in file('/proc/meminfo'):
+            name, value, unit = line.split()[:3]
+            if 'MemTotal:' == name:
+                total = int(value)
+            elif 'MemFree:' == name:
+                free = int(value)
+            elif 'Buffers:' == name:
+                buffers = int(value)
+            elif 'Cached:' == name:
+                cached = int(value)
+            elif 'Active:' == name:
+                break
+        return (free + buffers + cached) * 100.0 / total
+
+    def __timer_cb(self):
+        try:
+            cpu_in_use = 100 - self._percentage_cpu_available()
+            memory_in_use = 100 - self._percentage_memory_available()
+        except IOError:
+            logging.exception('An error ocurred while trying to '
+                'retrieve resource usage statistics')
+            self._stop_computing_statistics()
+            return False
+        else:
+            self._cpu_text.set_label(_('CPU in use: %d%%' % cpu_in_use))
+            self._cpu_bar.set_fraction( cpu_in_use / 100.0 )
+            self._memory_text.set_label(_('Memory in use: %d%%' %
+                memory_in_use))
+            self._memory_bar.set_fraction( memory_in_use / 100.0 )
+
+            # both cpu_free and memory_free lie between 0-100
+            system_mood = _SYSTEM_MOODS[
+                    int( ( 200 - (cpu_in_use + memory_in_use) ) / 66.66 ) ]
+
+            # check if self._system_mood exists
+            try:
+                if self._system_mood != system_mood:
+                    self.emit('system-mood-changed', system_mood)
+                    self._system_mood = system_mood
+            except AttributeError:
+                self.emit('system-mood-changed', system_mood)
+                self._system_mood = system_mood
+
+            return True
+
+    def _stop_computing_statistics(self):
+        """
+        Stop computing usage statistics and display and error message
+        since we've hit an exception.
+
+        """
+        # Use the existing _cpu_text label to display the error. Remove
+        # everything else.
+        self._cpu_text.set_size_request(
+            style.zoom(style.GRID_CELL_SIZE * 4), -1)
+        self._cpu_text.set_line_wrap(True)
+        self._cpu_text.set_text(_('Cannot compute CPU and memory usage '
+            'statistics!'))
+        self.vbox.remove(self._cpu_bar)
+        self.vbox.remove(self._memory_text)
+        self.vbox.remove(self._memory_bar)
+        self.emit('system-mood-changed', '-error')
+
+def setup(tray):
+    if not (os.path.exists('/proc/stat') and os.path.exists('/proc/meminfo')):
+        logging.warning('Either /proc/stat or /proc/meminfo not present. Not '
+            'adding the CPU and memory usage icon to the frame')
+        return
+    tray.add_device(DeviceView())
-- 
1.7.1

_______________________________________________
Sugar-devel mailing list
Sugar-devel@lists.sugarlabs.org
http://lists.sugarlabs.org/listinfo/sugar-devel

Reply via email to