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>