[Xfce4-commits] <xfce4-taskmanager:master> Show list of tasks

Mike Massonnet noreply at xfce.org
Wed May 5 09:08:08 CEST 2010


Updating branch refs/heads/master
         to a02bf695731de0e02b21ff2a977afaf5ac67214c (commit)
       from 71d1684696c49be2d73ebe98bd44177a33f8e9f8 (commit)

commit a02bf695731de0e02b21ff2a977afaf5ac67214c
Author: Mike Massonnet <mmassonnet at xfce.org>
Date:   Wed May 5 08:53:49 2010 +0200

    Show list of tasks
    
    Provide the list of tasks through a GArray and parse it in main.c to
    update the GtkTreeModel.

 src/main.c               |  122 ++++++++++++++++++++++++++++++-
 src/process-tree-view.c  |  115 ++++++++---------------------
 src/process-tree-view.h  |   17 ++++
 src/task-manager-linux.c |  185 ++++++++++++++++++++++++++++++++++++++++++++--
 src/task-manager.c       |   90 +++++++++++++++++++++--
 src/task-manager.h       |   26 ++++---
 6 files changed, 443 insertions(+), 112 deletions(-)

diff --git a/src/main.c b/src/main.c
index 5fac70f..2659c33 100644
--- a/src/main.c
+++ b/src/main.c
@@ -12,21 +12,137 @@
 #include <config.h>
 #endif
 
+#include <glib/gi18n.h>
 #include <gtk/gtk.h>
 
 #include "process-window.h"
+#include "process-tree-view.h"
 #include "task-manager.h"
 
 static GtkWidget *window;
 static XtmTaskManager *task_manager;
+static gboolean timeout = 0;
+
+static void
+update_tree_iter (GtkTreeModel *model, GtkTreeIter *iter, Task *task)
+{
+	gchar vsz[64], rss[64], cpu[16];
+
+	// TODO add precision for values < 1 MB
+	g_snprintf (vsz, 64, _("%lu MB"), task->vsz / 1024 / 1024);
+	g_snprintf (rss, 64, _("%lu MB"), task->rss / 1024 / 1024);
+	// TODO make precision optional
+	g_snprintf (cpu, 16, _("%.2f%%"), task->cpu_user + task->cpu_system);
+
+	gtk_list_store_set (GTK_LIST_STORE (model), iter,
+		XTM_PTV_COLUMN_PPID, task->ppid,
+		XTM_PTV_COLUMN_STATE, task->state,
+		XTM_PTV_COLUMN_VSZ, task->vsz,
+		XTM_PTV_COLUMN_VSZ_STR, vsz,
+		XTM_PTV_COLUMN_RSS, task->rss,
+		XTM_PTV_COLUMN_RSS_STR, rss,
+		XTM_PTV_COLUMN_CPU, task->cpu_user + task->cpu_system,
+		XTM_PTV_COLUMN_CPU_STR, cpu,
+		XTM_PTV_COLUMN_PRIORITY, task->prio,
+		-1);
+}
+
+static void
+add_tree_iter (GtkTreeModel *model, Task *task)
+{
+	GtkTreeIter iter;
+	gtk_list_store_append (GTK_LIST_STORE (model), &iter);
+	gtk_list_store_set (GTK_LIST_STORE (model), &iter,
+		XTM_PTV_COLUMN_COMMAND, task->cmdline,
+		XTM_PTV_COLUMN_PID, task->pid,
+		XTM_PTV_COLUMN_STATE, task->state,
+		XTM_PTV_COLUMN_UID, task->uid_name,
+		-1);
+	update_tree_iter (model, &iter, task);
+}
+
+static void
+update_tree_model (const GArray *task_list)
+{
+	GtkTreeModel *model;
+	GtkTreeIter iter;
+	Task *task;
+	guint i;
+	gboolean valid;
+
+	model = xtm_process_window_get_model (XTM_PROCESS_WINDOW (window));
+
+	// TODO pick a timestamp for started/terminated tasks to keep them momentary (red/green color, italic, ...)
+	/* Remove terminated tasks */
+	valid = gtk_tree_model_get_iter_first (model, &iter);
+	while (valid)
+	{
+		guint pid;
+		gboolean found = FALSE;
+
+		gtk_tree_model_get (model, &iter, XTM_PTV_COLUMN_PID, &pid, -1);
+		for (i = 0; i < task_list->len; i++)
+		{
+			task = &g_array_index (task_list, Task, i);
+			if (pid != task->pid)
+				continue;
+			found = TRUE;
+			break;
+		}
+
+		if (found == FALSE)
+			gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
+
+		valid = gtk_tree_model_iter_next (model, &iter);
+	}
+
+	/* Append started tasks and update existing ones */
+	for (i = 0; i < task_list->len; i++)
+	{
+		guint pid;
+		gboolean found = FALSE;
+
+		task = &g_array_index (task_list, Task, i);
+		valid = gtk_tree_model_get_iter_first (model, &iter);
+		while (valid)
+		{
+			gtk_tree_model_get (model, &iter, XTM_PTV_COLUMN_PID, &pid, -1);
+
+			if (pid == task->pid)
+			{
+				// TODO check if elements have to be updated, updating everything always is a CPU hog
+				update_tree_iter (model, &iter, task);
+				found = TRUE;
+				break;
+			}
+
+			valid = gtk_tree_model_iter_next (model, &iter);
+		}
+
+		if (found == FALSE)
+		{
+			add_tree_iter (model, task);
+		}
+	}
+}
 
 static gboolean
