diff options
Diffstat (limited to 'services/console/interface')
33 files changed, 1218 insertions, 0 deletions
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() + |