Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
authorMarco Pesenti Gritti <marco@localhost.localdomain>2007-01-08 17:06:59 (GMT)
committer Marco Pesenti Gritti <marco@localhost.localdomain>2007-01-08 17:06:59 (GMT)
commitcae78d70415923c0deabd518f23dc534f11cfacd (patch)
tree482c96ed3f959b8f8f3d135d9ec1d905db6a541f /services
parent764eee81e57aa637c7d6c95d3d75f94d9f29d650 (diff)
Rework the console to use autoactivation, move it in services/
Diffstat (limited to 'services')
-rw-r--r--services/Makefile.am2
-rw-r--r--services/console/Makefile.am17
-rw-r--r--services/console/__init__.py1
-rwxr-xr-xservices/console/console.py90
-rw-r--r--services/console/interface/Makefile.am6
-rw-r--r--services/console/interface/__init__.py0
-rw-r--r--services/console/interface/logviewer/Makefile.am4
-rw-r--r--services/console/interface/logviewer/__init__.py1
-rw-r--r--services/console/interface/logviewer/logviewer.py173
-rw-r--r--services/console/interface/memphis/Makefile.am8
-rw-r--r--services/console/interface/memphis/__init__.py1
-rw-r--r--services/console/interface/memphis/memphis.py238
-rw-r--r--services/console/interface/memphis/plugin.py48
-rw-r--r--services/console/interface/memphis/plugins/Makefile.am4
-rw-r--r--services/console/interface/memphis/plugins/clean_size/Makefile.am6
-rw-r--r--services/console/interface/memphis/plugins/clean_size/README2
-rw-r--r--services/console/interface/memphis/plugins/clean_size/__init__.py16
-rw-r--r--services/console/interface/memphis/plugins/clean_size/info.py15
-rw-r--r--services/console/interface/memphis/plugins/cpu/Makefile.am6
-rw-r--r--services/console/interface/memphis/plugins/cpu/README2
-rw-r--r--services/console/interface/memphis/plugins/cpu/__init__.py23
-rw-r--r--services/console/interface/memphis/plugins/cpu/info.py48
-rw-r--r--services/console/interface/memphis/plugins/dirty_size/Makefile.am6
-rw-r--r--services/console/interface/memphis/plugins/dirty_size/README2
-rw-r--r--services/console/interface/memphis/plugins/dirty_size/__init__.py17
-rw-r--r--services/console/interface/memphis/plugins/dirty_size/info.py20
-rw-r--r--services/console/interface/memphis/plugins/memphis_init/Makefile.am6
-rw-r--r--services/console/interface/memphis/plugins/memphis_init/README2
-rw-r--r--services/console/interface/memphis/plugins/memphis_init/__init__.py15
-rw-r--r--services/console/interface/memphis/plugins/memphis_init/info.py13
-rw-r--r--services/console/interface/terminal/Makefile.am5
-rw-r--r--services/console/interface/terminal/__init__.py1
-rw-r--r--services/console/interface/terminal/terminal.py247
-rw-r--r--services/console/interface/xo/Makefile.am6
-rw-r--r--services/console/interface/xo/__init__.py1
-rw-r--r--services/console/interface/xo/drwarea.py77
-rw-r--r--services/console/interface/xo/xo.py199
-rw-r--r--services/console/lib/Makefile.am4
-rw-r--r--services/console/lib/procmem/Makefile.am8
-rw-r--r--services/console/lib/procmem/__init__.py0
-rw-r--r--services/console/lib/procmem/analysis.py30
-rw-r--r--services/console/lib/procmem/proc.py100
-rw-r--r--services/console/lib/procmem/proc_smaps.py129
-rw-r--r--services/console/org.laptop.sugar.Console.service.in4
-rwxr-xr-xservices/console/sugar-console11
45 files changed, 1613 insertions, 1 deletions
diff --git a/services/Makefile.am b/services/Makefile.am
index 9cf9b95..ceb990c 100644
--- a/services/Makefile.am
+++ b/services/Makefile.am
@@ -1 +1 @@
-SUBDIRS = presence nm clipboard datastore
+SUBDIRS = presence nm clipboard datastore console
diff --git a/services/console/Makefile.am b/services/console/Makefile.am
new file mode 100644
index 0000000..fe6aee0
--- /dev/null
+++ b/services/console/Makefile.am
@@ -0,0 +1,17 @@
+SUBDIRS = interface lib
+
+servicedir = $(datadir)/dbus-1/services
+service_in_files = org.laptop.sugar.Console.service.in
+service_DATA = $(service_in_files:.service.in=.service)
+
+$(service_DATA): $(service_in_files) Makefile
+ @sed -e "s|\@bindir\@|$(bindir)|" $< > $@
+
+sugardir = $(pkgdatadir)/shell/console
+sugar_PYTHON = \
+ __init__.py \
+ console.py
+
+bin_SCRIPTS = sugar-console
+
+DISTCLEANFILES = $(service_DATA)
diff --git a/services/console/__init__.py b/services/console/__init__.py
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/services/console/__init__.py
@@ -0,0 +1 @@
+
diff --git a/services/console/console.py b/services/console/console.py
new file mode 100755
index 0000000..1b2a371
--- /dev/null
+++ b/services/console/console.py
@@ -0,0 +1,90 @@
+#!/usr/bin/env python
+
+# Copyright (C) 2006, Eduardo Silva (edsiper@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
+
+import dbus
+import dbus.glib
+import dbus.service
+import os
+import sys
+import gtk
+import gobject
+
+sys.path.append(os.path.dirname(__file__) + '/lib')
+sys.path.append(os.path.dirname(__file__) + '/interface')
+
+CONSOLE_BUS = 'org.laptop.sugar.Console'
+CONSOLE_PATH = '/org/laptop/sugar/Console'
+CONSOLE_IFACE = 'org.laptop.sugar.Console'
+
+class Console:
+
+ def __init__(self):
+
+ # Main Window
+ self.window = gtk.Window()
+ self.window.set_title('Developer console')
+ self.window.connect("delete-event", self._delete_event_cb)
+
+ self.default_width = gtk.gdk.screen_width() * 95 / 100
+ self.default_height = gtk.gdk.screen_height() * 95 / 100
+
+ self.window.set_default_size(self.default_width, self.default_height)
+
+ self.window.realize()
+ self.window.window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG)
+
+ # Notebook
+ self.notebook = gtk.Notebook()
+
+ self._load_interface('xo', 'XO Resources')
+ self._load_interface('memphis', 'Memphis')
+ self._load_interface('logviewer', 'Log Viewer')
+ self._load_interface('terminal', 'Terminal')
+
+ main_hbox = gtk.HBox()
+ main_hbox.pack_start(self.notebook, True, True, 0)
+ main_hbox.show()
+
+ self.notebook.show()
+ self.window.add(main_hbox)
+
+ def _load_interface(self, interface, label):
+ mod = __import__(interface)
+ widget = mod.Interface().widget
+ widget.show()
+
+ self.notebook.append_page(widget, gtk.Label(label))
+
+ def _delete_event_cb(self, window, gdkevent):
+ window.hide()
+ return True
+
+class Service(dbus.service.Object):
+ def __init__(self, bus, object_path=CONSOLE_PATH):
+ dbus.service.Object.__init__(self, bus, object_path)
+ self._console = Console()
+
+ @dbus.service.method(CONSOLE_IFACE)
+ def show(self):
+ self._console.window.present()
+
+bus = dbus.SessionBus()
+name = dbus.service.BusName(CONSOLE_BUS, bus)
+obj = Service(name)
+
+gtk.main()
diff --git a/services/console/interface/Makefile.am b/services/console/interface/Makefile.am
new file mode 100644
index 0000000..2654a4b
--- /dev/null
+++ b/services/console/interface/Makefile.am
@@ -0,0 +1,6 @@
+SUBDIRS = memphis logviewer terminal xo
+
+sugardir = $(pkgdatadir)/shell/console/interface
+sugar_PYTHON = \
+ __init__.py
+
diff --git a/services/console/interface/__init__.py b/services/console/interface/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/services/console/interface/__init__.py
diff --git a/services/console/interface/logviewer/Makefile.am b/services/console/interface/logviewer/Makefile.am
new file mode 100644
index 0000000..e6a6979
--- /dev/null
+++ b/services/console/interface/logviewer/Makefile.am
@@ -0,0 +1,4 @@
+sugardir = $(pkgdatadir)/shell/console/interface/logviewer
+sugar_PYTHON = \
+ __init__.py \
+ logviewer.py
diff --git a/services/console/interface/logviewer/__init__.py b/services/console/interface/logviewer/__init__.py
new file mode 100644
index 0000000..614ed67
--- /dev/null
+++ b/services/console/interface/logviewer/__init__.py
@@ -0,0 +1 @@
+from logviewer import Interface
diff --git a/services/console/interface/logviewer/logviewer.py b/services/console/interface/logviewer/logviewer.py
new file mode 100644
index 0000000..6bd4543
--- /dev/null
+++ b/services/console/interface/logviewer/logviewer.py
@@ -0,0 +1,173 @@
+#!/usr/bin/python
+
+# Copyright (C) 2006, Red Hat, Inc.
+#
+# 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
+
+
+# Rewritten by Eduardo Silva, edsiper@gmail.com
+
+import os
+
+import pygtk
+pygtk.require('2.0')
+import gtk
+import gobject
+
+from sugar import env
+
+class MultiLogView(gtk.VBox):
+ def __init__(self, path):
+ self._active_log = None
+ self._iters = []
+
+ # Creating Main treeview with Actitivities list
+ tv_menu = gtk.TreeView()
+ tv_menu.connect('cursor-changed', self._load_log)
+ tv_menu.set_rules_hint(True)
+
+ # Set width
+ box_width = gtk.gdk.screen_width() * 80 / 100
+ tv_menu.set_size_request(box_width*25/100, 0)
+
+ self.store_menu = gtk.TreeStore(str)
+ tv_menu.set_model(self.store_menu)
+
+ self._add_column(tv_menu, 'Sugar logs', 0)
+ self._logs_path = os.path.join(env.get_profile_path(), 'logs')
+ self._activity = {}
+
+ # Activities menu
+ self.hbox = gtk.HBox(False, 3)
+ self.hbox.pack_start(tv_menu, True, True, 0)
+
+ # Activity log, set width
+ self._view = LogView()
+ self._view.set_size_request(box_width*75/100, 0)
+
+ self.hbox.pack_start(self._view, True, True, 0)
+ self.hbox.show_all()
+
+ gobject.timeout_add(1000, self._update, tv_menu)
+
+ # Load the log information in View (textview)
+ def _load_log(self, treeview):
+ treeselection = treeview.get_selection()
+
+ treestore, iter = treeselection.get_selected()
+
+ # Get current selection
+ act_log = self.store_menu.get_value(iter, 0)
+
+ # Set buffer and scroll down
+ self._view.textview.set_buffer(self._activity[act_log])
+ self._view.textview.scroll_to_mark(self._activity[act_log].get_insert(), 0);
+ self._active_log = act_log
+
+ def _update(self, tv_menu):
+ # Searching log files
+ for logfile in os.listdir(self._logs_path):
+
+ if not self._activity.has_key(logfile):
+ self._add_activity(logfile)
+ full_log_path = os.path.join(self._logs_path, logfile)
+ model = LogBuffer(full_log_path)
+ self._activity[logfile] = model
+
+ self._activity[logfile].update()
+ written = self._activity[logfile]._written
+
+ # Load the first iter
+ if self._active_log == None:
+ self._active_log = logfile
+ iter = tv_menu.get_model().get_iter_root()
+ tv_menu.get_selection().select_iter(iter)
+ self._load_log(tv_menu)
+
+ if written > 0 and self._active_log == logfile:
+ self._view.textview.scroll_to_mark(self._activity[logfile].get_insert(), 0);
+
+ return True
+
+ def _add_activity(self, name):
+ self._insert_row(self.store_menu, None, name)
+
+ # Add a new column to the main treeview, (code from Memphis)
+ def _add_column(self, treeview, column_name, index):
+ cell = gtk.CellRendererText()
+ col_tv = gtk.TreeViewColumn(column_name, cell, text=index)
+ col_tv.set_resizable(True)
+ col_tv.set_property('clickable', True)
+
+ treeview.append_column(col_tv)
+
+ # Set the last column index added
+ self.last_col_index = index
+
+ # Insert a Row in our TreeView
+ def _insert_row(self, store, parent, name):
+ iter = store.insert_before(parent, None)
+ index = 0
+ store.set_value(iter, index , name)
+
+ return iter
+
+class LogBuffer(gtk.TextBuffer):
+ def __init__(self, logfile):
+ gtk.TextBuffer.__init__(self)
+
+ self._logfile = logfile
+ self._pos = 0
+ self.update()
+
+ def update(self):
+ f = open(self._logfile, 'r')
+
+ init_pos = self._pos
+
+ f.seek(self._pos)
+ self.insert(self.get_end_iter(), f.read())
+ self._pos = f.tell()
+
+ f.close()
+
+ self._written = (self._pos - init_pos)
+ return True
+
+class LogView(gtk.ScrolledWindow):
+ def __init__(self):
+ gtk.ScrolledWindow.__init__(self)
+
+ self.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+
+ self.textview = gtk.TextView()
+ self.textview.set_wrap_mode(gtk.WRAP_WORD)
+
+ # Set background color
+ bgcolor = gtk.gdk.color_parse("#FFFFFF")
+ self.textview.modify_base(gtk.STATE_NORMAL, bgcolor)
+
+ self.textview.set_editable(False)
+
+ self.add(self.textview)
+ self.textview.show()
+
+class Interface:
+
+ def __init__(self):
+ path = None
+ viewer = MultiLogView(path)
+ self.widget = viewer.hbox
+
diff --git a/services/console/interface/memphis/Makefile.am b/services/console/interface/memphis/Makefile.am
new file mode 100644
index 0000000..319dad6
--- /dev/null
+++ b/services/console/interface/memphis/Makefile.am
@@ -0,0 +1,8 @@
+SUBDIRS = plugins
+
+sugardir = $(pkgdatadir)/shell/console/interface/memphis
+sugar_PYTHON = \
+ __init__.py \
+ memphis.py \
+ plugin.py
+
diff --git a/services/console/interface/memphis/__init__.py b/services/console/interface/memphis/__init__.py
new file mode 100644
index 0000000..145d9d4
--- /dev/null
+++ b/services/console/interface/memphis/__init__.py
@@ -0,0 +1 @@
+from memphis import Interface
diff --git a/services/console/interface/memphis/memphis.py b/services/console/interface/memphis/memphis.py
new file mode 100644
index 0000000..8fbc85b
--- /dev/null
+++ b/services/console/interface/memphis/memphis.py
@@ -0,0 +1,238 @@
+#!/usr/bin/env python
+
+# Copyright (C) 2006, Eduardo Silva (edsiper@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
+
+import sys
+import os
+import string
+import wnck
+import plugin
+
+from procmem import proc
+
+try:
+ import gtk
+ import gtk.gdk
+ import gobject
+except:
+ sys.exit(1)
+
+class Interface:
+
+ store_data_types = []
+ store_data_types_details = []
+
+ def __init__(self):
+
+ # Our GtkTree (Treeview)
+ self.treeview = gtk.TreeView()
+ self.treeview.show()
+
+ self.button_start = gtk.Button('Start Memphis')
+ self.button_stop = gtk.Button('Stop Memphis')
+
+ fixed = gtk.Fixed()
+ fixed.add(self.button_start)
+ fixed.add(self.button_stop)
+
+ vbox = gtk.VBox(False)
+ vbox.set_border_width(5)
+ vbox.pack_start(fixed, True, True, 0)
+
+ # Our GtkTree (Treeview)
+ self.treeview = gtk.TreeView()
+ t_width = gtk.gdk.screen_width()
+ t_height = gtk.gdk.screen_height() * 83 / 100
+
+ self.treeview.set_size_request(t_width, t_height)
+ vbox.pack_start(self.treeview, True, True, 0)
+ vbox.show_all()
+ self.widget = vbox
+
+ # Loading plugins
+ self.plg = plugin.Plugin()
+
+ # TOP data types (columns)
+ self.store_data_types = []
+
+ for plg in self.plg.list:
+ plg_data = plg.INTERNALS
+
+ # Give plugin object to plugin
+ plg.INTERNALS['Plg'] = self.plg
+
+ # Creating a store model and loading process data to Treeview
+ # self.store_data_types, ex [int, str, str, str, int,...]
+ #self.store = gtk.TreeStore(*self.store_data_types)
+ self.data = Data(self, self.treeview, self.plg.list)
+
+ self.button_stop.hide()
+ self.button_start.connect('clicked', self.data._start_memphis)
+ self.button_stop.connect('clicked', self.data._stop_memphis)
+
+class Data:
+
+ last_col_index = 0
+
+ store_data_cols = []
+ store_data_types = []
+ store_data_types_details = []
+
+ _running_status = False
+
+ def __init__(self, interface, treeview, plg_list):
+
+ self.interface = interface
+
+ # Top data types
+ self.plg_list = plg_list
+
+ for plg in self.plg_list:
+
+ if plg.INTERNALS['top_data'] != None:
+ last_dt = len(self.store_data_types)
+
+ if last_dt > 0:
+ last_dt -= 1
+
+ len_dt = len(plg.INTERNALS['top_data'])
+
+ self.store_data_types_details.append({"plugin": plg, "init": last_dt, "end": last_dt + len_dt})
+
+ for dt in plg.INTERNALS['top_data']:
+ self.store_data_types.append(dt)
+
+ for col in plg.INTERNALS['top_cols']:
+ self.store_data_cols.append(col)
+
+ # Set global treeview
+ self.treeview = treeview
+
+ # Basic columns
+ index = 0
+ for column_name in self.store_data_cols:
+ self.add_column(column_name, index)
+ index += 1
+
+ self.store = gtk.TreeStore(*self.store_data_types)
+ treeview.set_model(self.store)
+
+ def _start_memphis(self, button):
+
+ # Update information every 1.5 second
+ button.hide()
+ self.interface.button_stop.show()
+ self._running_status = True
+ gobject.timeout_add(1500, self.load_data, self.treeview)
+
+ def _stop_memphis(self, button):
+
+ self._running_status = False
+ button.hide()
+ self.interface.button_start.show()
+
+ # Add a new column to the main treeview
+ def add_column(self, column_name, index):
+ cell = gtk.CellRendererText()
+ col_tv = gtk.TreeViewColumn(column_name, cell, text=index)
+ col_tv.set_resizable(True)
+ col_tv.connect('clicked', self.sort_column_clicked)
+ col_tv.set_property('clickable', True)
+
+ self.treeview.append_column(col_tv)
+
+ # Set the last column index added
+ self.last_col_index = index
+
+ # Sorting
+ def sort_column_clicked(self, TreeViewColumn):
+ cols = self.treeview.get_columns()
+
+ # Searching column index
+ index = 0
+ for col in cols:
+ if col == TreeViewColumn:
+ break
+
+ index += 1
+
+ self.store.set_sort_column_id(index, gtk.SORT_DESCENDING)
+
+ def load_data(self, treeview):
+ self.store.clear()
+
+ # Getting procfs data
+ self.procdata = proc.ProcInfo()
+ self.process_list = []
+
+ pids = []
+ screen = wnck.screen_get_default()
+ windows = screen.get_windows()
+
+ current_pid = os.getpid()
+
+ for win in windows:
+ pid = int(win.get_pid())
+ if current_pid != pid:
+ pids.append(pid)
+
+ self.process_list = set(pids)
+
+ # Sort rows using pid
+ #self.process_list.sort(key=operator.itemgetter('pid'))
+ self.process_iter = []
+
+ for pid in self.process_list:
+ pi = self.build_row(self.store, None, self.procdata, pid)
+ self.process_iter.append(pi)
+
+ treeview.set_rules_hint(True)
+ treeview.expand_all()
+
+ return self._running_status
+
+ def build_row(self, store, parent_iter, proc_data, pid):
+ data = []
+
+ pinfo = proc_data.MemoryInfo(pid)
+
+ # Look for plugins that need to update the top data treeview
+ for plg in self.plg_list:
+ plg_data = []
+
+ if plg.INTERNALS['top_data'] != None:
+ # data = [xxx, yyy,zzz,...]
+ plg_data = plg.info.plg_on_top_data_refresh(plg, pinfo)
+
+ for field in plg_data:
+ data.append(field)
+
+ pi = self.insert_row(store, parent_iter, data)
+
+ return pi
+
+ # Insert a Row in our TreeView
+ def insert_row(self, store, parent, row_data):
+ iter = store.insert_after(parent, None)
+
+ index = 0
+
+ for data in row_data:
+ store.set_value(iter, index , data)
+ index += 1
+
+ return iter
diff --git a/services/console/interface/memphis/plugin.py b/services/console/interface/memphis/plugin.py
new file mode 100644
index 0000000..5ee8eb7
--- /dev/null
+++ b/services/console/interface/memphis/plugin.py
@@ -0,0 +1,48 @@
+###############################################
+# Memphis Plugin Support
+###############################################
+
+import sys, os
+from procmem import proc, proc_smaps, analysis
+
+class Plugin:
+
+ # Plugin list
+ list = []
+ proc = proc.ProcInfo()
+
+ internal_plugin = "memphis_init"
+ plg_path = os.path.dirname(os.path.abspath(__file__)) + "/plugins"
+
+ # Frequency timer, managed by main program
+ freq_timer = 0
+
+ def __init__(self):
+
+ sys.path.insert(0, self.plg_path)
+
+ # Including memphis plugin
+ self.list.append(__import__(self.internal_plugin))
+
+ if os.path.isdir(self.plg_path):
+ # around dir entries
+ for plg in os.listdir(self.plg_path):
+
+ if plg == self.internal_plugin:
+ continue
+
+ if os.path.isdir(self.plg_path + "/" + plg):
+ p = __import__(plg)
+ self.list.append(__import__(plg))
+
+ # Parse /proc/PID/smaps information
+ def proc_get_smaps(self, pid):
+ return proc_smaps.ProcSmaps(pid)
+
+ # Parse /proc/PID/maps information
+ def proc_get_maps(self, pid):
+ return proc_smaps.ProcMaps(pid)
+
+ def proc_analysis(self, pid):
+ return analysis.Analysis(pid)
+
diff --git a/services/console/interface/memphis/plugins/Makefile.am b/services/console/interface/memphis/plugins/Makefile.am
new file mode 100644
index 0000000..2c6b1dd
--- /dev/null
+++ b/services/console/interface/memphis/plugins/Makefile.am
@@ -0,0 +1,4 @@
+SUBDIRS = clean_size cpu dirty_size memphis_init
+
+sugardir = $(pkgdatadir)/shell/console/interface/memphis/plugins
+sugar_PYTHON =
diff --git a/services/console/interface/memphis/plugins/clean_size/Makefile.am b/services/console/interface/memphis/plugins/clean_size/Makefile.am
new file mode 100644
index 0000000..33565f5
--- /dev/null
+++ b/services/console/interface/memphis/plugins/clean_size/Makefile.am
@@ -0,0 +1,6 @@
+
+sugardir = $(pkgdatadir)/shell/console/interface/memphis/plugins/clean_size
+sugar_PYTHON = \
+ README \
+ __init__.py \
+ info.py
diff --git a/services/console/interface/memphis/plugins/clean_size/README b/services/console/interface/memphis/plugins/clean_size/README
new file mode 100644
index 0000000..3dd3ae3
--- /dev/null
+++ b/services/console/interface/memphis/plugins/clean_size/README
@@ -0,0 +1,2 @@
+This plugin give support to get the clean size memory usage
+by process using the /proc/PID/maps file.
diff --git a/services/console/interface/memphis/plugins/clean_size/__init__.py b/services/console/interface/memphis/plugins/clean_size/__init__.py
new file mode 100644
index 0000000..75ce1d1
--- /dev/null
+++ b/services/console/interface/memphis/plugins/clean_size/__init__.py
@@ -0,0 +1,16 @@
+
+import info
+
+INTERNALS = {
+ # Basic information
+ 'PLGNAME': "Clean Size",
+ 'TABNAME': None,
+ 'AUTHOR': "Eduardo Silva",
+ 'DESC': "Print the approx real memory usage",
+
+ # Plugin API
+ 'Plg': None, # Plugin object
+
+ 'top_data': [int], # Top data types needed by memphis core plugin
+ 'top_cols': ["Approx Real Usage (kb)"]
+ }
diff --git a/services/console/interface/memphis/plugins/clean_size/info.py b/services/console/interface/memphis/plugins/clean_size/info.py
new file mode 100644
index 0000000..25ed044
--- /dev/null
+++ b/services/console/interface/memphis/plugins/clean_size/info.py
@@ -0,0 +1,15 @@
+###########################################################
+# Main function:
+# -----------------
+# self: self plugin object
+# mself: memphis object / principal class
+# pinfo: row with information about current tracing process
+############################################################
+
+def plg_on_top_data_refresh(self, pinfo):
+
+ # Get clean size
+ maps = self.INTERNALS['Plg'].proc_get_maps(pinfo['pid'])
+
+ size = (maps.clean_size/1024)
+ return [size]
diff --git a/services/console/interface/memphis/plugins/cpu/Makefile.am b/services/console/interface/memphis/plugins/cpu/Makefile.am
new file mode 100644
index 0000000..58e9eab
--- /dev/null
+++ b/services/console/interface/memphis/plugins/cpu/Makefile.am
@@ -0,0 +1,6 @@
+
+sugardir = $(pkgdatadir)/shell/console/interface/memphis/plugins/cpu
+sugar_PYTHON = \
+ README \
+ __init__.py \
+ info.py
diff --git a/services/console/interface/memphis/plugins/cpu/README b/services/console/interface/memphis/plugins/cpu/README
new file mode 100644
index 0000000..9c7d6f3
--- /dev/null
+++ b/services/console/interface/memphis/plugins/cpu/README
@@ -0,0 +1,2 @@
+This plugin give support to draw the Virtual Memory Size
+usage by the current tracing process.
diff --git a/services/console/interface/memphis/plugins/cpu/__init__.py b/services/console/interface/memphis/plugins/cpu/__init__.py
new file mode 100644
index 0000000..e22a413
--- /dev/null
+++ b/services/console/interface/memphis/plugins/cpu/__init__.py
@@ -0,0 +1,23 @@
+import os
+import info
+
+INTERNALS = {
+ 'PLGNAME': "cpu",
+ 'TABNAME': None,
+ 'AUTHOR': "Eduardo Silva",
+ 'DESC': "Print CPU usage",
+
+ # Plugin API
+ 'Plg': None, # Plugin object
+ 'current_plg': None, # Current plugin object
+ 'current_page': None, # Current page number
+
+ # Top process view requirements
+ 'top_data': [int], # Top data types needed by memphis core plugin
+ 'top_cols': ["%CPU "] # Column names
+ }
+
+# Get CPU frequency
+cpu_hz = os.sysconf(2)
+
+pids_ujiffies = {}
diff --git a/services/console/interface/memphis/plugins/cpu/info.py b/services/console/interface/memphis/plugins/cpu/info.py
new file mode 100644
index 0000000..9cb1ad4
--- /dev/null
+++ b/services/console/interface/memphis/plugins/cpu/info.py
@@ -0,0 +1,48 @@
+###########################################################
+# Main function:
+# -----------------
+# self: self plugin object
+# mself: memphis object / principal class
+# pinfo: row with information about current tracing process
+############################################################
+
+def plg_on_top_data_refresh(self, pinfo):
+ PI = self.INTERNALS['Plg'].proc
+
+ pid = pinfo['pid']
+
+ # Get JIFFIES CPU usage
+ used_jiffies = pinfo['utime'] + pinfo['stime']
+ last_ujiffies = get_pid_ujiffies(self, pid)
+
+ cpu_usage = PI.get_CPU_usage(self.cpu_hz, used_jiffies, pinfo['start_time'])
+
+ # Get PERCENT CPU usage
+ if last_ujiffies == 0.0:
+ pcpu = 0.0
+ set_pid_ujiffies(self, pid, cpu_usage['used_jiffies'])
+ data = [int(pcpu)]
+ return data
+
+ used_jiffies = cpu_usage['used_jiffies'] - last_ujiffies
+
+ # Available jiffies are
+ avail_jiffies = (500/1000.0)*self.cpu_hz # 500 = 0.5 second
+ pcpu = ((used_jiffies*100)/avail_jiffies)
+
+ set_pid_ujiffies(self, pid, cpu_usage['used_jiffies'])
+
+ data = [int(pcpu)]
+ return data
+
+def get_pid_ujiffies(self, pid):
+
+ if pid in self.pids_ujiffies:
+ return self.pids_ujiffies[pid]
+ else:
+ set_pid_ujiffies(self, pid, 0)
+ return self.pids_ujiffies[pid]
+
+def set_pid_ujiffies(self, pid, ujiffies):
+ self.pids_ujiffies[pid] = ujiffies
+
diff --git a/services/console/interface/memphis/plugins/dirty_size/Makefile.am b/services/console/interface/memphis/plugins/dirty_size/Makefile.am
new file mode 100644
index 0000000..47c5298
--- /dev/null
+++ b/services/console/interface/memphis/plugins/dirty_size/Makefile.am
@@ -0,0 +1,6 @@
+
+sugardir = $(pkgdatadir)/shell/console/interface/memphis/plugins/dirty_size
+sugar_PYTHON = \
+ README \
+ __init__.py \
+ info.py
diff --git a/services/console/interface/memphis/plugins/dirty_size/README b/services/console/interface/memphis/plugins/dirty_size/README
new file mode 100644
index 0000000..ee4d1a5
--- /dev/null
+++ b/services/console/interface/memphis/plugins/dirty_size/README
@@ -0,0 +1,2 @@
+This plugin give support to get the public and shared dirty memory usage
+by process using the /proc/PID/smaps file.
diff --git a/services/console/interface/memphis/plugins/dirty_size/__init__.py b/services/console/interface/memphis/plugins/dirty_size/__init__.py
new file mode 100644
index 0000000..f8e9e0a
--- /dev/null
+++ b/services/console/interface/memphis/plugins/dirty_size/__init__.py
@@ -0,0 +1,17 @@
+
+import info
+
+
+INTERNALS = {
+ # Basic information
+ 'PLGNAME': "Dirty Size",
+ 'TABNAME': None, # No tabbed plugin
+ 'AUTHOR': "Eduardo Silva",
+ 'DESC': "Get dirty size memory usage",
+
+ # Plugin API
+ 'Plg': None, # Plugin object
+
+ 'top_data': [int], # Top data types needed by memphis core plugin
+ 'top_cols': ["PDRSS (kb)"]
+ }
diff --git a/services/console/interface/memphis/plugins/dirty_size/info.py b/services/console/interface/memphis/plugins/dirty_size/info.py
new file mode 100644
index 0000000..54a2e7e
--- /dev/null
+++ b/services/console/interface/memphis/plugins/dirty_size/info.py
@@ -0,0 +1,20 @@
+###########################################################
+# Main function:
+# -----------------
+# self: self plugin object
+# mself: memphis object / principal class
+# pinfo: row with information about current tracing process
+############################################################
+
+
+def plg_on_top_data_refresh(self, ppinfo):
+
+ dirty_sizes = get_dirty(self, ppinfo['pid'])
+
+ # memhis need an array
+ return [dirty_sizes['private']]
+
+def get_dirty(pself, pid):
+ ProcAnalysis = pself.INTERNALS['Plg'].proc_analysis(pid)
+
+ return ProcAnalysis.DirtyRSS()
diff --git a/services/console/interface/memphis/plugins/memphis_init/Makefile.am b/services/console/interface/memphis/plugins/memphis_init/Makefile.am
new file mode 100644
index 0000000..53b398a
--- /dev/null
+++ b/services/console/interface/memphis/plugins/memphis_init/Makefile.am
@@ -0,0 +1,6 @@
+
+sugardir = $(pkgdatadir)/shell/console/interface/memphis/plugins/memphis_init
+sugar_PYTHON = \
+ README \
+ __init__.py \
+ info.py
diff --git a/services/console/interface/memphis/plugins/memphis_init/README b/services/console/interface/memphis/plugins/memphis_init/README
new file mode 100644
index 0000000..9c7d6f3
--- /dev/null
+++ b/services/console/interface/memphis/plugins/memphis_init/README
@@ -0,0 +1,2 @@
+This plugin give support to draw the Virtual Memory Size
+usage by the current tracing process.
diff --git a/services/console/interface/memphis/plugins/memphis_init/__init__.py b/services/console/interface/memphis/plugins/memphis_init/__init__.py
new file mode 100644
index 0000000..f5ada7e
--- /dev/null
+++ b/services/console/interface/memphis/plugins/memphis_init/__init__.py
@@ -0,0 +1,15 @@
+import info
+
+INTERNALS = {
+ 'PLGNAME': "memphis",
+ 'TABNAME': None,
+ 'AUTHOR': "Eduardo Silva",
+ 'DESC': "Print basic process information",
+
+ # Plugin API
+ 'Plg': None, # Plugin object
+
+ # Top process view requirements
+ 'top_data': [int, str, str], # Top data types needed by memphis core plugin
+ 'top_cols': ["PID", "Process Name", "Status"] # Column names
+ }
diff --git a/services/console/interface/memphis/plugins/memphis_init/info.py b/services/console/interface/memphis/plugins/memphis_init/info.py
new file mode 100644
index 0000000..6e524c7
--- /dev/null
+++ b/services/console/interface/memphis/plugins/memphis_init/info.py
@@ -0,0 +1,13 @@
+###########################################################
+# Main function:
+# -----------------
+# self: self plugin object
+# mself: memphis object / principal class
+# pinfo: row with information about current tracing process
+############################################################
+
+def plg_on_top_data_refresh(self, ppinfo):
+
+ data = [ppinfo['pid'], ppinfo['name'], ppinfo['state_name']]
+
+ return data
diff --git a/services/console/interface/terminal/Makefile.am b/services/console/interface/terminal/Makefile.am
new file mode 100644
index 0000000..8df4650
--- /dev/null
+++ b/services/console/interface/terminal/Makefile.am
@@ -0,0 +1,5 @@
+sugardir = $(pkgdatadir)/shell/console/interface/terminal
+sugar_PYTHON = \
+ __init__.py \
+ terminal.py
+
diff --git a/services/console/interface/terminal/__init__.py b/services/console/interface/terminal/__init__.py
new file mode 100644
index 0000000..eb78b86
--- /dev/null
+++ b/services/console/interface/terminal/__init__.py
@@ -0,0 +1 @@
+from terminal import Interface \ No newline at end of file
diff --git a/services/console/interface/terminal/terminal.py b/services/console/interface/terminal/terminal.py
new file mode 100644
index 0000000..3621fb2
--- /dev/null
+++ b/services/console/interface/terminal/terminal.py
@@ -0,0 +1,247 @@
+#!/usr/bin/python
+
+# Copyright (C) 2006, Red Hat, Inc.
+#
+# 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
+
+
+# Modified by Eduardo Silva, edsiper@gmail.com
+
+import ConfigParser
+import os.path
+
+import gtk
+import vte
+import pango
+
+import sugar.env
+
+class Terminal(gtk.HBox):
+ def __init__(self):
+ gtk.HBox.__init__(self, False, 4)
+
+ self._vte = vte.Terminal()
+ self._configure_vte()
+ self._vte.set_size(30, 5)
+ self._vte.set_size_request(200, 450)
+ self._vte.show()
+ self.pack_start(self._vte)
+
+ self._scrollbar = gtk.VScrollbar(self._vte.get_adjustment())
+ self._scrollbar.show()
+ self.pack_start(self._scrollbar, False, False, 0)
+
+ self._vte.connect("child-exited", lambda term: term.fork_command())
+
+ self._vte.fork_command()
+
+ def _configure_vte(self):
+ conf = ConfigParser.ConfigParser()
+
+ conf_file = os.path.join(sugar.env.get_profile_path(), 'terminalrc')
+
+ if os.path.isfile(conf_file):
+ f = open(conf_file, 'r')
+ conf.readfp(f)
+ f.close()
+ else:
+ conf.add_section('terminal')
+
+ if conf.has_option('terminal', 'font'):
+ font = conf.get('terminal', 'font')
+ else:
+ font = 'Monospace 8'
+ conf.set('terminal', 'font', font)
+ self._vte.set_font(pango.FontDescription(font))
+
+ if conf.has_option('terminal', 'fg_color'):
+ fg_color = conf.get('terminal', 'fg_color')
+ else:
+ fg_color = '#000000'
+ conf.set('terminal', 'fg_color', fg_color)
+ if conf.has_option('terminal', 'bg_color'):
+ bg_color = conf.get('terminal', 'bg_color')
+ else:
+ bg_color = '#FFFFFF'
+ conf.set('terminal', 'bg_color', bg_color)
+ self._vte.set_colors(gtk.gdk.color_parse (fg_color),
+ gtk.gdk.color_parse (bg_color),
+ [])
+
+ if conf.has_option('terminal', 'cursor_blink'):
+ blink = conf.getboolean('terminal', 'cursor_blink')
+ else:
+ blink = False
+ conf.set('terminal', 'cursor_blink', blink)
+
+ self._vte.set_cursor_blinks(blink)
+
+ if conf.has_option('terminal', 'bell'):
+ bell = conf.getboolean('terminal', 'bell')
+ else:
+ bell = False
+ conf.set('terminal', 'bell', bell)
+ self._vte.set_audible_bell(bell)
+
+ if conf.has_option('terminal', 'scrollback_lines'):
+ scrollback_lines = conf.getint('terminal', 'scrollback_lines')
+ else:
+ scrollback_lines = 1000
+ conf.set('terminal', 'scrollback_lines', scrollback_lines)
+
+ self._vte.set_scrollback_lines(scrollback_lines)
+
+ self._vte.set_allow_bold(True)
+
+ if conf.has_option('terminal', 'scroll_on_keystroke'):
+ scroll_key = conf.getboolean('terminal', 'scroll_on_keystroke')
+ else:
+ scroll_key = False
+ conf.set('terminal', 'scroll_on_keystroke', scroll_key)
+ self._vte.set_scroll_on_keystroke(scroll_key)
+
+ if conf.has_option('terminal', 'scroll_on_output'):
+ scroll_output = conf.getboolean('terminal', 'scroll_on_output')
+ else:
+ scroll_output = False
+ conf.set('terminal', 'scroll_on_output', scroll_output)
+ self._vte.set_scroll_on_output(scroll_output)
+
+ if conf.has_option('terminal', 'emulation'):
+ emulation = conf.get('terminal', 'emulation')
+ else:
+ emulation = 'xterm'
+ conf.set('terminal', 'emulation', emulation)
+ self._vte.set_emulation(emulation)
+
+ if conf.has_option('terminal', 'visible_bell'):
+ visible_bell = conf.getboolean('terminal', 'visible_bell')
+ else:
+ visible_bell = False
+ conf.set('terminal', 'visible_bell', visible_bell)
+ self._vte.set_visible_bell(visible_bell)
+
+ conf.write(open(conf_file, 'w'))
+
+ def on_gconf_notification(self, client, cnxn_id, entry, what):
+ self.reconfigure_vte()
+
+ def on_vte_button_press(self, term, event):
+ if event.button == 3:
+ self.do_popup(event)
+ return True
+
+ def on_vte_popup_menu(self, term):
+ pass
+
+class Multiple:
+
+ page_number = 0
+
+ def __init__(self):
+ self.notebook = gtk.Notebook()
+ t_width = gtk.gdk.screen_width()
+ t_height = gtk.gdk.screen_height() * 83 / 100
+ self.notebook.set_size_request(t_width, t_height)
+
+ self.add_new_terminal()
+
+ open_terminal = gtk.Button('Open a new terminal')
+ open_terminal.connect("clicked", self.add_new_terminal)
+ open_terminal.show()
+
+ self.notebook.show()
+
+ self.main_vbox = gtk.VBox(False, 3)
+ self.main_vbox.pack_start(open_terminal, True, True, 2)
+ self.main_vbox.pack_start(self.notebook, True, True, 2)
+
+ self.main_vbox.show_all()
+
+ # Remove a page from the notebook
+ def close_terminal(self, button, child):
+ page = self.notebook.page_num(child)
+
+ if page != -1:
+ self.notebook.remove_page(page)
+
+
+ pages = self.notebook.get_n_pages()
+ if pages <= 0:
+ self.page_number = 0
+ self.add_new_terminal()
+
+ # Need to refresh the widget --
+ # This forces the widget to redraw itself.
+ self.notebook.queue_draw_area(0, 0, -1, -1)
+
+ def add_icon_to_button(self, button):
+ iconBox = gtk.HBox(False, 0)
+ image = gtk.Image()
+ image.set_from_stock(gtk.STOCK_CLOSE, gtk.ICON_SIZE_MENU)
+ gtk.Button.set_relief(button, gtk.RELIEF_NONE)
+
+ settings = gtk.Widget.get_settings (button)
+ (w,h) = gtk.icon_size_lookup_for_settings (settings, gtk.ICON_SIZE_MENU)
+ gtk.Widget.set_size_request (button, w + 4, h + 4)
+ image.show()
+ iconBox.pack_start(image, True, False, 0)
+ button.add(iconBox)
+ iconBox.show()
+
+ def add_new_terminal(self, *arguments, **keywords):
+ self.page_number += 1
+
+ terminal = Terminal()
+ terminal.show()
+
+ eventBox = self.create_custom_tab("Term %d" % self.page_number, terminal)
+ self.notebook.append_page(terminal, eventBox)
+
+ # Set the new page
+ pages = gtk.Notebook.get_n_pages(self.notebook)
+ self.notebook.set_current_page(pages - 1)
+ return True
+
+ def create_custom_tab(self, text, child):
+ eventBox = gtk.EventBox()
+ tabBox = gtk.HBox(False, 2)
+ tabLabel = gtk.Label(text)
+
+ tabButton = gtk.Button()
+ tabButton.connect('clicked', self.close_terminal, child)
+
+ # Add a picture on a button
+ self.add_icon_to_button(tabButton)
+ iconBox = gtk.HBox(False, 0)
+
+ eventBox.show()
+ tabButton.show()
+ tabLabel.show()
+
+ tabBox.pack_start(tabLabel, False)
+ tabBox.pack_start(tabButton, False)
+
+ tabBox.show_all()
+ eventBox.add(tabBox)
+
+ return eventBox
+
+class Interface:
+
+ def __init__(self):
+ multiple = Multiple()
+ self.widget = multiple.main_vbox
+
diff --git a/services/console/interface/xo/Makefile.am b/services/console/interface/xo/Makefile.am
new file mode 100644
index 0000000..b2035dd
--- /dev/null
+++ b/services/console/interface/xo/Makefile.am
@@ -0,0 +1,6 @@
+sugardir = $(pkgdatadir)/shell/console/interface/xo
+sugar_PYTHON = \
+ __init__.py \
+ drwarea.py \
+ xo.py
+
diff --git a/services/console/interface/xo/__init__.py b/services/console/interface/xo/__init__.py
new file mode 100644
index 0000000..6610a0d
--- /dev/null
+++ b/services/console/interface/xo/__init__.py
@@ -0,0 +1 @@
+from xo import Interface
diff --git a/services/console/interface/xo/drwarea.py b/services/console/interface/xo/drwarea.py
new file mode 100644
index 0000000..b0e598a
--- /dev/null
+++ b/services/console/interface/xo/drwarea.py
@@ -0,0 +1,77 @@
+#!/usr/bin/env python
+
+# Copyright (C) 2007, Eduardo Silva (edsiper@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
+
+#############################################
+# Drawing area tools
+#############################################
+
+import gtk
+import gtk.gdk
+
+class Drawing_Area_Tools:
+
+ height = 0
+ width = 0
+
+ margin = 5 # Left and bottom margin
+
+ range_x = []
+ range_y = []
+
+ def __init__(self, drwarea):
+ drwarea_size = drwarea.get_size_request()
+
+ self.width = drwarea_size[0]
+ self.height = drwarea_size[1]
+
+ # print "width %i" % self.width
+ # print "height %i" % self.height
+
+ self.range_x = {'from': self.margin+2, 'to': self.width - (self.margin+2)}
+ self.range_y = {'from': self.margin+2, 'to': self.height - (self.margin+2)}
+
+ def draw_line(self, context, from_x, from_y, to_x, to_y):
+ context.move_to(from_x, from_y)
+ context.line_to(to_x, to_y)
+
+ def draw_border_lines(self, context):
+ context.set_source_rgb(1, 1, 1)
+ self.draw_line(context, self.margin, self.margin, self.margin, self.height - self.margin)
+ self.draw_line(context, self.margin, self.height - self.margin - 1, self.width - self.margin, self.height - self.margin - 1)
+ context.stroke()
+
+ # Draw a grid
+ def draw_grid(self, context, init_x, init_y, end_x, end_y):
+
+ x_range = (end_x - init_x) + 5
+ y_range = (end_y - init_y) + 1
+
+ current_y = init_y
+ context.set_line_width(0.3)
+
+ for y in range(y_range):
+ if (y%20) == 0:
+ context.move_to(init_x, y)
+ context.line_to(end_x, y)
+
+ for x in range(x_range):
+ if (x%20) == 0:
+ context.move_to(x, init_y)
+ context.line_to(x, end_y)
+
+ context.stroke()
diff --git a/services/console/interface/xo/xo.py b/services/console/interface/xo/xo.py
new file mode 100644
index 0000000..3a3d668
--- /dev/null
+++ b/services/console/interface/xo/xo.py
@@ -0,0 +1,199 @@
+#!/usr/bin/env python
+
+# Copyright (C) 2007, Eduardo Silva (edsiper@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
+
+import os
+import gtk, gobject
+import gtk.gdk
+import cairo
+import string
+import drwarea
+
+
+class CPU_Usage:
+
+ CPU_HZ = 0
+ last_jiffies = 0
+ times = 0
+
+ def __init__(self):
+ self.CPU_hz = os.sysconf(2)
+
+ def _get_CPU_data(self):
+ # Uptime info
+ stat_file = "/proc/stat"
+
+ try:
+ infile = file(stat_file, "r")
+ except:
+ print "Error trying uptime file"
+ return -1
+
+ stat_line = infile.readline()
+ cpu_info = string.split(stat_line, ' ')
+ infile.close()
+
+ return cpu_info
+
+ def _get_CPU_usage(self):
+
+ cpu_info = self._get_CPU_data()
+
+ used_jiffies = (int(cpu_info[2]) + int(cpu_info[3]) + int(cpu_info[4]))
+
+ if self.times ==0:
+ self.last_jiffies = used_jiffies
+ self.times +=1
+ return True
+
+ new_ujiffies = (used_jiffies - self.last_jiffies)
+ new_ajiffies = ((self.frequency/1000) * self.CPU_hz)
+
+ if new_ajiffies <= 0:
+ pcpu = 0.0
+ else:
+ pcpu = ((new_ujiffies*100)/new_ajiffies)
+
+ if pcpu >100:
+ pcpu = 100
+
+ self.times +=1
+ self.last_jiffies = used_jiffies
+
+ return pcpu
+
+class Interface:
+
+ context = None
+ frequency_timer = 1
+ graph_offset = 7
+
+ def __init__(self):
+
+ self.drw_width = gtk.gdk.screen_width() * 90 / 100
+ self.drw_height = gtk.gdk.screen_height() * 20 / 100
+ self.y_cpu = self.drw_height - self.graph_offset
+ self.drw_buffer = []
+
+ drawingarea = gtk.DrawingArea()
+ drawingarea.set_size_request(self.drw_width, self.drw_height)
+ drawingarea.connect("expose-event", self.do_expose)
+
+ self.dat = drwarea.Drawing_Area_Tools(drawingarea)
+
+ fixed = gtk.Fixed();
+ fixed.set_border_width(10)
+ fixed.add(drawingarea)
+
+ self.frame = gtk.Frame('System CPU Usage: 0%')
+ self.frame.set_border_width(10)
+ self.frame.add(fixed)
+
+ self.widget = self.hbox = gtk.HBox(False, 3)
+ self.hbox.pack_start(self.frame, True, True, 0)
+ self.hbox.show_all()
+
+ DRW_CPU = CPU_Usage()
+ DRW_CPU.frequency = 1000 # 1 Second
+
+ gobject.timeout_add(DRW_CPU.frequency, self._draw_cpu_usage, DRW_CPU, drawingarea)
+
+ def _draw_cpu_usage(self, DRW_CPU, drwarea):
+ # End of the graph ?
+ if ((self.frequency_timer + 1)*self.graph_offset) >= (self.drw_width - self.graph_offset):
+ self.frequency_timer = 1
+ self.drw_buffer = []
+ self.do_expose(drwarea, None)
+
+ context = drwarea.window.cairo_create()
+
+ from_x = self.frequency_timer * self.graph_offset
+ from_y = self.y_cpu
+
+ self.frequency_timer += 1
+
+ pcpu = DRW_CPU._get_CPU_usage()
+
+ self.drw_buffer.append(pcpu)
+
+ to_x = self.frequency_timer * self.graph_offset
+ self.y_cpu = to_y = self._get_y_cpu(pcpu)
+
+ # Context properties
+ context.set_line_width(2)
+ context.set_source_rgb(0,1,0)
+
+ cpu_label = str(round(pcpu, 4))
+ self.frame.set_label('System CPU Usage: ' + cpu_label + ' %')
+
+ self.dat.draw_line(context, from_x, from_y, to_x, to_y)
+ context.stroke()
+
+ return True
+
+ def _get_y_cpu(self, pcpu):
+
+ height = (self.dat.range_y['to']) - (self.dat.range_y['from'])
+
+ # Get percent of cpu usage
+ y_value = (height - ((pcpu*height)/100) + 4)
+
+ return int(y_value)
+
+ def do_expose(self, widget, event):
+
+ self.context = widget.window.cairo_create()
+ self.context.rectangle(0, 0, self.dat.width - 1, self.dat.height - 1)
+
+ self.context.set_source_rgb (0,0,0)
+ self.context.fill_preserve()
+
+ # Drawing horizontal and vertical border lines
+ self.dat.draw_border_lines(self.context)
+
+ # Drawing grid
+ line_margin = self.dat.margin
+ self.context.set_source_rgb(1, 1, 1)
+ self.context.set_line_width(1)
+ self.dat.draw_grid(self.context, line_margin + 1, line_margin + 1, self.dat.width - line_margin - 2, self.dat.height - line_margin - 2)
+ self.context.stroke()
+
+ self._draw_buffer(widget)
+ return False
+
+ def _draw_buffer(self, drwarea):
+ freq = 1 # Frequency timer
+ last_y = self.drw_height - self.graph_offset
+
+ context = drwarea.window.cairo_create()
+ for pcpu in self.drw_buffer:
+
+ from_x = freq * self.graph_offset
+ from_y = last_y
+
+ freq+=1
+
+ to_x = freq * self.graph_offset
+ last_y = to_y = self._get_y_cpu(pcpu)
+
+ # Context properties
+ context.set_line_width(2)
+ context.set_source_rgb(0,1,0)
+
+ self.dat.draw_line(context, from_x, from_y, to_x, to_y)
+ context.stroke()
+
diff --git a/services/console/lib/Makefile.am b/services/console/lib/Makefile.am
new file mode 100644
index 0000000..16782d7
--- /dev/null
+++ b/services/console/lib/Makefile.am
@@ -0,0 +1,4 @@
+SUBDIRS = procmem
+
+sugardir = $(pkgdatadir)/shell/console/lib
+sugar_PYTHON =
diff --git a/services/console/lib/procmem/Makefile.am b/services/console/lib/procmem/Makefile.am
new file mode 100644
index 0000000..257c13f
--- /dev/null
+++ b/services/console/lib/procmem/Makefile.am
@@ -0,0 +1,8 @@
+
+sugardir = $(pkgdatadir)/shell/console/lib/procmem
+
+sugar_PYTHON = \
+ __init__.py \
+ proc.py \
+ proc_smaps.py \
+ analysis.py
diff --git a/services/console/lib/procmem/__init__.py b/services/console/lib/procmem/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/services/console/lib/procmem/__init__.py
diff --git a/services/console/lib/procmem/analysis.py b/services/console/lib/procmem/analysis.py
new file mode 100644
index 0000000..d2a247a
--- /dev/null
+++ b/services/console/lib/procmem/analysis.py
@@ -0,0 +1,30 @@
+import proc, proc_smaps
+
+class Analysis:
+
+ pid = 0
+
+ def __init__(self, pid):
+ self.pid = pid
+
+ def DirtyRSS(self):
+ smaps = proc_smaps.ProcSmaps(self.pid)
+ dirty = []
+
+ private = 0
+ shared = 0
+
+ for map in smaps.mappings:
+ private += map.private_dirty
+ shared += map.shared_dirty
+
+ dirty = {"private": int(private), "shared": int(shared)}
+
+ return dirty
+
+ def ApproxRealMemoryUsage(self):
+ maps = proc_smaps.ProcMaps(self.pid)
+ size = (maps.clean_size/1024)
+
+ return size
+ \ No newline at end of file
diff --git a/services/console/lib/procmem/proc.py b/services/console/lib/procmem/proc.py
new file mode 100644
index 0000000..729aa13
--- /dev/null
+++ b/services/console/lib/procmem/proc.py
@@ -0,0 +1,100 @@
+#!/usr/bin/env python
+
+import sys, os
+import string
+
+class ProcInfo:
+
+ dir_path = "/proc/" # Our cute Proc File System
+ status_file = "status"
+ stat_file = "stat"
+
+ proc_list = [] # Our PID list :D
+ proc_info = [] #
+
+ def __init__(self):
+ self.proc_list = self.Get_PID_List()
+
+ # Returns Process List
+ def Get_PID_List(self):
+ list = []
+
+ # Exists our procfs ?
+ if os.path.isdir(self.dir_path):
+ # around dir entries
+ for f in os.listdir(self.dir_path):
+ if os.path.isdir(self.dir_path+f) & str.isdigit(f):
+ list.append(int(f))
+
+ return list
+
+ def MemoryInfo(self, pid):
+ # Path
+ pidfile = self.dir_path + str(pid) + "/stat"
+ try:
+ infile = open(pidfile, "r")
+ except:
+ print "Error trying " + pidfile
+ return None
+
+ # Parsing data , check 'man 5 proc' for details
+ data = infile.read().split()
+
+ infile.close()
+
+ state_dic = {
+ 'R': 'Running',
+ 'S': 'Sleeping',
+ 'D': 'Disk sleep',
+ 'Z': 'Zombie',
+ 'T': 'Traced/Stopped',
+ 'W': 'Paging'
+ }
+
+ # user and group owners
+ pidstat = os.stat(pidfile)
+
+ info = {
+ 'pid': int(data[0]), # Process ID
+ 'name': data[1].strip('()'), # Process name
+ 'state': data[2], # Process State, ex: R|S|D|Z|T|W
+ 'state_name': state_dic[data[2]], # Process State name, ex: Running, sleeping, Zombie, etc
+ 'ppid': int(data[3]), # Parent process ID
+ 'utime': int(data[13]), # Used jiffies in user mode
+ 'stime': int(data[14]), # Used jiffies in kernel mode
+ 'start_time': int(data[21]), # Process time from system boot (jiffies)
+ 'vsize': int(data[22]), # Virtual memory size used (bytes)
+ 'rss': int(data[23])*4, # Resident Set Size (bytes)
+ 'user_id': pidstat.st_uid, # process owner
+ 'group_id': pidstat.st_gid # owner group
+ }
+
+ return info
+
+
+ # Returns the CPU usage expressed in Jiffies
+ def get_CPU_usage(self, cpu_hz, used_jiffies, start_time):
+
+ # Uptime info
+ uptime_file = self.dir_path + "/uptime"
+ try:
+ infile = file(uptime_file, "r")
+ except:
+ print "Error trying uptime file"
+ return None
+
+ uptime_line = infile.readline()
+ uptime = string.split(uptime_line, " ",2)
+
+ infile.close()
+
+ # System uptime, from /proc/uptime
+ uptime = float(uptime[0])
+
+ # Jiffies
+ avail_jiffies = (uptime * cpu_hz) - start_time
+
+ cpu_usage = {'used_jiffies': used_jiffies, 'avail_jiffies': avail_jiffies}
+
+ return cpu_usage
+
diff --git a/services/console/lib/procmem/proc_smaps.py b/services/console/lib/procmem/proc_smaps.py
new file mode 100644
index 0000000..9416c52
--- /dev/null
+++ b/services/console/lib/procmem/proc_smaps.py
@@ -0,0 +1,129 @@
+####################################################################
+# This class open the /proc/PID/maps and /proc/PID/smaps files
+# to get useful information about the real memory usage
+####################################################################
+#!/usr/bin/env python
+
+import os
+
+# Parse the /proc/PID/smaps file
+class ProcSmaps:
+
+ mappings = [] # Devices information
+
+ def __init__(self, pid):
+
+ smapfile = "/proc/%s/smaps" % pid
+ self.mappings = []
+
+ # Coded by Federico Mena (script)
+ try:
+ infile = open(smapfile, "r")
+ input = infile.read()
+ infile.close()
+ except:
+ print "Error trying " + smapfile
+ return
+
+ lines = input.splitlines()
+
+ num_lines = len (lines)
+ line_idx = 0
+
+ # 08065000-08067000 rw-p 0001c000 03:01 147613 /opt/gnome/bin/evolution-2.6
+ # Size: 8 kB
+ # Rss: 8 kB
+ # Shared_Clean: 0 kB
+ # Shared_Dirty: 0 kB
+ # Private_Clean: 8 kB
+ # Private_Dirty: 0 kB
+
+ while num_lines > 0:
+ fields = lines[line_idx].split (" ", 5)
+ if len (fields) == 6:
+ (offsets, permissions, bin_permissions, device, inode, name) = fields
+ else:
+ (offsets, permissions, bin_permissions, device, inode) = fields
+ name = ""
+
+ size = self.parse_smaps_size_line (lines[line_idx + 1])
+ rss = self.parse_smaps_size_line (lines[line_idx + 2])
+ shared_clean = self.parse_smaps_size_line (lines[line_idx + 3])
+ shared_dirty = self.parse_smaps_size_line (lines[line_idx + 4])
+ private_clean = self.parse_smaps_size_line (lines[line_idx + 5])
+ private_dirty = self.parse_smaps_size_line (lines[line_idx + 6])
+ name = name.strip ()
+
+ mapping = Mapping (size, rss, shared_clean, shared_dirty, private_clean, private_dirty, permissions, name)
+ self.mappings.append (mapping)
+
+ num_lines -= 7
+ line_idx += 7
+
+ # Parses a line of the form "foo: 42 kB" and returns an integer for the "42" field
+ def parse_smaps_size_line (self, line):
+ # Rss: 8 kB
+ fields = line.split ()
+ return int(fields[1])
+
+class Mapping:
+ def __init__ (self, size, rss, shared_clean, shared_dirty, private_clean, private_dirty, permissions, name):
+ self.size = size
+ self.rss = rss
+ self.shared_clean = shared_clean
+ self.shared_dirty = shared_dirty
+ self.private_clean = private_clean
+ self.private_dirty = private_dirty
+ self.permissions = permissions
+ self.name = name
+
+# Parse /proc/PID/maps file to get the clean memory usage by process,
+# we avoid lines with backed-files
+class ProcMaps:
+
+ clean_size = 0
+
+ def __init__(self, pid):
+ mapfile = "/proc/%s/maps" % pid
+
+ try:
+ infile = open(mapfile, "r")
+ except:
+ print "Error trying " + mapfile
+ return None
+
+ sum = 0
+ to_data_do = {
+ "[anon]": self.parse_size_line,
+ "[heap]": self.parse_size_line
+ }
+
+ for line in infile:
+ arr = line.split()
+
+ # Just parse writable mapped areas
+ if arr[1][1] != "w":
+ continue
+
+ if len(arr) == 6:
+ # if we got a backed-file we skip this info
+ if os.path.isfile(arr[5]):
+ continue
+ else:
+ line_size = to_data_do.get(arr[5], self.skip)(line)
+ sum += line_size
+ else:
+ line_size = self.parse_size_line(line)
+ sum += line_size
+
+ infile.close()
+ self.clean_size = sum
+
+ def skip(self, line):
+ return 0
+
+ # Parse a maps line and return the mapped size
+ def parse_size_line(self, line):
+ start, end = line.split()[0].split('-')
+ size = int(end, 16) - int(start, 16)
+ return size
diff --git a/services/console/org.laptop.sugar.Console.service.in b/services/console/org.laptop.sugar.Console.service.in
new file mode 100644
index 0000000..90882fe
--- /dev/null
+++ b/services/console/org.laptop.sugar.Console.service.in
@@ -0,0 +1,4 @@
+[D-BUS Service]
+Name = org.laptop.Console
+Exec = @bindir@/sugar-console
+
diff --git a/services/console/sugar-console b/services/console/sugar-console
new file mode 100755
index 0000000..b971fb4
--- /dev/null
+++ b/services/console/sugar-console
@@ -0,0 +1,11 @@
+#!/usr/bin/env python
+
+import pygtk
+pygtk.require('2.0')
+
+import os, sys
+from sugar import env
+
+sys.path.insert(0, os.path.join(env.get_data_dir(), 'services/console'))
+
+import console