-timeout_cb ()
+init_timeout ()
 {
 	guint num_processes;
 	gfloat cpu, memory, swap;
+	const GArray *task_list;
+
 	xtm_task_manager_get_system_info (task_manager, &num_processes, &cpu, &memory, &swap);
 	xtm_process_window_set_system_info (XTM_PROCESS_WINDOW (window), num_processes, cpu, memory, swap);
+
+	task_list = xtm_task_manager_get_task_list (task_manager);
+	update_tree_model (task_list);
+
+	if (timeout == 0)
+		timeout = g_timeout_add (1000, init_timeout, NULL);
+
+	return TRUE;
 }
 
 int main (int argc, char *argv[])
@@ -45,12 +161,14 @@ int main (int argc, char *argv[])
 	task_manager = xtm_task_manager_new ();
 	g_message ("Running as %s on %s", xtm_task_manager_get_username (task_manager), xtm_task_manager_get_hostname (task_manager));
 
-	g_timeout_add (1000, timeout_cb, NULL);
+	init_timeout ();
 
 	g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
 
 	gtk_main ();
 
+	if (timeout > 0)
+		g_source_remove (timeout);
 	g_object_unref (window);
 
 	return 0;
diff --git a/src/process-tree-view.c b/src/process-tree-view.c
index e649f58..450681b 100644
--- a/src/process-tree-view.c
+++ b/src/process-tree-view.c
@@ -34,20 +34,6 @@ struct _XtmProcessTreeView
 };
 G_DEFINE_TYPE (XtmProcessTreeView, xtm_process_tree_view, GTK_TYPE_TREE_VIEW)
 
-enum
-{
-	COLUMN_COMMAND,
-	COLUMN_PID,
-	COLUMN_PPID,
-	COLUMN_STATE,
-	COLUMN_VSZ,
-	COLUMN_RSS,
-	COLUMN_UID,
-	COLUMN_CPU,
-	COLUMN_PRIORITY,
-	N_COLUMNS,
-};
-
 static gboolean	treeview_clicked				(XtmProcessTreeView *treeview, GdkEventButton *event);
 static void	settings_changed				(GObject *object, GParamSpec *pspec, XtmProcessTreeView *treeview);
 static int	sort_by_string					(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer user_data);
@@ -74,10 +60,10 @@ xtm_process_tree_view_init (XtmProcessTreeView *treeview)
 	g_object_get (treeview->settings, "sort-column-id", &sort_column_id, "sort-type", &sort_type, NULL);
 	g_signal_connect (treeview->settings, "notify", G_CALLBACK (settings_changed), treeview);
 
