Is this patch proposed to include in sugar?<br>The last time, I think we did not have consensus about the face sad/happy.<br><br>Gonzalo <br> <br><br><div class="gmail_quote">On Fri, Jan 21, 2011 at 12:18 PM, Sascha Silbe <span dir="ltr"><<a href="mailto:sascha-pgp@silbe.org">sascha-pgp@silbe.org</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;">From: anishmangal2002 <<a href="mailto:anishmangal2002@gmail.com">anishmangal2002@gmail.com</a>><br>

<div class="im"><br>
This patch adds an icon to the frame, whose palette<br>
menu displays the memory and cpu resources. For computing<br>
free memory, the code reads the /proc/meminfo file (thanks<br>
quozl) and for computing cpu usage, the code reads the<br>
/proc/stat file.<br>
<br>
The frame icon is updated after every 5 seconds if required.<br>
Similarly, the palette menu entries are updated after every<br>
5 seconds as well.<br>
<br>
Signed-off-by: anishmangal2002 <<a href="mailto:anishmangal2002@gmail.com">anishmangal2002@gmail.com</a>><br>
</div>[style fixes, increase weight of memory utilisation for "system mood" so<br>
bursts of CPU activity don't take us from "happy" directly to "sad"]<br>
Signed-off-by: Sascha Silbe <<a href="mailto:sascha-pgp@silbe.org">sascha-pgp@silbe.org</a>><br>
Reviewed-by: Sascha Silbe <<a href="mailto:sascha-pgp@silbe.org">sascha-pgp@silbe.org</a>><br>
---<br>
 extensions/deviceicon/Makefile.am  |    1 +<br>
 extensions/deviceicon/resources.py |  212 ++++++++++++++++++++++++++++++++++++<br>
 po/POTFILES.in                     |    1 +<br>
 3 files changed, 214 insertions(+), 0 deletions(-)<br>
<div class="im"><br>
diff --git a/extensions/deviceicon/Makefile.am b/extensions/deviceicon/Makefile.am<br>
</div>index d46ddde..44f3e54 100644<br>
<div class="im">--- a/extensions/deviceicon/Makefile.am<br>
+++ b/extensions/deviceicon/Makefile.am<br>
</div>@@ -4,6 +4,7 @@ sugar_PYTHON =          \<br>
        __init__.py     \<br>
        battery.py      \<br>
        network.py      \<br>
+       resources.py    \<br>
        speaker.py      \<br>
        touchpad.py     \<br>
        volume.py<br>
<div class="im">diff --git a/extensions/deviceicon/resources.py b/extensions/deviceicon/resources.py<br>
new file mode 100644<br>
</div>index 0000000..c1e6d23<br>
<div class="im">--- /dev/null<br>
+++ b/extensions/deviceicon/resources.py<br>
</div>@@ -0,0 +1,212 @@<br>
<div class="im">+# Copyright (C) Anish Mangal <<a href="mailto:anishmangal2002@gmail.com">anishmangal2002@gmail.com</a>><br>
+#<br>
+# This program is free software; you can redistribute it and/or modify<br>
+# it under the terms of the GNU General Public License as published by<br>
+# the Free Software Foundation; either version 2 of the License, or<br>
+# (at your option) any later version.<br>
+#<br>
+# This program is distributed in the hope that it will be useful,<br>
+# but WITHOUT ANY WARRANTY; without even the implied warranty of<br>
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the<br>
+# GNU General Public License for more details.<br>
+#<br>
+# You should have received a copy of the GNU General Public License<br>
+# along with this program; if not, write to the Free Software<br>
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA<br>
+<br>
+from gettext import gettext as _<br>
+import logging<br>
+import os<br>
+<br>
+import gobject<br>
+import gtk<br>
+import gconf<br>
+<br>
+from sugar.graphics.tray import TrayIcon<br>
+from sugar.graphics.xocolor import XoColor<br>
+from sugar.graphics.palette import Palette<br>
+from sugar.graphics import style<br>
+<br>
+<br>
+_SYSTEM_MOODS = ['-sad', '-normal', '-happy']<br>
+_ICON_NAME = 'computer'<br>
</div>+_UPDATE_INTERVAL = 5*1000<br>
<div class="im">+<br>
+<br>
+class DeviceView(TrayIcon):<br>
+<br>
+    FRAME_POSITION_RELATIVE = 500<br>
+<br>
+    def __init__(self):<br>
+        client = gconf.client_get_default()<br>
+        self._color = XoColor(client.get_string('/desktop/sugar/user/color'))<br>
+        TrayIcon.__init__(self, icon_name=_ICON_NAME, xo_color=self._color)<br>
+        self.create_palette()<br>
+<br>
+    def create_palette(self):<br>
+        logging.debug('palette created')<br>
+        self.palette = ResourcePalette(_('System resources'))<br>
+        self.palette.set_group_id('frame')<br>
+        self.palette.add_timer()<br>
+        self.palette.connect('system-mood-changed',<br>
+                self._system_mood_changed_cb)<br>
+        return self.palette<br>
+<br>
</div>+    def _system_mood_changed_cb(self, palette_, mood):<br>
<div class="im">+        self.icon.props.icon_name = _ICON_NAME + mood<br>
+<br>
+<br>
+class ResourcePalette(Palette):<br>
+    __gsignals__ = {<br>
+        'system-mood-changed': (gobject.SIGNAL_RUN_FIRST,<br>
+                           gobject.TYPE_NONE,<br>
+                           ([str])),<br>
+    }<br>
+<br>
+    def __init__(self, primary_text):<br>
+        Palette.__init__(self, label=primary_text)<br>
+<br>
+        self.vbox = gtk.VBox()<br>
+        self.set_content(self.vbox)<br>
+<br>
+        self._cpu_text = gtk.Label()<br>
+        self.vbox.pack_start(self._cpu_text, padding=style.DEFAULT_PADDING)<br>
+        self._cpu_bar = gtk.ProgressBar()<br>
+        self._cpu_bar.set_size_request(<br>
+            style.zoom(style.GRID_CELL_SIZE * 4), -1)<br>
+        self.vbox.pack_start(self._cpu_bar, padding=style.DEFAULT_PADDING)<br>
+<br>
+        self._memory_text = gtk.Label()<br>
+        self.vbox.pack_start(self._memory_text, padding=style.DEFAULT_PADDING)<br>
+        self._memory_bar = gtk.ProgressBar()<br>
+        self._memory_bar.set_size_request(<br>
+            style.zoom(style.GRID_CELL_SIZE * 4), -1)<br>
+        self.vbox.pack_start(self._memory_bar, padding=style.DEFAULT_PADDING)<br>
+<br>
</div>+        self._system_mood = None<br>
<div class="im">+        try:<br>
+            self._cpu_times = self._get_cpu_times_list()<br>
+        except IOError:<br>
+            logging.exception('An error ocurred while attempting to '<br>
+                'read /proc/stat')<br>
+            self._stop_computing_statistics()<br>
+<br>
+        self.vbox.show()<br>
+        self._cpu_text.show()<br>
+        self._cpu_bar.show()<br>
+        self._memory_text.show()<br>
+        self._memory_bar.show()<br>
+<br>
+    def add_timer(self):<br>
</div>+        gobject.timeout_add(_UPDATE_INTERVAL, self.__timer_cb)<br>
<div><div></div><div class="h5">+<br>
+    def _get_cpu_times_list(self):<br>
+        """Return various cpu times as read from /proc/stat<br>
+<br>
+        This method returns the following cpu times measured<br>
+        in jiffies (1/100 of a second for x86 systems)<br>
+        as an ordered list of numbers - [user, nice,<br>
+        system, idle, iowait] where,<br>
+<br>
+        user: normal processes executing in user mode<br>
+        nice: niced processes executing in user mode<br>
+        system: processes executing in kernel mode<br>
+        idle: twiddling thumbs<br>
+        iowait: waiting for I/O to complete<br>
+<br>
+        Note: For systems having 2 or more CPU's, the above<br>
+        numbers would be the cumulative sum of these times<br>
+        for all CPU's present in the system.<br>
+<br>
+        """<br>
+        return [int(count)<br>
+           for count in file('/proc/stat').readline().split()[1:6]]<br>
+<br>
+    def _percentage_cpu_available(self):<br>
+        """<br>
+        Return free CPU resources as a percentage<br>
+<br>
+        """<br>
+        _cpu_times_new = self._get_cpu_times_list()<br>
+        _cpu_times_current = [(new - old)<br>
+            for new, old in zip(_cpu_times_new, self._cpu_times)]<br>
+        user_, nice_, system_, idle, iowait = _cpu_times_current<br>
+        cpu_free = (idle + iowait) * 100.0 / sum(_cpu_times_current)<br>
+        self._cpu_times = self._get_cpu_times_list()<br>
+        return cpu_free<br>
+<br>
+    def _percentage_memory_available(self):<br>
+        """<br>
+        Return free memory as a percentage<br>
+<br>
+        """<br>
+        for line in file('/proc/meminfo'):<br>
+            name, value, unit_ = line.split()[:3]<br>
+            if 'MemTotal:' == name:<br>
+                total = int(value)<br>
+            elif 'MemFree:' == name:<br>
+                free = int(value)<br>
+            elif 'Buffers:' == name:<br>
+                buffers = int(value)<br>
+            elif 'Cached:' == name:<br>
+                cached = int(value)<br>
+            elif 'Active:' == name:<br>
+                break<br>
+        return (free + buffers + cached) * 100.0 / total<br>
+<br>
+    def __timer_cb(self):<br>
+        try:<br>
+            cpu_in_use = 100 - self._percentage_cpu_available()<br>
+            memory_in_use = 100 - self._percentage_memory_available()<br>
+        except IOError:<br>
+            logging.exception('An error ocurred while trying to '<br>
+                'retrieve resource usage statistics')<br>
</div></div>+            self._stop_and_show_error()<br>
<div class="im">+            return False<br>
+        else:<br>
+            self._cpu_text.set_label(_('CPU in use: %d%%' % cpu_in_use))<br>
</div>+            self._cpu_bar.set_fraction(float(cpu_in_use) / 100)<br>
<div class="im">+            self._memory_text.set_label(_('Memory in use: %d%%' %<br>
+                memory_in_use))<br>
</div>+            self._memory_bar.set_fraction(float(memory_in_use) / 100)<br>
<div class="im">+<br>
+            # both cpu_free and memory_free lie between 0-100<br>
+            system_mood = _SYSTEM_MOODS[<br>
</div>+                    int(300 - (cpu_in_use + 2 * memory_in_use)) // 100]<br>
<div class="im">+<br>
+            # check if self._system_mood exists<br>
+            try:<br>
+                if self._system_mood != system_mood:<br>
+                    self.emit('system-mood-changed', system_mood)<br>
+                    self._system_mood = system_mood<br>
+            except AttributeError:<br>
+                self.emit('system-mood-changed', system_mood)<br>
+                self._system_mood = system_mood<br>
+<br>
+            return True<br>
+<br>
</div>+    def _stop_and_show_error(self):<br>
+        """<br>
+        Stop computing usage statistics and display an error message<br>
<div class="im">+        since we've hit an exception.<br>
+<br>
+        """<br>
+        # Use the existing _cpu_text label to display the error. Remove<br>
+        # everything else.<br>
+        self._cpu_text.set_size_request(<br>
+            style.zoom(style.GRID_CELL_SIZE * 4), -1)<br>
+        self._cpu_text.set_line_wrap(True)<br>
+        self._cpu_text.set_text(_('Cannot compute CPU and memory usage '<br>
+            'statistics!'))<br>
+        self.vbox.remove(self._cpu_bar)<br>
+        self.vbox.remove(self._memory_text)<br>
+        self.vbox.remove(self._memory_bar)<br>
+        self.emit('system-mood-changed', '-error')<br>
+<br>
+<br>
+def setup(tray):<br>
+    if not (os.path.exists('/proc/stat') and os.path.exists('/proc/meminfo')):<br>
+        logging.warning('Either /proc/stat or /proc/meminfo not present. Not '<br>
+            'adding the CPU and memory usage icon to the frame')<br>
+        return<br>
+    tray.add_device(DeviceView())<br>
</div>diff --git a/po/POTFILES.in b/po/POTFILES.in<br>
index 9e46831..b799339 100644<br>
--- a/po/POTFILES.in<br>
+++ b/po/POTFILES.in<br>
@@ -27,6 +27,7 @@ extensions/cpsection/updater/__init__.py<br>
 extensions/cpsection/updater/view.py<br>
 extensions/deviceicon/battery.py<br>
 extensions/deviceicon/network.py<br>
+extensions/deviceicon/resources.py<br>
 extensions/deviceicon/speaker.py<br>
 extensions/deviceicon/touchpad.py<br>
 extensions/deviceicon/volume.py<br>
<font color="#888888">--<br>
1.7.2.3<br>
</font><div><div></div><div class="h5"><br>
_______________________________________________<br>
Sugar-devel mailing list<br>
<a href="mailto:Sugar-devel@lists.sugarlabs.org">Sugar-devel@lists.sugarlabs.org</a><br>
<a href="http://lists.sugarlabs.org/listinfo/sugar-devel" target="_blank">http://lists.sugarlabs.org/listinfo/sugar-devel</a><br>
</div></div></blockquote></div><br>