Rework the console to use autoactivation, move it in services/
This commit is contained in:
+2
-4
@@ -1,11 +1,9 @@
|
||||
SUBDIRS = data model view console
|
||||
SUBDIRS = data model view
|
||||
|
||||
bin_SCRIPTS = \
|
||||
sugar-activity \
|
||||
sugar-activity-factory \
|
||||
sugar-shell \
|
||||
sugar-shutdown \
|
||||
sugar-devel-console
|
||||
sugar-shell
|
||||
|
||||
sugardir = $(pkgdatadir)/shell
|
||||
sugar_PYTHON = \
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
SUBDIRS = interface lib
|
||||
|
||||
sugardir = $(pkgdatadir)/shell/console
|
||||
sugar_PYTHON = \
|
||||
__init__.py \
|
||||
console.py
|
||||
@@ -1 +0,0 @@
|
||||
|
||||
@@ -1,128 +0,0 @@
|
||||
#!/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.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')
|
||||
|
||||
DBUS_BUS = 'org.freedesktop.DBus'
|
||||
DBUS_PATH = '/org/freedesktop/DBus'
|
||||
|
||||
CONSOLE_BUS = 'org.laptop.Sugar.DeveloperConsole'
|
||||
CONSOLE_PATH = '/org/laptop/Sugar/DeveloperConsole'
|
||||
CONSOLE_IFACE = 'org.laptop.Sugar.DeveloperConsole'
|
||||
|
||||
class Console:
|
||||
|
||||
def __init__(self):
|
||||
|
||||
# Main Window
|
||||
self.window = gtk.Window()
|
||||
self.window.set_title('Developer console')
|
||||
self.window.connect("delete-event", self._minimize_main_window)
|
||||
|
||||
self.default_width = gtk.gdk.screen_width() * 95 / 100
|
||||
self.default_height = gtk.gdk.screen_height() * 95 / 100
|
||||
self.default_mini_width = 150
|
||||
self.default_mini_height = 30
|
||||
|
||||
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)
|
||||
|
||||
# Minimize Window
|
||||
self.mini_fixed = gtk.Fixed()
|
||||
|
||||
# Minimize buttons
|
||||
button_restore = gtk.Button('Restore')
|
||||
button_restore.connect("clicked", self._restore_window)
|
||||
|
||||
button_quit = gtk.Button('Quit')
|
||||
button_quit.connect("clicked", gtk.main_quit)
|
||||
|
||||
mini_hbox = gtk.HBox()
|
||||
mini_hbox.pack_start(button_restore, True, True, 0)
|
||||
mini_hbox.pack_start(button_quit, True, True, 0)
|
||||
self.mini_fixed.add(mini_hbox)
|
||||
|
||||
# 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.pack_start(self.mini_fixed, True, True, 0)
|
||||
main_hbox.show()
|
||||
|
||||
self.notebook.show()
|
||||
self.window.add(main_hbox)
|
||||
self.window.show()
|
||||
|
||||
self.mini_fixed.hide()
|
||||
|
||||
def _load_interface(self, interface, label):
|
||||
mod = __import__(interface)
|
||||
widget = mod.Interface().widget
|
||||
widget.show()
|
||||
|
||||
self.notebook.append_page(widget, gtk.Label(label))
|
||||
|
||||
|
||||
def _restore_window(self, button):
|
||||
self.mini_fixed.hide_all()
|
||||
self.window.resize(self.default_mini_width, self.default_mini_height)
|
||||
self.notebook.show_all()
|
||||
|
||||
def _minimize_main_window(self, window, gdkevent):
|
||||
self.notebook.hide_all()
|
||||
window.resize(self.default_mini_width, self.default_mini_height)
|
||||
self.mini_fixed.show_all()
|
||||
return True
|
||||
|
||||
# We're using a DBUS-Service to avoid open devconsole more than one time
|
||||
class Init_Service(dbus.service.Object):
|
||||
|
||||
def __init__(self, bus, object_path=CONSOLE_PATH):
|
||||
dbus.service.Object.__init__(self, bus, object_path)
|
||||
CS = Console()
|
||||
|
||||
bus = dbus.SessionBus()
|
||||
obj = bus.get_object(DBUS_BUS, DBUS_PATH)
|
||||
|
||||
dbus_iface = dbus.Interface(obj, DBUS_BUS)
|
||||
services = dbus_iface.ListNames()
|
||||
|
||||
# A temporal way to check if the service is running
|
||||
if not CONSOLE_BUS in services:
|
||||
name = dbus.service.BusName(CONSOLE_BUS, bus)
|
||||
obj = Init_Service(name)
|
||||
gtk.main()
|
||||
else:
|
||||
sys.exit(1)
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
SUBDIRS = memphis logviewer terminal xo
|
||||
|
||||
sugardir = $(pkgdatadir)/shell/console/interface
|
||||
sugar_PYTHON = \
|
||||
__init__.py
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
sugardir = $(pkgdatadir)/shell/console/interface/logviewer
|
||||
sugar_PYTHON = \
|
||||
__init__.py \
|
||||
logviewer.py
|
||||
@@ -1 +0,0 @@
|
||||
from logviewer import Interface
|
||||
@@ -1,173 +0,0 @@
|
||||
#!/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
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
SUBDIRS = plugins
|
||||
|
||||
sugardir = $(pkgdatadir)/shell/console/interface/memphis
|
||||
sugar_PYTHON = \
|
||||
__init__.py \
|
||||
memphis.py \
|
||||
plugin.py
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
from memphis import Interface
|
||||
@@ -1,238 +0,0 @@
|
||||
#!/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
|
||||
@@ -1,48 +0,0 @@
|
||||
###############################################
|
||||
# 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)
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
SUBDIRS = clean_size cpu dirty_size memphis_init
|
||||
|
||||
sugardir = $(pkgdatadir)/shell/console/interface/memphis/plugins
|
||||
sugar_PYTHON =
|
||||
@@ -1,6 +0,0 @@
|
||||
|
||||
sugardir = $(pkgdatadir)/shell/console/interface/memphis/plugins/clean_size
|
||||
sugar_PYTHON = \
|
||||
README \
|
||||
__init__.py \
|
||||
info.py
|
||||
@@ -1,2 +0,0 @@
|
||||
This plugin give support to get the clean size memory usage
|
||||
by process using the /proc/PID/maps file.
|
||||
@@ -1,16 +0,0 @@
|
||||
|
||||
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)"]
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
###########################################################
|
||||
# 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]
|
||||
@@ -1,6 +0,0 @@
|
||||
|
||||
sugardir = $(pkgdatadir)/shell/console/interface/memphis/plugins/cpu
|
||||
sugar_PYTHON = \
|
||||
README \
|
||||
__init__.py \
|
||||
info.py
|
||||
@@ -1,2 +0,0 @@
|
||||
This plugin give support to draw the Virtual Memory Size
|
||||
usage by the current tracing process.
|
||||
@@ -1,23 +0,0 @@
|
||||
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 = {}
|
||||
@@ -1,48 +0,0 @@
|
||||
###########################################################
|
||||
# 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
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
|
||||
sugardir = $(pkgdatadir)/shell/console/interface/memphis/plugins/dirty_size
|
||||
sugar_PYTHON = \
|
||||
README \
|
||||
__init__.py \
|
||||
info.py
|
||||
@@ -1,2 +0,0 @@
|
||||
This plugin give support to get the public and shared dirty memory usage
|
||||
by process using the /proc/PID/smaps file.
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
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)"]
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
###########################################################
|
||||
# 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()
|
||||
@@ -1,6 +0,0 @@
|
||||
|
||||
sugardir = $(pkgdatadir)/shell/console/interface/memphis/plugins/memphis_init
|
||||
sugar_PYTHON = \
|
||||
README \
|
||||
__init__.py \
|
||||
info.py
|
||||
@@ -1,2 +0,0 @@
|
||||
This plugin give support to draw the Virtual Memory Size
|
||||
usage by the current tracing process.
|
||||
@@ -1,15 +0,0 @@
|
||||
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
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
###########################################################
|
||||
# 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
|
||||
@@ -1,5 +0,0 @@
|
||||
sugardir = $(pkgdatadir)/shell/console/interface/terminal
|
||||
sugar_PYTHON = \
|
||||
__init__.py \
|
||||
terminal.py
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
from terminal import Interface
|
||||
@@ -1,247 +0,0 @@
|
||||
#!/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
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
sugardir = $(pkgdatadir)/shell/console/interface/xo
|
||||
sugar_PYTHON = \
|
||||
__init__.py \
|
||||
drwarea.py \
|
||||
xo.py
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
from xo import Interface
|
||||
@@ -1,77 +0,0 @@
|
||||
#!/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()
|
||||
@@ -1,199 +0,0 @@
|
||||
#!/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()
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
SUBDIRS = procmem
|
||||
|
||||
sugardir = $(pkgdatadir)/shell/console/lib
|
||||
sugar_PYTHON =
|
||||
@@ -1,8 +0,0 @@
|
||||
|
||||
sugardir = $(pkgdatadir)/shell/console/lib/procmem
|
||||
|
||||
sugar_PYTHON = \
|
||||
__init__.py \
|
||||
proc.py \
|
||||
proc_smaps.py \
|
||||
analysis.py
|
||||
@@ -1,30 +0,0 @@
|
||||
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
|
||||
|
||||
@@ -1,100 +0,0 @@
|
||||
#!/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
|
||||
|
||||
@@ -1,129 +0,0 @@
|
||||
####################################################################
|
||||
# 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
|
||||
@@ -6,6 +6,4 @@
|
||||
<Alt>p=prev
|
||||
<Alt>c=close
|
||||
|
||||
<Alt><Shift>F12=!sugar-devel-console
|
||||
<Alt>q=!sugar-emulator-shutdown
|
||||
<Alt><Shift>Escape=!sugar-shutdown
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
# Sugar developer console launcher
|
||||
import pygtk
|
||||
pygtk.require('2.0')
|
||||
|
||||
import os, sys
|
||||
from sugar import env
|
||||
|
||||
sys.path.insert(0, os.path.join(env.get_data_dir(), 'shell'))
|
||||
|
||||
import console.console
|
||||
@@ -1,4 +0,0 @@
|
||||
#!/bin/sh
|
||||
dbus-send --system --print-reply --dest=org.freedesktop.Hal \
|
||||
/org/freedesktop/Hal/devices/computer \
|
||||
org.freedesktop.Hal.Device.SystemPowerManagement.Shutdown
|
||||
@@ -94,6 +94,8 @@ class Shell(gobject.GObject):
|
||||
self._key_grabber.grab('F12')
|
||||
self._key_grabber.grab('<alt>F5')
|
||||
self._key_grabber.grab('<alt>F8')
|
||||
self._key_grabber.grab('<alt>=')
|
||||
self._key_grabber.grab('<alt>0')
|
||||
|
||||
self._key_grabber.grab('0xDC') # Camera key
|
||||
self._key_grabber.grab('0xE0') # Overlay key
|
||||
@@ -135,6 +137,8 @@ class Shell(gobject.GObject):
|
||||
self._hw_manager.set_display_mode(HardwareManager.COLOR_MODE)
|
||||
elif key == '<alt>F8':
|
||||
self._hw_manager.set_display_mode(HardwareManager.B_AND_W_MODE)
|
||||
elif key == '<alt>=' or key == '<alt>0':
|
||||
self._show_console()
|
||||
elif key == '<shft><alt>F9':
|
||||
self._frame.notify_key_press()
|
||||
elif key == '<shft><alt>F10':
|
||||
@@ -154,6 +158,13 @@ class Shell(gobject.GObject):
|
||||
box = self._home_window.get_home_box()
|
||||
box.grab_and_rotate()
|
||||
|
||||
def _show_console(self):
|
||||
bus = dbus.SessionBus()
|
||||
proxy = bus.get_object('org.laptop.sugar.Console',
|
||||
'/org/laptop/sugar/Console')
|
||||
mgr = dbus.Interface(proxy, 'org.laptop.sugar.Console')
|
||||
mgr.show()
|
||||
|
||||
def _shutdown(self):
|
||||
bus = dbus.SystemBus()
|
||||
proxy = bus.get_object('org.freedesktop.Hal',
|
||||
|
||||
Reference in New Issue
Block a user