-	treeview->model = gtk_list_store_new (9, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
-		G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
+	treeview->model = gtk_list_store_new (XTM_PTV_N_COLUMNS, G_TYPE_STRING, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_STRING, G_TYPE_UINT64,
+		G_TYPE_STRING, G_TYPE_UINT64, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_FLOAT, G_TYPE_STRING, G_TYPE_INT);
 
-	g_object_set (treeview, "search-column", COLUMN_COMMAND, "model", treeview->model, NULL);
+	g_object_set (treeview, "search-column", XTM_PTV_COLUMN_COMMAND, "model", treeview->model, NULL);
 
 	cell_text = gtk_cell_renderer_text_new();
 
@@ -87,61 +73,60 @@ xtm_process_tree_view_init (XtmProcessTreeView *treeview)
 	cell_cmdline = gtk_cell_renderer_text_new ();
 	g_object_set (cell_cmdline, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
 
-	column = gtk_tree_view_column_new_with_attributes (_("Task"), cell_cmdline, "text", COLUMN_COMMAND, NULL);
+	column = gtk_tree_view_column_new_with_attributes (_("Task"), cell_cmdline, "text", XTM_PTV_COLUMN_COMMAND, NULL);
 	g_object_set (column, "expand", TRUE, "reorderable", FALSE, "resizable", TRUE, "visible", TRUE, NULL);
-	gtk_tree_view_column_set_sort_column_id (GTK_TREE_VIEW_COLUMN (column), COLUMN_COMMAND);
+	gtk_tree_view_column_set_sort_column_id (GTK_TREE_VIEW_COLUMN (column), XTM_PTV_COLUMN_COMMAND);
 	gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
 
 	g_object_get (treeview->settings, "column-pid", &visible, NULL);
-	column = gtk_tree_view_column_new_with_attributes (_("PID"), cell_right_aligned, "text", COLUMN_PID, NULL);
+	column = gtk_tree_view_column_new_with_attributes (_("PID"), cell_right_aligned, "text", XTM_PTV_COLUMN_PID, NULL);
 	g_object_set (column, "expand", FALSE, "reorderable", FALSE, "resizable", TRUE, "visible", visible, NULL);
-	gtk_tree_view_column_set_sort_column_id (GTK_TREE_VIEW_COLUMN (column), COLUMN_PID);
+	gtk_tree_view_column_set_sort_column_id (GTK_TREE_VIEW_COLUMN (column), XTM_PTV_COLUMN_PID);
 	gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
 
 	g_object_get (treeview->settings, "column-ppid", &visible, NULL);
-	column = gtk_tree_view_column_new_with_attributes (_("PPID"), cell_right_aligned, "text", COLUMN_PPID, NULL);
+	column = gtk_tree_view_column_new_with_attributes (_("PPID"), cell_right_aligned, "text", XTM_PTV_COLUMN_PPID, NULL);
 	g_object_set (column, "expand", FALSE, "reorderable", FALSE, "resizable", TRUE, "visible", visible, NULL);
-	gtk_tree_view_column_set_sort_column_id (GTK_TREE_VIEW_COLUMN (column), COLUMN_PPID);
+	gtk_tree_view_column_set_sort_column_id (GTK_TREE_VIEW_COLUMN (column), XTM_PTV_COLUMN_PPID);
 	gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
 
 	g_object_get (treeview->settings, "column-state", &visible, NULL);
-	column = gtk_tree_view_column_new_with_attributes (_("State"), cell_text, "text", COLUMN_STATE, NULL);
+	column = gtk_tree_view_column_new_with_attributes (_("State"), cell_text, "text", XTM_PTV_COLUMN_STATE, NULL);
 	g_object_set (column, "expand", FALSE, "reorderable", FALSE, "resizable", TRUE, "visible", visible, NULL);
-	gtk_tree_view_column_set_sort_column_id (GTK_TREE_VIEW_COLUMN (column), COLUMN_STATE);
+	gtk_tree_view_column_set_sort_column_id (GTK_TREE_VIEW_COLUMN (column), XTM_PTV_COLUMN_STATE);
 	gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
 
 	g_object_get (treeview->settings, "column-vsz", &visible, NULL);
-	column = gtk_tree_view_column_new_with_attributes (_("VSZ"), cell_right_aligned, "text", COLUMN_VSZ, NULL);
+	column = gtk_tree_view_column_new_with_attributes (_("VSZ"), cell_right_aligned, "text", XTM_PTV_COLUMN_VSZ_STR, NULL);
 	g_object_set (column, "expand", FALSE, "reorderable", FALSE, "resizable", TRUE, "visible", visible, NULL);
-	gtk_tree_view_column_set_sort_column_id (GTK_TREE_VIEW_COLUMN (column), COLUMN_VSZ);
+	gtk_tree_view_column_set_sort_column_id (GTK_TREE_VIEW_COLUMN (column), XTM_PTV_COLUMN_VSZ);
 	gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
 
 	g_object_get (treeview->settings, "column-rss", &visible, NULL);
-	column = gtk_tree_view_column_new_with_attributes (_("RSS"), cell_right_aligned, "text", COLUMN_RSS, NULL);
+	column = gtk_tree_view_column_new_with_attributes (_("RSS"), cell_right_aligned, "text", XTM_PTV_COLUMN_RSS_STR, NULL);
 	g_object_set (column, "expand", FALSE, "reorderable", FALSE, "resizable", TRUE, "visible", visible, NULL);
-	gtk_tree_view_column_set_sort_column_id (GTK_TREE_VIEW_COLUMN (column), COLUMN_RSS);
+	gtk_tree_view_column_set_sort_column_id (GTK_TREE_VIEW_COLUMN (column), XTM_PTV_COLUMN_RSS);
 	gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
 
 	g_object_get (treeview->settings, "column-uid", &visible, NULL);
-	column = gtk_tree_view_column_new_with_attributes (_("UID"), cell_text, "text", COLUMN_UID, NULL);
+	column = gtk_tree_view_column_new_with_attributes (_("UID"), cell_text, "text", XTM_PTV_COLUMN_UID, NULL);
 	g_object_set (column, "expand", FALSE, "reorderable", FALSE, "resizable", TRUE, "visible", visible, NULL);
-	gtk_tree_view_column_set_sort_column_id (GTK_TREE_VIEW_COLUMN (column), COLUMN_UID);
+	gtk_tree_view_column_set_sort_column_id (GTK_TREE_VIEW_COLUMN (column), XTM_PTV_COLUMN_UID);
 	gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
 
 	g_object_get (treeview->settings, "column-cpu", &visible, NULL);
-	column = gtk_tree_view_column_new_with_attributes (_("CPU"), cell_right_aligned, "text", COLUMN_CPU, NULL);
+	column = gtk_tree_view_column_new_with_attributes (_("CPU"), cell_right_aligned, "text", XTM_PTV_COLUMN_CPU_STR, NULL);
 	g_object_set (column, "expand", FALSE, "reorderable", FALSE, "resizable", TRUE, "visible", visible, NULL);
-	gtk_tree_view_column_set_sort_column_id (GTK_TREE_VIEW_COLUMN (column), COLUMN_CPU);
+	gtk_tree_view_column_set_sort_column_id (GTK_TREE_VIEW_COLUMN (column), XTM_PTV_COLUMN_CPU);
 	gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
 
 	g_object_get (treeview->settings, "column-priority", &visible, NULL);
 	/* TRANSLATORS: “Prio.” is short for Priority, it appears in the tree view header. */
-	column = gtk_tree_view_column_new_with_attributes (_("Prio."), cell_right_aligned, "text", COLUMN_PRIORITY, NULL);
+	column = gtk_tree_view_column_new_with_attributes (_("Prio."), cell_right_aligned, "text", XTM_PTV_COLUMN_PRIORITY, NULL);
 	g_object_set (column, "expand", FALSE, "reorderable", FALSE, "resizable", TRUE, "visible", visible, NULL);
-	gtk_tree_view_column_set_sort_column_id (GTK_TREE_VIEW_COLUMN (column), COLUMN_PRIORITY);
+	gtk_tree_view_column_set_sort_column_id (GTK_TREE_VIEW_COLUMN (column), XTM_PTV_COLUMN_PRIORITY);
 	gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
 
-	gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (treeview->model), sort_by_string, NULL, NULL);
 	gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (treeview->model), sort_column_id, sort_type);
 
 	g_signal_connect (treeview, "button-press-event", G_CALLBACK (treeview_clicked), NULL);
@@ -165,27 +150,27 @@ treeview_clicked (XtmProcessTreeView *treeview, GdkEventButton *event)
 static void
 settings_changed (GObject *object, GParamSpec *pspec, XtmProcessTreeView *treeview)
 {
-	if (g_strstr_len (pspec->name, -1, "column-") != NULL)
+	if (g_str_has_prefix (pspec->name, "column-"))
 	{
 		gboolean visible;
 		gushort column_id;
 
 		if (!g_strcmp0 (pspec->name, "column-uid"))
-			column_id = COLUMN_UID;
+			column_id = XTM_PTV_COLUMN_UID;
 		else if (!g_strcmp0 (pspec->name, "column-pid"))
-			column_id = COLUMN_PID;
+			column_id = XTM_PTV_COLUMN_PID;
 		else if (!g_strcmp0 (pspec->name, "column-ppid"))
-			column_id = COLUMN_PPID;
+			column_id = XTM_PTV_COLUMN_PPID;
 		else if (!g_strcmp0 (pspec->name, "column-state"))
-			column_id = COLUMN_STATE;
+			column_id = XTM_PTV_COLUMN_STATE;
 		else if (!g_strcmp0 (pspec->name, "column-vsz"))
-			column_id = COLUMN_VSZ;
+			column_id = XTM_PTV_COLUMN_VSZ_STR;
 		else if (!g_strcmp0 (pspec->name, "column-rss"))
-			column_id = COLUMN_RSS;
+			column_id = XTM_PTV_COLUMN_RSS_STR;
 		else if (!g_strcmp0 (pspec->name, "column-cpu"))
-			column_id = COLUMN_CPU;
+			column_id = XTM_PTV_COLUMN_CPU_STR;
 		else if (!g_strcmp0 (pspec->name, "column-priority"))
-			column_id = COLUMN_PRIORITY;
+			column_id = XTM_PTV_COLUMN_PRIORITY;
 
 		g_object_get (object, pspec->name, &visible, NULL);
 		gtk_tree_view_column_set_visible (gtk_tree_view_get_column (GTK_TREE_VIEW (treeview), column_id), visible);
@@ -198,46 +183,6 @@ settings_changed (GObject *object, GParamSpec *pspec, XtmProcessTreeView *treevi
 	}
 }
 
-static int
-sort_by_string (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer user_data)
-{
-	gint sort_column_id;
-	GtkSortType order;
-	gchar *str1 = NULL, *str2 = NULL;
-	gchar *cstr1 = NULL, *cstr2 = NULL;
-	gint ret = 0;
-
-	g_debug (__func__);
-
-	if (!gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (model), &sort_column_id, &order))
-	{
-		g_debug ("sort column default or unsorted: %d", sort_column_id);
-		return ret;
-	}
-
-	gtk_tree_model_get(model, a, sort_column_id, &str1, -1);
-	gtk_tree_model_get(model, b, sort_column_id, &str2, -1);
-
-	cstr1 = g_utf8_collate_key_for_filename (str1, -1);
-	cstr2 = g_utf8_collate_key_for_filename (str2, -1);
-
-	if (cstr1 != NULL && cstr2 != NULL)
-	{
-		ret = g_utf8_collate (cstr1, cstr2);
-	}
-	else if ((cstr1 == NULL && cstr2 != NULL) || (cstr1 != NULL && cstr2 == NULL))
-	{
-		ret = (cstr1 == NULL) ? -1 : 1;
-	}
-
-	g_free (str1);
-	g_free (str2);
-	g_free (cstr1);
-	g_free (cstr2);
-
-	return ret;
-}
-
 
 
 GtkWidget *
diff --git a/src/process-tree-view.h b/src/process-tree-view.h
index 71db963..481c552 100644
--- a/src/process-tree-view.h
+++ b/src/process-tree-view.h
@@ -16,6 +16,23 @@
 
 #include <glib-object.h>
 
+enum
+{
+	XTM_PTV_COLUMN_COMMAND,
+	XTM_PTV_COLUMN_PID,
+	XTM_PTV_COLUMN_PPID,
+	XTM_PTV_COLUMN_STATE,
+	XTM_PTV_COLUMN_VSZ,
+	XTM_PTV_COLUMN_VSZ_STR,
+	XTM_PTV_COLUMN_RSS,
+	XTM_PTV_COLUMN_RSS_STR,
+	XTM_PTV_COLUMN_UID,
+	XTM_PTV_COLUMN_CPU,
+	XTM_PTV_COLUMN_CPU_STR,
+	XTM_PTV_COLUMN_PRIORITY,
+	XTM_PTV_N_COLUMNS,
+};
+
 #define XTM_TYPE_PROCESS_TREE_VIEW		(xtm_process_tree_view_get_type ())
 #define XTM_PROCESS_TREE_VIEW(obj)		(G_TYPE_CHECK_INSTANCE_CAST ((obj), XTM_TYPE_PROCESS_TREE_VIEW, XtmProcessTreeView))
 #define XTM_PROCESS_TREE_VIEW_CLASS(klass)	(G_TYPE_CHECK_CLASS_CAST ((klass), XTM_TYPE_PROCESS_TREE_VIEW, XtmProcessTreeViewClass))
diff --git a/src/task-manager-linux.c b/src/task-manager-linux.c
index c207a11..d006bde 100644
--- a/src/task-manager-linux.c
+++ b/src/task-manager-linux.c
@@ -9,11 +9,18 @@
  */
 
 #include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <pwd.h>
+#include <unistd.h>
+#include <string.h>
 
 #include <glib.h>
 
 #include "task-manager.h"
 
+static gushort _cpu_count = 0;
+
 gboolean
 get_memory_usage (guint64 *memory_total, guint64 *memory_free, guint64 *memory_cache, guint64 *memory_buffers, guint64 *swap_total, guint64 *swap_free)
 {
@@ -23,9 +30,7 @@ get_memory_usage (guint64 *memory_total, guint64 *memory_free, guint64 *memory_c
 	gushort found = 0;
 
 	if ((file = fopen (filename, "r")) == NULL)
-	{
 		return FALSE;
-	}
 
 	while (found < 6 && fgets (buffer, 1024, file) != NULL)
 	{
@@ -58,21 +63,19 @@ get_cpu_usage (gushort *cpu_count, gfloat *cpu_user, gfloat *cpu_system)
 	static gulong cur_jiffies_system = 0, old_jiffies_system = 0;
 	static gulong cur_jiffies = 0, old_jiffies = 0;
 	gulong user, user_nice, system, idle;
-	gushort count = 0;
 
 	if ((file = fopen (filename, "r")) == NULL)
-	{
 		return FALSE;
-	}
 
 	fgets (buffer, 1024, file);
 	sscanf (buffer, "cpu\t%u %u %u %u", &user, &user_nice, &system, &idle);
 
+	_cpu_count = 0;
 	while (fgets (buffer, 1024, file) != NULL)
 	{
 		if (buffer[0] != 'c' && buffer[1] != 'p' && buffer[2] != 'u')
 			break;
-		count += 1;
+		_cpu_count += 1;
 	}
 	fclose (file);
 
@@ -86,7 +89,175 @@ get_cpu_usage (gushort *cpu_count, gfloat *cpu_user, gfloat *cpu_system)
 
 	*cpu_user = (old_jiffies > 0) ? (cur_jiffies_user - old_jiffies_user) * 100 / (gdouble)(cur_jiffies - old_jiffies) : 0;
 	*cpu_system = (old_jiffies > 0) ? (cur_jiffies_system - old_jiffies_system) * 100 / (gdouble)(cur_jiffies - old_jiffies) : 0;
-	*cpu_count = (count != 0) ? count : 1;
+	*cpu_count = (_cpu_count > 0) ? _cpu_count : 1;
+	_cpu_count = *cpu_count;
+
+	return TRUE;
+}
+
+static inline int get_pagesize ()
+{
+	static int pagesize = 0;
+	if (pagesize == 0)
+	{
+		pagesize = sysconf (_SC_PAGESIZE);
+		if (pagesize == 0)
+			pagesize = 4096;
+	}
+	return pagesize;
+}
+
+static void
+get_task_cmdline (Task *task)
+{
+	FILE *file;
+	gchar filename[96];
+	gint i;
+	gchar c;
+
+	snprintf (filename, 96, "/proc/%i/cmdline", task->pid);
+	if ((file = fopen (filename, "r")) == NULL)
+		return;
+
+	/* Drop parentheses around task->name */
+	// FIXME comm concats the name to 15 chars
+	{
+		gchar *p;
+		g_strlcpy (task->name, &task->name[1], sizeof (task->name));
+		p = g_strrstr (task->name, ")");
+		*p = '\0';
+	}
+
+	/* Read byte per byte until EOF */
+	for (i = 0; (c = fgetc (file)) != EOF && i < sizeof (task->cmdline) - 1; i++)
+		task->cmdline[i] = (c == '\0') ? ' ' : c;
+	if (task->cmdline[i-1] == ' ')
+		task->cmdline[i-1] = '\0';
+	fclose (file);
+
+	/* Kernel processes don't have a cmdline nor an exec path */
+	if (i == 0)
+	{
+		size_t len = strlen (task->name);
+		g_strlcpy (&task->cmdline[1], task->name, len + 1);
+		task->cmdline[0] = '[';
+		task->cmdline[len+1] = ']';
+		task->cmdline[len+2] = '\0';
+	}
+}
+
+static gboolean
+get_task_details (guint pid, Task *task)
+{
+	FILE *file;
+	gchar filename[96];
+	gchar buffer[1024];
+
+	snprintf (filename, 96, "/proc/%d/stat", pid);
+	if ((file = fopen (filename, "r")) == NULL)
+		return FALSE;
+
+	fgets (buffer, 1024, file);
+	fclose (file);
+
+	{
+		gchar dummy[255];
+		gint idummy;
+		static gulong cur_j_user, cur_j_system;
+		static gulong old_j_user, old_j_system;
+		struct passwd *pw;
+		struct stat sstat;
+
+		sscanf(buffer, "%i %255s %1s %i %i %i %i %i %255s %255s %255s %255s %255s %i %i %i %i %i %i %i %i %i %i %i %255s %255s %255s %i %255s %255s %255s %255s %255s %255s %255s %255s %255s %255s %i %255s %255s",
+			&task->pid,	// processid
+			task->name,	// processname
+			task->state,	// processstate
+			&task->ppid,	// parentid
+			 &idummy,	// processs groupid
+
+			 &idummy,	// session id
+			 &idummy,	// tty id
+			 &idummy,	// tpgid the process group ID of the process running on tty of the process
+			 dummy,		// flags
+			 dummy,		// minflt minor faults the process has maid
+
+			 dummy,		// cminflt
+			 dummy,		// majflt
+			 dummy,		// cmajflt
+			&cur_j_user,	// utime the number of jiffies that this process has scheduled in user mode
+			&cur_j_system,	// stime " system mode
+
+			 &idummy,	// cutime " waited for children in user mode
+			 &idummy,	// cstime " system mode
+			 &idummy,	// priority (nice value + fifteen)
+			&task->prio,	// nice range from 19 to -19
+			 &idummy,	// hardcoded 0
+
+			 &idummy,	// itrealvalue time in jiffies to next SIGALRM send to this process
+			 &idummy,	// starttime jiffies the process startet after system boot
+			&task->vsz,	// vsize in bytes
+			&task->rss,	// rss (number of pages in real memory)
+			 dummy,		// rlim limit in bytes for rss
+
+			 dummy,		// startcode
+			 dummy,		// endcode
+			 &idummy,	// startstack
+			 dummy,		// kstkesp value of esp (stack pointer)
+			 dummy,		// kstkeip value of EIP (instruction pointer)
+
+			 dummy,		// signal. bitmap of pending signals
+			 dummy,		// blocked: bitmap of blocked signals
+			 dummy,		// sigignore: bitmap of ignored signals
+			 dummy,		// sigcatch: bitmap of catched signals
+			 dummy,		// wchan
+
+			 dummy,		// nswap
+			 dummy,		// cnswap
+			 dummy,		// exit_signal
+			 &idummy,	// CPU number last executed on
+			 dummy,
+
+			 dummy
+		);
+
+		task->rss *= get_pagesize ();
+		task->cpu_user = (old_j_user > 0 && _cpu_count > 0) ? (cur_j_user - old_j_user) / (gfloat)_cpu_count : 0;
+		task->cpu_system = (old_j_system > 0 && _cpu_count > 0) ? (cur_j_system - old_j_system) / (gfloat)_cpu_count : 0;
+
+		stat (filename, &sstat);
+		pw = getpwuid (sstat.st_uid);
+		task->uid = sstat.st_uid;
+		g_strlcpy (task->uid_name, (pw != NULL) ? pw->pw_name : "nobody", sizeof (task->uid_name));
+	}
+
+	get_task_cmdline (task);
+
+	return TRUE;
+}
+
+gboolean
+get_task_list (GArray *task_list)
+{
+	GDir *dir;
+	const gchar *name;
+	guint pid;
+	Task task = { 0 };
+
+	if ((dir = g_dir_open ("/proc", 0, NULL)) == NULL)
+		return FALSE;
+
+	while ((name = g_dir_read_name(dir)) != NULL)
+	{
+		if ((pid = (guint)g_ascii_strtoull (name, NULL, 0)) > 0)
+		{
+			if (get_task_details (pid, &task))
+			{
+				g_array_append_val (task_list, task);
+			}
+		}
+	}
+
+	g_dir_close (dir);
 
 	return TRUE;
 }
diff --git a/src/task-manager.c b/src/task-manager.c
index ca5de7d..c12696a 100644
--- a/src/task-manager.c
+++ b/src/task-manager.c
@@ -66,6 +66,7 @@ xtm_task_manager_class_init (XtmTaskManagerClass *klass)
 static void
 xtm_task_manager_init (XtmTaskManager *manager)
 {
+	manager->tasks = g_array_new (FALSE, FALSE, sizeof (Task));
 	get_owner_uid (&(manager->owner_uid), &(manager->owner_uid_name));
 	manager->hostname = get_hostname ();
 }
@@ -74,6 +75,7 @@ static void
 xtm_task_manager_finalize (GObject *object)
 {
 	XtmTaskManager *manager = XTM_TASK_MANAGER (object);
+	g_array_free (manager->tasks, TRUE);
 	g_free (manager->owner_uid_name);
 	g_free (manager->hostname);
 }
@@ -128,18 +130,13 @@ xtm_task_manager_get_hostname (XtmTaskManager *manager)
 	return manager->hostname;
 }
 
-GArray *
-xtm_task_manager_get_tasklist (XtmTaskManager *manager)
-{
-}
-
 void
 xtm_task_manager_get_system_info (XtmTaskManager *manager, guint *num_processes, gfloat *cpu, gfloat *memory, gfloat *swap)
 {
 	guint64 memory_used, swap_used;
 
 	/* Set number of processes */
-	*num_processes = 0;//manager->tasks->len;
+	*num_processes = manager->tasks->len;
 
 	/* Set memory and swap usage */
 	get_memory_usage (&manager->memory_total, &manager->memory_free, &manager->memory_cache, &manager->memory_buffers,
@@ -156,6 +153,87 @@ xtm_task_manager_get_system_info (XtmTaskManager *manager, guint *num_processes,
 	*cpu = manager->cpu_user + manager->cpu_system;
 }
 
+const GArray *
+xtm_task_manager_get_task_list (XtmTaskManager *manager)
+{
+	GArray *array;
+	guint i;
+
+	if (manager->tasks->len == 0)
+	{
+		get_task_list (manager->tasks);
+#if 1|DEBUG
+		{
+			gint i;
+			for (i = 0; i < manager->tasks->len; i++)
+			{
+				Task *task = &g_array_index (manager->tasks, Task, i);
+				g_print ("%5d %5s %15s %.50s\n", task->pid, task->uid_name, task->name, task->cmdline);
+			}
+		}
+#endif
+		return manager->tasks;
+	}
+
+	/* Retrieve new task list */
+	array = g_array_new (FALSE, FALSE, sizeof (Task));
+	get_task_list (array);
+
+	/* Remove terminated tasks */
+	for (i = 0; i < manager->tasks->len; i++)
+	{
+		guint j;
+		Task *task = &g_array_index (manager->tasks, Task, i);
+		gboolean found = FALSE;
+
+		for (j = 0; j < array->len; j++)
+		{
+			Task *tasktmp = &g_array_index (array, Task, j);
+			if (task->pid != tasktmp->pid)
+				continue;
+			found = TRUE;
+			break;
+		}
+
+		if (found == FALSE)
+			g_array_remove_index (manager->tasks, i);
+	}
+
+	/* Append started tasks and update existing ones */
+	for (i = 0; i < array->len; i++)
+	{
+		guint j;
+		Task *tasktmp = &g_array_index (array, Task, i);
+		gboolean found = FALSE;
+
+		for (j = 0; j < manager->tasks->len; j++)
+		{
+			Task *task = &g_array_index (manager->tasks, Task, j);
+			if (task->pid != tasktmp->pid)
+				continue;
+
+			found = TRUE;
+
+			task->ppid = tasktmp->ppid;
+			if (g_strcmp0 (task->state, tasktmp->state))
+				g_strlcpy (task->state, tasktmp->state, sizeof (task->state));
+			task->cpu_user = tasktmp->cpu_user;
+			task->cpu_system = tasktmp->cpu_system;
+			task->rss = tasktmp->rss;
+			task->vsz = tasktmp->vsz;
+			task->prio = tasktmp->prio;
+			break;
+		}
+
+		if (found == FALSE)
+			g_array_append_val (manager->tasks, tasktmp);
+	}
+
+	g_array_free (array, TRUE);
+
+	return manager->tasks;
+}
+
 void
 xtm_task_manager_send_signal_to_pid (XtmTaskManager *manager)
 {
diff --git a/src/task-manager.h b/src/task-manager.h
index b1b05bd..76eb5eb 100644
--- a/src/task-manager.h
+++ b/src/task-manager.h
@@ -23,17 +23,18 @@
 typedef struct _Task Task;
 struct _Task
 {
-	guint uid;
-	gchar uid_name[64];
-	guint pid;
-	guint ppid;
-	gchar program_name[64];
-	gchar full_cmdline[255];
-	gchar state[16];
-	gfloat cpu;
-	guint64 memory_vsz;
-	guint64 memory_rss;
-	gushort priority;
+	guint		uid;
+	gchar		uid_name[256];
+	guint		pid;
+	guint		ppid;
+	gchar		name[256];
+	gchar		cmdline[1024];
+	gchar		state[16];
+	gfloat		cpu_user;
+	gfloat		cpu_system;
+	guint64		vsz;
+	guint64		rss;
+	gshort		prio;
 };
 
 /**
@@ -42,7 +43,7 @@ struct _Task
 
 gboolean	get_memory_usage (guint64 *memory_total, guint64 *memory_free, guint64 *memory_cache, guint64 *memory_buffers, guint64 *swap_total, guint64 *swap_free);
 gboolean	get_cpu_usage (gushort *cpu_count, gfloat *cpu_user, gfloat *cpu_system);
-//gboolean	get_task_list (GArray *task_list);
+gboolean	get_task_list (GArray *task_list);
 //void		send_signal_to_task (gint task_id, gint signal);
 //void		set_priority_to_task (gint task_id, gint prio);
 
@@ -64,5 +65,6 @@ XtmTaskManager *	xtm_task_manager_new				();
 const gchar *		xtm_task_manager_get_username			(XtmTaskManager *manager);
 const gchar *		xtm_task_manager_get_hostname			(XtmTaskManager *manager);
 void			xtm_task_manager_get_system_info		(XtmTaskManager *manager, guint *num_processes, gfloat *cpu, gfloat *memory, gfloat *swap);
+const GArray *		xtm_task_manager_get_task_list			(XtmTaskManager *manager);
 
 #endif /* !TASK_MANAGER_H */



More information about the Xfce4-commits mailing list