|
Packit |
76ec6a |
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
Packit |
76ec6a |
/* Procman tree view and process updating
|
|
Packit |
76ec6a |
* Copyright (C) 2001 Kevin Vandersloot
|
|
Packit |
76ec6a |
*
|
|
Packit |
76ec6a |
* This program is free software; you can redistribute it and/or
|
|
Packit |
76ec6a |
* modify it under the terms of the GNU General Public License
|
|
Packit |
76ec6a |
* as published by the Free Software Foundation; either version 2
|
|
Packit |
76ec6a |
* of the License, or (at your option) any later version.
|
|
Packit |
76ec6a |
*
|
|
Packit |
76ec6a |
* This program is distributed in the hope that it will be useful,
|
|
Packit |
76ec6a |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
76ec6a |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit |
76ec6a |
* GNU General Public License for more details.
|
|
Packit |
76ec6a |
*
|
|
Packit |
76ec6a |
* You should have received a copy of the GNU Library General Public
|
|
Packit |
76ec6a |
* License along with this program; if not, see <http://www.gnu.org/licenses/>.
|
|
Packit |
76ec6a |
*
|
|
Packit |
76ec6a |
*/
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
#include <config.h>
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
#include <string.h>
|
|
Packit |
76ec6a |
#include <math.h>
|
|
Packit |
76ec6a |
#include <glib/gi18n.h>
|
|
Packit |
76ec6a |
#include <glib/gprintf.h>
|
|
Packit |
76ec6a |
#include <glibtop.h>
|
|
Packit |
76ec6a |
#include <glibtop/proclist.h>
|
|
Packit |
76ec6a |
#include <glibtop/procstate.h>
|
|
Packit |
76ec6a |
#include <glibtop/procio.h>
|
|
Packit |
76ec6a |
#include <glibtop/procmem.h>
|
|
Packit |
76ec6a |
#include <glibtop/procmap.h>
|
|
Packit |
76ec6a |
#include <glibtop/proctime.h>
|
|
Packit |
76ec6a |
#include <glibtop/procuid.h>
|
|
Packit |
76ec6a |
#include <glibtop/procargs.h>
|
|
Packit |
76ec6a |
#include <glibtop/prockernel.h>
|
|
Packit |
76ec6a |
#include <glibtop/mem.h>
|
|
Packit |
76ec6a |
#include <glibtop/swap.h>
|
|
Packit |
76ec6a |
#include <sys/stat.h>
|
|
Packit |
76ec6a |
#include <pwd.h>
|
|
Packit |
76ec6a |
#include <time.h>
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
#include <set>
|
|
Packit |
76ec6a |
#include <list>
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
#ifdef HAVE_WNCK
|
|
Packit |
76ec6a |
#define WNCK_I_KNOW_THIS_IS_UNSTABLE
|
|
Packit |
76ec6a |
#include <libwnck/libwnck.h>
|
|
Packit |
76ec6a |
#endif
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
#include "application.h"
|
|
Packit |
76ec6a |
#include "proctable.h"
|
|
Packit |
76ec6a |
#include "prettytable.h"
|
|
Packit |
76ec6a |
#include "util.h"
|
|
Packit |
76ec6a |
#include "interface.h"
|
|
Packit |
76ec6a |
#include "selinux.h"
|
|
Packit |
76ec6a |
#include "settings-keys.h"
|
|
Packit |
76ec6a |
#include "cgroups.h"
|
|
Packit |
76ec6a |
#include "legacy/treeview.h"
|
|
Packit |
76ec6a |
#include "systemd.h"
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
#ifdef GDK_WINDOWING_X11
|
|
Packit |
76ec6a |
#include <gdk/gdkx.h>
|
|
Packit |
76ec6a |
#endif
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
ProcInfo* ProcList::find(pid_t pid)
|
|
Packit |
76ec6a |
{
|
|
Packit |
76ec6a |
auto it = data.find(pid);
|
|
Packit |
76ec6a |
return (it == data.end() ? nullptr : &it->second);
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
static void
|
|
Packit |
76ec6a |
cb_save_tree_state(gpointer, gpointer data)
|
|
Packit |
76ec6a |
{
|
|
Packit |
76ec6a |
GsmApplication * const app = static_cast<GsmApplication *>(data);
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
gsm_tree_view_save_state (app->tree);
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
static void
|
|
Packit |
76ec6a |
cb_proctree_destroying (GtkTreeView *self, gpointer data)
|
|
Packit |
76ec6a |
{
|
|
Packit |
76ec6a |
g_signal_handlers_disconnect_by_func (self,
|
|
Packit |
76ec6a |
(gpointer) cb_save_tree_state,
|
|
Packit |
76ec6a |
data);
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
g_signal_handlers_disconnect_by_func (gtk_tree_view_get_model (self),
|
|
Packit |
76ec6a |
(gpointer) cb_save_tree_state,
|
|
Packit |
76ec6a |
data);
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
static gboolean
|
|
Packit |
76ec6a |
cb_tree_button_pressed (GtkWidget *widget, GdkEventButton *event, gpointer data)
|
|
Packit |
76ec6a |
{
|
|
Packit |
76ec6a |
GsmApplication *app = (GsmApplication *) data;
|
|
Packit |
76ec6a |
GtkTreePath *path;
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
if (!gdk_event_triggers_context_menu ((GdkEvent *) event))
|
|
Packit |
76ec6a |
return FALSE;
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
if (!gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (app->tree), event->x, event->y, &path, NULL, NULL, NULL))
|
|
Packit |
76ec6a |
return FALSE;
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
if (!gtk_tree_selection_path_is_selected (app->selection, path)) {
|
|
Packit |
76ec6a |
if (!(event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)))
|
|
Packit |
76ec6a |
gtk_tree_selection_unselect_all (app->selection);
|
|
Packit |
76ec6a |
gtk_tree_selection_select_path (app->selection, path);
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
gtk_tree_path_free (path);
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
gtk_menu_popup_at_pointer (GTK_MENU (app->popup_menu), NULL);
|
|
Packit |
76ec6a |
return TRUE;
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
static gboolean
|
|
Packit |
76ec6a |
cb_tree_popup_menu (GtkWidget *widget, gpointer data)
|
|
Packit |
76ec6a |
{
|
|
Packit |
76ec6a |
GsmApplication *app = (GsmApplication *) data;
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
gtk_menu_popup_at_pointer (GTK_MENU (app->popup_menu), NULL);
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
return TRUE;
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
void
|
|
Packit |
76ec6a |
get_last_selected (GtkTreeModel *model, GtkTreePath *path,
|
|
Packit |
76ec6a |
GtkTreeIter *iter, gpointer data)
|
|
Packit |
76ec6a |
{
|
|
Packit |
76ec6a |
ProcInfo **info = (ProcInfo**) data;
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
gtk_tree_model_get (model, iter, COL_POINTER, info, -1);
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
void
|
|
Packit |
76ec6a |
cb_row_selected (GtkTreeSelection *selection, gpointer data)
|
|
Packit |
76ec6a |
{
|
|
Packit |
76ec6a |
GsmApplication *app = (GsmApplication *) data;
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
app->selection = selection;
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
ProcInfo *selected_process = NULL;
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
/* get the most recent selected process and determine if there are
|
|
Packit |
76ec6a |
** no selected processes
|
|
Packit |
76ec6a |
*/
|
|
Packit |
76ec6a |
gtk_tree_selection_selected_foreach (app->selection, get_last_selected,
|
|
Packit |
76ec6a |
&selected_process);
|
|
Packit |
76ec6a |
if (selected_process) {
|
|
Packit |
76ec6a |
GVariant *priority;
|
|
Packit |
76ec6a |
gint nice = selected_process->nice;
|
|
Packit |
76ec6a |
if (nice < -7)
|
|
Packit |
76ec6a |
priority = g_variant_new_int32 (-20);
|
|
Packit |
76ec6a |
else if (nice < -2)
|
|
Packit |
76ec6a |
priority = g_variant_new_int32 (-5);
|
|
Packit |
76ec6a |
else if (nice < 3)
|
|
Packit |
76ec6a |
priority = g_variant_new_int32 (0);
|
|
Packit |
76ec6a |
else if (nice < 7)
|
|
Packit |
76ec6a |
priority = g_variant_new_int32 (5);
|
|
Packit |
76ec6a |
else
|
|
Packit |
76ec6a |
priority = g_variant_new_int32 (19);
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
GAction *action = g_action_map_lookup_action (G_ACTION_MAP (app->main_window),
|
|
Packit |
76ec6a |
"priority");
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
g_action_change_state (action, priority);
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
update_sensitivity(app);
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
static gint
|
|
Packit |
76ec6a |
cb_timeout (gpointer data)
|
|
Packit |
76ec6a |
{
|
|
Packit |
76ec6a |
GsmApplication *app = (GsmApplication *) data;
|
|
Packit |
76ec6a |
guint new_interval;
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
proctable_update (app);
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
if (app->smooth_refresh->get(new_interval)) {
|
|
Packit |
76ec6a |
app->timeout = g_timeout_add(new_interval,
|
|
Packit |
76ec6a |
cb_timeout,
|
|
Packit |
76ec6a |
app);
|
|
Packit |
76ec6a |
return G_SOURCE_REMOVE;
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
return G_SOURCE_CONTINUE;
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
static void
|
|
Packit |
76ec6a |
cb_refresh_icons (GtkIconTheme *theme, gpointer data)
|
|
Packit |
76ec6a |
{
|
|
Packit |
76ec6a |
GsmApplication *app = (GsmApplication *) data;
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
if(app->timeout) {
|
|
Packit |
76ec6a |
g_source_remove (app->timeout);
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
for (auto& v : app->processes) {
|
|
Packit |
76ec6a |
app->pretty_table->set_icon(v.second);
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
cb_timeout(app);
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
static gboolean
|
|
Packit |
76ec6a |
iter_matches_search_key (GtkTreeModel *model, GtkTreeIter *iter, const gchar *search_text)
|
|
Packit |
76ec6a |
{
|
|
Packit |
76ec6a |
char *name;
|
|
Packit |
76ec6a |
char *user;
|
|
Packit |
76ec6a |
pid_t pid;
|
|
Packit |
76ec6a |
char *pids;
|
|
Packit |
76ec6a |
char *args;
|
|
Packit |
76ec6a |
gboolean found;
|
|
Packit |
76ec6a |
char *search_pattern;
|
|
Packit |
76ec6a |
char **keys;
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
gtk_tree_model_get (model, iter,
|
|
Packit |
76ec6a |
COL_NAME, &name,
|
|
Packit |
76ec6a |
COL_USER, &user,
|
|
Packit |
76ec6a |
COL_PID, &pid,
|
|
Packit |
76ec6a |
COL_ARGS, &args,
|
|
Packit |
76ec6a |
-1);
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
pids = g_strdup_printf ("%d", pid);
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
keys = g_strsplit_set(search_text, " |", -1);
|
|
Packit |
76ec6a |
search_pattern = g_strjoinv ("|", keys);
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
auto regex = Glib::Regex::create(search_pattern, Glib::REGEX_CASELESS);
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
found = (name && regex->match(name)) || (user && regex->match(user))
|
|
Packit |
76ec6a |
|| (pids && regex->match(pids)) || (args && regex->match(args));
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
g_strfreev (keys);
|
|
Packit |
76ec6a |
g_free (search_pattern);
|
|
Packit |
76ec6a |
g_free (name);
|
|
Packit |
76ec6a |
g_free (user);
|
|
Packit |
76ec6a |
g_free (args);
|
|
Packit |
76ec6a |
g_free (pids);
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
return found;
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
static gboolean
|
|
Packit |
76ec6a |
process_visibility_func (GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
|
|
Packit |
76ec6a |
{
|
|
Packit |
76ec6a |
GsmApplication * const app = static_cast<GsmApplication *>(data);
|
|
Packit |
76ec6a |
const gchar * search_text = app->search_entry == NULL ? "" : gtk_entry_get_text (GTK_ENTRY (app->search_entry));
|
|
Packit |
76ec6a |
GtkTreePath *tree_path = gtk_tree_model_get_path (model, iter);
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
if (strcmp (search_text, "") == 0) {
|
|
Packit |
76ec6a |
gtk_tree_path_free (tree_path);
|
|
Packit |
76ec6a |
return TRUE;
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
// in case we are in dependencies view, we show (and expand) rows not matching the text, but having a matching child
|
|
Packit |
76ec6a |
gboolean match = false;
|
|
Packit |
76ec6a |
if (app->settings->get_boolean (GSM_SETTING_SHOW_DEPENDENCIES)) {
|
|
Packit |
76ec6a |
GtkTreeIter child;
|
|
Packit |
76ec6a |
if (gtk_tree_model_iter_children (model, &child, iter)) {
|
|
Packit |
76ec6a |
gboolean child_match = FALSE;
|
|
Packit |
76ec6a |
do {
|
|
Packit |
76ec6a |
child_match = process_visibility_func (model, &child, data);
|
|
Packit |
76ec6a |
} while (gtk_tree_model_iter_next (model, &child) && !child_match);
|
|
Packit |
76ec6a |
match = child_match;
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
match |= iter_matches_search_key (model, iter, search_text);
|
|
Packit |
76ec6a |
// TODO auto-expand items not matching the search string but having matching children
|
|
Packit |
76ec6a |
// complicated because of treestore nested in treemodelfilter nested in treemodelsort
|
|
Packit |
76ec6a |
// expand to path requires the path string in the treemodelsort, but tree_path is the path in the double nested treestore
|
|
Packit |
76ec6a |
//if (match && (strlen (search_text) > 0)) {
|
|
Packit |
76ec6a |
// gtk_tree_view_expand_to_path (GTK_TREE_VIEW (app->tree), tree_path);
|
|
Packit |
76ec6a |
//}
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
} else {
|
|
Packit |
76ec6a |
match = iter_matches_search_key (model, iter, search_text);
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
gtk_tree_path_free (tree_path);
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
return match;
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
static void
|
|
Packit |
76ec6a |
proctable_clear_tree (GsmApplication * const app)
|
|
Packit |
76ec6a |
{
|
|
Packit |
76ec6a |
GtkTreeModel *model;
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (
|
|
Packit |
76ec6a |
gtk_tree_model_sort_get_model(GTK_TREE_MODEL_SORT (
|
|
Packit |
76ec6a |
gtk_tree_view_get_model (GTK_TREE_VIEW(app->tree))))));
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
gtk_tree_store_clear (GTK_TREE_STORE (model));
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
proctable_free_table (app);
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
update_sensitivity(app);
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
static void
|
|
Packit |
76ec6a |
cb_show_dependencies_changed(Gio::Settings& settings, Glib::ustring key, GsmApplication* app) {
|
|
Packit |
76ec6a |
if (app->timeout) {
|
|
Packit |
76ec6a |
gtk_tree_view_set_show_expanders (GTK_TREE_VIEW (app->tree),
|
|
Packit |
76ec6a |
settings.get_boolean (GSM_SETTING_SHOW_DEPENDENCIES));
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
proctable_clear_tree (app);
|
|
Packit |
76ec6a |
proctable_update (app);
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
static void
|
|
Packit |
76ec6a |
cb_show_whose_processes_changed(Gio::Settings& settings, Glib::ustring key, GsmApplication* app) {
|
|
Packit |
76ec6a |
if (app->timeout) {
|
|
Packit |
76ec6a |
proctable_clear_tree (app);
|
|
Packit |
76ec6a |
proctable_update (app);
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
GsmTreeView *
|
|
Packit |
76ec6a |
proctable_new (GsmApplication * const app)
|
|
Packit |
76ec6a |
{
|
|
Packit |
76ec6a |
GsmTreeView *proctree;
|
|
Packit |
76ec6a |
GtkTreeStore *model;
|
|
Packit |
76ec6a |
GtkTreeModelFilter *model_filter;
|
|
Packit |
76ec6a |
GtkTreeModelSort *model_sort;
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
GtkTreeViewColumn *column;
|
|
Packit |
76ec6a |
GtkCellRenderer *cell_renderer;
|
|
Packit |
76ec6a |
const gchar *titles[] = {
|
|
Packit |
76ec6a |
N_("Process Name"),
|
|
Packit |
76ec6a |
N_("User"),
|
|
Packit |
76ec6a |
N_("Status"),
|
|
Packit |
76ec6a |
N_("Virtual Memory"),
|
|
Packit |
76ec6a |
N_("Resident Memory"),
|
|
Packit |
76ec6a |
N_("Writable Memory"),
|
|
Packit |
76ec6a |
N_("Shared Memory"),
|
|
Packit |
76ec6a |
N_("X Server Memory"),
|
|
Packit |
76ec6a |
/* xgettext:no-c-format */ N_("% CPU"),
|
|
Packit |
76ec6a |
N_("CPU Time"),
|
|
Packit |
76ec6a |
N_("Started"),
|
|
Packit |
76ec6a |
N_("Nice"),
|
|
Packit |
76ec6a |
N_("ID"),
|
|
Packit |
76ec6a |
N_("Security Context"),
|
|
Packit |
76ec6a |
N_("Command Line"),
|
|
Packit |
76ec6a |
N_("Memory"),
|
|
Packit |
76ec6a |
/* xgettext: combined noun, the function the process is waiting in, see wchan ps(1) */
|
|
Packit |
76ec6a |
N_("Waiting Channel"),
|
|
Packit |
76ec6a |
N_("Control Group"),
|
|
Packit |
76ec6a |
N_("Unit"),
|
|
Packit |
76ec6a |
N_("Session"),
|
|
Packit |
76ec6a |
/* TRANSLATORS: Seat = i.e. the physical seat the session of the process belongs to, only
|
|
Packit |
76ec6a |
for multi-seat environments. See http://en.wikipedia.org/wiki/Multiseat_configuration */
|
|
Packit |
76ec6a |
N_("Seat"),
|
|
Packit |
76ec6a |
N_("Owner"),
|
|
Packit |
76ec6a |
N_("Disk read total"),
|
|
Packit |
76ec6a |
N_("Disk write total"),
|
|
Packit |
76ec6a |
N_("Disk read"),
|
|
Packit |
76ec6a |
N_("Disk write"),
|
|
Packit |
76ec6a |
N_("Priority"),
|
|
Packit |
76ec6a |
NULL,
|
|
Packit |
76ec6a |
"POINTER"
|
|
Packit |
76ec6a |
};
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
gint i;
|
|
Packit |
76ec6a |
auto settings = g_settings_get_child (app->settings->gobj (), GSM_SETTINGS_CHILD_PROCESSES);
|
|
Packit |
76ec6a |
model = gtk_tree_store_new (NUM_COLUMNS,
|
|
Packit |
76ec6a |
G_TYPE_STRING, /* Process Name */
|
|
Packit |
76ec6a |
G_TYPE_STRING, /* User */
|
|
Packit |
76ec6a |
G_TYPE_UINT, /* Status */
|
|
Packit |
76ec6a |
G_TYPE_ULONG, /* VM Size */
|
|
Packit |
76ec6a |
G_TYPE_ULONG, /* Resident Memory */
|
|
Packit |
76ec6a |
G_TYPE_ULONG, /* Writable Memory */
|
|
Packit |
76ec6a |
G_TYPE_ULONG, /* Shared Memory */
|
|
Packit |
76ec6a |
G_TYPE_ULONG, /* X Server Memory */
|
|
Packit |
76ec6a |
G_TYPE_UINT, /* % CPU */
|
|
Packit |
76ec6a |
G_TYPE_UINT64, /* CPU time */
|
|
Packit |
76ec6a |
G_TYPE_ULONG, /* Started */
|
|
Packit |
76ec6a |
G_TYPE_INT, /* Nice */
|
|
Packit |
76ec6a |
G_TYPE_UINT, /* ID */
|
|
Packit |
76ec6a |
G_TYPE_STRING, /* Security Context */
|
|
Packit |
76ec6a |
G_TYPE_STRING, /* Arguments */
|
|
Packit |
76ec6a |
G_TYPE_ULONG, /* Memory */
|
|
Packit |
76ec6a |
G_TYPE_STRING, /* wchan */
|
|
Packit |
76ec6a |
G_TYPE_STRING, /* Cgroup */
|
|
Packit |
76ec6a |
G_TYPE_STRING, /* Unit */
|
|
Packit |
76ec6a |
G_TYPE_STRING, /* Session */
|
|
Packit |
76ec6a |
G_TYPE_STRING, /* Seat */
|
|
Packit |
76ec6a |
G_TYPE_STRING, /* Owner */
|
|
Packit |
76ec6a |
G_TYPE_UINT64, /* Disk read total */
|
|
Packit |
76ec6a |
G_TYPE_UINT64, /* Disk write total*/
|
|
Packit |
76ec6a |
G_TYPE_UINT64, /* Disk read */
|
|
Packit |
76ec6a |
G_TYPE_UINT64, /* Disk write */
|
|
Packit |
76ec6a |
G_TYPE_STRING, /* Priority */
|
|
Packit |
76ec6a |
GDK_TYPE_PIXBUF, /* Icon */
|
|
Packit |
76ec6a |
G_TYPE_POINTER, /* ProcInfo */
|
|
Packit |
76ec6a |
G_TYPE_STRING /* Sexy tooltip */
|
|
Packit |
76ec6a |
);
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
model_filter = GTK_TREE_MODEL_FILTER (gtk_tree_model_filter_new (GTK_TREE_MODEL (model), NULL));
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
gtk_tree_model_filter_set_visible_func(model_filter, process_visibility_func, app, NULL);
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
model_sort = GTK_TREE_MODEL_SORT (gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (model_filter)));
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
proctree = gsm_tree_view_new (settings, TRUE);
|
|
Packit |
76ec6a |
gtk_tree_view_set_model (GTK_TREE_VIEW (proctree), GTK_TREE_MODEL (model_sort));
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
gtk_tree_view_set_tooltip_column (GTK_TREE_VIEW (proctree), COL_TOOLTIP);
|
|
Packit |
76ec6a |
gtk_tree_view_set_show_expanders (GTK_TREE_VIEW (proctree), app->settings->get_boolean (GSM_SETTING_SHOW_DEPENDENCIES));
|
|
Packit |
76ec6a |
gtk_tree_view_set_enable_search (GTK_TREE_VIEW (proctree), FALSE);
|
|
Packit |
76ec6a |
g_object_unref (G_OBJECT (model));
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
column = gtk_tree_view_column_new ();
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
cell_renderer = gtk_cell_renderer_pixbuf_new ();
|
|
Packit |
76ec6a |
gtk_tree_view_column_pack_start (column, cell_renderer, FALSE);
|
|
Packit |
76ec6a |
gtk_tree_view_column_set_attributes (column, cell_renderer,
|
|
Packit |
76ec6a |
"pixbuf", COL_PIXBUF,
|
|
Packit |
76ec6a |
NULL);
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
cell_renderer = gtk_cell_renderer_text_new ();
|
|
Packit |
76ec6a |
gtk_tree_view_column_pack_start (column, cell_renderer, FALSE);
|
|
Packit |
76ec6a |
gtk_tree_view_column_set_attributes (column, cell_renderer,
|
|
Packit |
76ec6a |
"text", COL_NAME,
|
|
Packit |
76ec6a |
NULL);
|
|
Packit |
76ec6a |
gtk_tree_view_column_set_title (column, _(titles[0]));
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
gtk_tree_view_column_set_sort_column_id (column, COL_NAME);
|
|
Packit |
76ec6a |
gtk_tree_view_column_set_resizable (column, TRUE);
|
|
Packit |
76ec6a |
gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
|
|
Packit |
76ec6a |
gtk_tree_view_column_set_min_width (column, 1);
|
|
Packit |
76ec6a |
gtk_tree_view_column_set_reorderable(column, TRUE);
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
gsm_tree_view_append_and_bind_column (proctree, column);
|
|
Packit |
76ec6a |
gtk_tree_view_set_expander_column (GTK_TREE_VIEW (proctree), column);
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
for (i = COL_USER; i <= COL_PRIORITY; i++) {
|
|
Packit |
76ec6a |
GtkTreeViewColumn *col;
|
|
Packit |
76ec6a |
GtkCellRenderer *cell;
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
#ifndef HAVE_WNCK
|
|
Packit |
76ec6a |
if (i == COL_MEMXSERVER)
|
|
Packit |
76ec6a |
continue;
|
|
Packit |
76ec6a |
#endif
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
if (i == COL_MEMWRITABLE)
|
|
Packit |
76ec6a |
continue;
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
cell = gtk_cell_renderer_text_new();
|
|
Packit |
76ec6a |
col = gtk_tree_view_column_new();
|
|
Packit |
76ec6a |
gtk_tree_view_column_pack_start(col, cell, TRUE);
|
|
Packit |
76ec6a |
gtk_tree_view_column_set_title(col, _(titles[i]));
|
|
Packit |
76ec6a |
gtk_tree_view_column_set_resizable(col, TRUE);
|
|
Packit |
76ec6a |
gtk_tree_view_column_set_sort_column_id(col, i);
|
|
Packit |
76ec6a |
gtk_tree_view_column_set_reorderable(col, TRUE);
|
|
Packit |
76ec6a |
gsm_tree_view_append_and_bind_column (proctree, col);
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
// type
|
|
Packit |
76ec6a |
switch (i) {
|
|
Packit |
76ec6a |
#ifdef HAVE_WNCK
|
|
Packit |
76ec6a |
case COL_MEMXSERVER:
|
|
Packit |
76ec6a |
gtk_tree_view_column_set_cell_data_func(col, cell,
|
|
Packit |
76ec6a |
&procman::size_cell_data_func,
|
|
Packit |
76ec6a |
GUINT_TO_POINTER(i),
|
|
Packit |
76ec6a |
NULL);
|
|
Packit |
76ec6a |
break;
|
|
Packit |
76ec6a |
#endif
|
|
Packit |
76ec6a |
case COL_VMSIZE:
|
|
Packit |
76ec6a |
case COL_MEMRES:
|
|
Packit |
76ec6a |
case COL_MEMSHARED:
|
|
Packit |
76ec6a |
case COL_MEM:
|
|
Packit |
76ec6a |
gtk_tree_view_column_set_cell_data_func(col, cell,
|
|
Packit |
76ec6a |
&procman::size_na_cell_data_func,
|
|
Packit |
76ec6a |
GUINT_TO_POINTER(i),
|
|
Packit |
76ec6a |
NULL);
|
|
Packit |
76ec6a |
break;
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
case COL_CPU_TIME:
|
|
Packit |
76ec6a |
gtk_tree_view_column_set_cell_data_func(col, cell,
|
|
Packit |
76ec6a |
&procman::duration_cell_data_func,
|
|
Packit |
76ec6a |
GUINT_TO_POINTER(i),
|
|
Packit |
76ec6a |
NULL);
|
|
Packit |
76ec6a |
break;
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
case COL_START_TIME:
|
|
Packit |
76ec6a |
gtk_tree_view_column_set_cell_data_func(col, cell,
|
|
Packit |
76ec6a |
&procman::time_cell_data_func,
|
|
Packit |
76ec6a |
GUINT_TO_POINTER(i),
|
|
Packit |
76ec6a |
NULL);
|
|
Packit |
76ec6a |
break;
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
case COL_STATUS:
|
|
Packit |
76ec6a |
gtk_tree_view_column_set_cell_data_func(col, cell,
|
|
Packit |
76ec6a |
&procman::status_cell_data_func,
|
|
Packit |
76ec6a |
GUINT_TO_POINTER(i),
|
|
Packit |
76ec6a |
NULL);
|
|
Packit |
76ec6a |
break;
|
|
Packit |
76ec6a |
case COL_DISK_READ_TOTAL:
|
|
Packit |
76ec6a |
case COL_DISK_WRITE_TOTAL:
|
|
Packit |
76ec6a |
gtk_tree_view_column_set_cell_data_func(col, cell,
|
|
Packit |
76ec6a |
&procman::size_na_cell_data_func,
|
|
Packit |
76ec6a |
GUINT_TO_POINTER(i),
|
|
Packit |
76ec6a |
NULL);
|
|
Packit |
76ec6a |
break;
|
|
Packit |
76ec6a |
case COL_DISK_READ_CURRENT:
|
|
Packit |
76ec6a |
case COL_DISK_WRITE_CURRENT:
|
|
Packit |
76ec6a |
gtk_tree_view_column_set_cell_data_func(col, cell,
|
|
Packit |
76ec6a |
&procman::io_rate_cell_data_func,
|
|
Packit |
76ec6a |
GUINT_TO_POINTER(i),
|
|
Packit |
76ec6a |
NULL);
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
break;
|
|
Packit |
76ec6a |
case COL_PRIORITY:
|
|
Packit |
76ec6a |
gtk_tree_view_column_set_cell_data_func(col, cell,
|
|
Packit |
76ec6a |
&procman::priority_cell_data_func,
|
|
Packit |
76ec6a |
GUINT_TO_POINTER(COL_NICE),
|
|
Packit |
76ec6a |
NULL);
|
|
Packit |
76ec6a |
break;
|
|
Packit |
76ec6a |
default:
|
|
Packit |
76ec6a |
gtk_tree_view_column_set_attributes(col, cell, "text", i, NULL);
|
|
Packit |
76ec6a |
break;
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
// sorting
|
|
Packit |
76ec6a |
switch (i) {
|
|
Packit |
76ec6a |
#ifdef HAVE_WNCK
|
|
Packit |
76ec6a |
case COL_MEMXSERVER:
|
|
Packit |
76ec6a |
#endif
|
|
Packit |
76ec6a |
case COL_VMSIZE:
|
|
Packit |
76ec6a |
case COL_MEMRES:
|
|
Packit |
76ec6a |
case COL_MEMSHARED:
|
|
Packit |
76ec6a |
case COL_MEM:
|
|
Packit |
76ec6a |
case COL_CPU:
|
|
Packit |
76ec6a |
case COL_CPU_TIME:
|
|
Packit |
76ec6a |
case COL_DISK_READ_TOTAL:
|
|
Packit |
76ec6a |
case COL_DISK_WRITE_TOTAL:
|
|
Packit |
76ec6a |
case COL_DISK_READ_CURRENT:
|
|
Packit |
76ec6a |
case COL_DISK_WRITE_CURRENT:
|
|
Packit |
76ec6a |
case COL_START_TIME:
|
|
Packit |
76ec6a |
gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (model_sort), i,
|
|
Packit |
76ec6a |
procman::number_compare_func,
|
|
Packit |
76ec6a |
GUINT_TO_POINTER (i),
|
|
Packit |
76ec6a |
NULL);
|
|
Packit |
76ec6a |
break;
|
|
Packit |
76ec6a |
case COL_PRIORITY:
|
|
Packit |
76ec6a |
gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (model_sort), i,
|
|
Packit |
76ec6a |
procman::priority_compare_func,
|
|
Packit |
76ec6a |
GUINT_TO_POINTER (COL_NICE), NULL);
|
|
Packit |
76ec6a |
break;
|
|
Packit |
76ec6a |
default:
|
|
Packit |
76ec6a |
break;
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
// xalign
|
|
Packit |
76ec6a |
switch(i)
|
|
Packit |
76ec6a |
{
|
|
Packit |
76ec6a |
case COL_VMSIZE:
|
|
Packit |
76ec6a |
case COL_MEMRES:
|
|
Packit |
76ec6a |
case COL_MEMSHARED:
|
|
Packit |
76ec6a |
#ifdef HAVE_WNCK
|
|
Packit |
76ec6a |
case COL_MEMXSERVER:
|
|
Packit |
76ec6a |
#endif
|
|
Packit |
76ec6a |
case COL_CPU:
|
|
Packit |
76ec6a |
case COL_NICE:
|
|
Packit |
76ec6a |
case COL_PID:
|
|
Packit |
76ec6a |
case COL_DISK_READ_TOTAL:
|
|
Packit |
76ec6a |
case COL_DISK_WRITE_TOTAL:
|
|
Packit |
76ec6a |
case COL_DISK_READ_CURRENT:
|
|
Packit |
76ec6a |
case COL_DISK_WRITE_CURRENT:
|
|
Packit |
76ec6a |
case COL_CPU_TIME:
|
|
Packit |
76ec6a |
case COL_MEM:
|
|
Packit |
76ec6a |
g_object_set(G_OBJECT(cell), "xalign", 1.0f, NULL);
|
|
Packit |
76ec6a |
break;
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
gtk_tree_view_column_set_sizing(col, GTK_TREE_VIEW_COLUMN_FIXED);
|
|
Packit |
76ec6a |
// sizing
|
|
Packit |
76ec6a |
switch (i) {
|
|
Packit |
76ec6a |
case COL_ARGS:
|
|
Packit |
76ec6a |
gtk_tree_view_column_set_min_width(col, 150);
|
|
Packit |
76ec6a |
break;
|
|
Packit |
76ec6a |
default:
|
|
Packit |
76ec6a |
gtk_tree_view_column_set_min_width(column, 20);
|
|
Packit |
76ec6a |
break;
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
app->tree = proctree;
|
|
Packit |
76ec6a |
app->top_of_tree = NULL;
|
|
Packit |
76ec6a |
app->last_vscroll_max = 0;
|
|
Packit |
76ec6a |
app->last_vscroll_value = 0;
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
if (!cgroups_enabled ())
|
|
Packit |
76ec6a |
gsm_tree_view_add_excluded_column (proctree, COL_CGROUP);
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
if (!procman::systemd_logind_running())
|
|
Packit |
76ec6a |
{
|
|
Packit |
76ec6a |
gsm_tree_view_add_excluded_column (proctree, COL_UNIT);
|
|
Packit |
76ec6a |
gsm_tree_view_add_excluded_column (proctree, COL_SESSION);
|
|
Packit |
76ec6a |
gsm_tree_view_add_excluded_column (proctree, COL_SEAT);
|
|
Packit |
76ec6a |
gsm_tree_view_add_excluded_column (proctree, COL_OWNER);
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
if (!can_show_security_context_column ())
|
|
Packit |
76ec6a |
gsm_tree_view_add_excluded_column (proctree, COL_SECURITYCONTEXT);
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
gsm_tree_view_load_state (proctree);
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
GtkIconTheme* theme = gtk_icon_theme_get_default();
|
|
Packit |
76ec6a |
g_signal_connect(G_OBJECT (theme), "changed", G_CALLBACK (cb_refresh_icons), app);
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
app->selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (proctree));
|
|
Packit |
76ec6a |
gtk_tree_selection_set_mode (app->selection, GTK_SELECTION_MULTIPLE);
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
g_signal_connect (G_OBJECT (app->selection),
|
|
Packit |
76ec6a |
"changed",
|
|
Packit |
76ec6a |
G_CALLBACK (cb_row_selected), app);
|
|
Packit |
76ec6a |
g_signal_connect (G_OBJECT (proctree), "popup_menu",
|
|
Packit |
76ec6a |
G_CALLBACK (cb_tree_popup_menu), app);
|
|
Packit |
76ec6a |
g_signal_connect (G_OBJECT (proctree), "button_press_event",
|
|
Packit |
76ec6a |
G_CALLBACK (cb_tree_button_pressed), app);
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
g_signal_connect (G_OBJECT (proctree), "destroy",
|
|
Packit |
76ec6a |
G_CALLBACK (cb_proctree_destroying),
|
|
Packit |
76ec6a |
app);
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
g_signal_connect (G_OBJECT (proctree), "columns-changed",
|
|
Packit |
76ec6a |
G_CALLBACK (cb_save_tree_state), app);
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
g_signal_connect (G_OBJECT (model_sort), "sort-column-changed",
|
|
Packit |
76ec6a |
G_CALLBACK (cb_save_tree_state), app);
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
app->settings->signal_changed(GSM_SETTING_SHOW_DEPENDENCIES).connect([app](const Glib::ustring& key) {
|
|
Packit |
76ec6a |
cb_show_dependencies_changed(*app->settings.operator->(), key, app);
|
|
Packit |
76ec6a |
});
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
app->settings->signal_changed(GSM_SETTING_SHOW_WHOSE_PROCESSES).connect([app](const Glib::ustring& key) {
|
|
Packit |
76ec6a |
cb_show_whose_processes_changed(*app->settings.operator->(), key, app);
|
|
Packit |
76ec6a |
});
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
gtk_widget_show (GTK_WIDGET (proctree));
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
return proctree;
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
static void
|
|
Packit |
76ec6a |
get_process_name (ProcInfo *info,
|
|
Packit |
76ec6a |
const gchar *cmd, const GStrv args)
|
|
Packit |
76ec6a |
{
|
|
Packit |
76ec6a |
if (args) {
|
|
Packit |
76ec6a |
// look for /usr/bin/very_long_name
|
|
Packit |
76ec6a |
// and also /usr/bin/interpreter /usr/.../very_long_name
|
|
Packit |
76ec6a |
// which may have use prctl to alter 'cmd' name
|
|
Packit |
76ec6a |
for (int i = 0; i != 2 && args[i]; ++i) {
|
|
Packit |
76ec6a |
char* basename;
|
|
Packit |
76ec6a |
basename = g_path_get_basename(args[i]);
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
if (g_str_has_prefix(basename, cmd)) {
|
|
Packit |
76ec6a |
info->name = make_string(basename);
|
|
Packit |
76ec6a |
return;
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
g_free(basename);
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
info->name = cmd;
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
std::string
|
|
Packit |
76ec6a |
ProcInfo::lookup_user(guint uid)
|
|
Packit |
76ec6a |
{
|
|
Packit |
76ec6a |
static std::map<guint, std::string> users;
|
|
Packit |
76ec6a |
auto p = users.insert({uid, ""});
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
// procman_debug("User lookup for uid %u: %s", uid, (p.second ? "MISS" : "HIT"));
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
if (p.second) {
|
|
Packit |
76ec6a |
struct passwd* pwd;
|
|
Packit |
76ec6a |
pwd = getpwuid(uid);
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
if (pwd && pwd->pw_name)
|
|
Packit |
76ec6a |
p.first->second = pwd->pw_name;
|
|
Packit |
76ec6a |
else {
|
|
Packit |
76ec6a |
char username[16];
|
|
Packit |
76ec6a |
g_sprintf(username, "%u", uid);
|
|
Packit |
76ec6a |
p.first->second = username;
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
return p.first->second;
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
void
|
|
Packit |
76ec6a |
ProcInfo::set_user(guint uid)
|
|
Packit |
76ec6a |
{
|
|
Packit |
76ec6a |
if (G_LIKELY(this->uid == uid))
|
|
Packit |
76ec6a |
return;
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
this->uid = uid;
|
|
Packit |
76ec6a |
this->user = lookup_user(uid);
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
void
|
|
Packit |
76ec6a |
get_process_memory_writable (ProcInfo *info)
|
|
Packit |
76ec6a |
{
|
|
Packit |
76ec6a |
glibtop_proc_map buf;
|
|
Packit |
76ec6a |
glibtop_map_entry *maps;
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
maps = glibtop_get_proc_map(&buf, info->pid);
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
const bool use_private_dirty = buf.flags & (1 << GLIBTOP_MAP_ENTRY_PRIVATE_DIRTY);
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
gulong memwritable = 0;
|
|
Packit |
76ec6a |
const unsigned number = buf.number;
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
for (unsigned i = 0; i < number; ++i) {
|
|
Packit |
76ec6a |
if (use_private_dirty) {
|
|
Packit |
76ec6a |
// clang++ 3.4 is not smart enough to move this invariant out of the loop
|
|
Packit |
76ec6a |
// but who cares ?
|
|
Packit |
76ec6a |
memwritable += maps[i].private_dirty;
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
else if (maps[i].perm & GLIBTOP_MAP_PERM_WRITE) {
|
|
Packit |
76ec6a |
memwritable += maps[i].size;
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
info->memwritable = memwritable;
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
g_free(maps);
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
static void
|
|
Packit |
76ec6a |
get_process_memory_info(ProcInfo *info)
|
|
Packit |
76ec6a |
{
|
|
Packit |
76ec6a |
glibtop_proc_mem procmem;
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
#ifdef HAVE_WNCK
|
|
Packit |
76ec6a |
info->memxserver = 0;
|
|
Packit |
76ec6a |
#ifdef GDK_WINDOWING_X11
|
|
Packit |
76ec6a |
if (GDK_IS_X11_DISPLAY (gdk_display_get_default ())) {
|
|
Packit |
76ec6a |
WnckResourceUsage xresources;
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
wnck_pid_read_resource_usage (gdk_display_get_default (),
|
|
Packit |
76ec6a |
info->pid,
|
|
Packit |
76ec6a |
&xresources);
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
info->memxserver = xresources.total_bytes_estimate;
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
#endif
|
|
Packit |
76ec6a |
#endif
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
glibtop_get_proc_mem(&procmem, info->pid);
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
info->vmsize = procmem.vsize;
|
|
Packit |
76ec6a |
info->memres = procmem.resident;
|
|
Packit |
76ec6a |
info->memshared = procmem.share;
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
info->mem = info->memres - info->memshared;
|
|
Packit |
76ec6a |
#ifdef HAVE_WNCK
|
|
Packit |
76ec6a |
info->mem += info->memxserver;
|
|
Packit |
76ec6a |
#endif
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
static void
|
|
Packit |
76ec6a |
update_info_mutable_cols(ProcInfo *info)
|
|
Packit |
76ec6a |
{
|
|
Packit |
76ec6a |
GtkTreeModel *model;
|
|
Packit |
76ec6a |
model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (
|
|
Packit |
76ec6a |
gtk_tree_model_sort_get_model(GTK_TREE_MODEL_SORT(
|
|
Packit |
76ec6a |
gtk_tree_view_get_model (GTK_TREE_VIEW(GsmApplication::get()->tree))))));
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
using procman::tree_store_update;
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
tree_store_update(model, &info->node, COL_STATUS, info->status);
|
|
Packit |
76ec6a |
tree_store_update(model, &info->node, COL_USER, info->user.c_str());
|
|
Packit |
76ec6a |
tree_store_update(model, &info->node, COL_VMSIZE, info->vmsize);
|
|
Packit |
76ec6a |
tree_store_update(model, &info->node, COL_MEMRES, info->memres);
|
|
Packit |
76ec6a |
tree_store_update(model, &info->node, COL_MEMSHARED, info->memshared);
|
|
Packit |
76ec6a |
#ifdef HAVE_WNCK
|
|
Packit |
76ec6a |
tree_store_update(model, &info->node, COL_MEMXSERVER, info->memxserver);
|
|
Packit |
76ec6a |
#endif
|
|
Packit |
76ec6a |
tree_store_update(model, &info->node, COL_CPU, info->pcpu);
|
|
Packit |
76ec6a |
tree_store_update(model, &info->node, COL_CPU_TIME, info->cpu_time);
|
|
Packit |
76ec6a |
tree_store_update(model, &info->node, COL_DISK_READ_TOTAL, info->disk_read_bytes_total);
|
|
Packit |
76ec6a |
tree_store_update(model, &info->node, COL_DISK_WRITE_TOTAL, info->disk_write_bytes_total);
|
|
Packit |
76ec6a |
tree_store_update(model, &info->node, COL_DISK_READ_CURRENT, info->disk_read_bytes_current);
|
|
Packit |
76ec6a |
tree_store_update(model, &info->node, COL_DISK_WRITE_CURRENT, info->disk_write_bytes_current);
|
|
Packit |
76ec6a |
tree_store_update(model, &info->node, COL_START_TIME, info->start_time);
|
|
Packit |
76ec6a |
tree_store_update(model, &info->node, COL_NICE, info->nice);
|
|
Packit |
76ec6a |
tree_store_update(model, &info->node, COL_MEM, info->mem);
|
|
Packit |
76ec6a |
tree_store_update(model, &info->node, COL_WCHAN, info->wchan.c_str());
|
|
Packit |
76ec6a |
tree_store_update(model, &info->node, COL_CGROUP, info->cgroup_name.c_str());
|
|
Packit |
76ec6a |
tree_store_update(model, &info->node, COL_UNIT, info->unit.c_str());
|
|
Packit |
76ec6a |
tree_store_update(model, &info->node, COL_SESSION, info->session.c_str());
|
|
Packit |
76ec6a |
tree_store_update(model, &info->node, COL_SEAT, info->seat.c_str());
|
|
Packit |
76ec6a |
tree_store_update(model, &info->node, COL_OWNER, info->owner.c_str());
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
static void
|
|
Packit |
76ec6a |
insert_info_to_tree (ProcInfo *info, GsmApplication *app, bool forced = false)
|
|
Packit |
76ec6a |
{
|
|
Packit |
76ec6a |
GtkTreeModel *model;
|
|
Packit |
76ec6a |
GtkTreeModel *filtered;
|
|
Packit |
76ec6a |
GtkTreeModel *sorted;
|
|
Packit |
76ec6a |
sorted = gtk_tree_view_get_model (GTK_TREE_VIEW(app->tree));
|
|
Packit |
76ec6a |
filtered = gtk_tree_model_sort_get_model(GTK_TREE_MODEL_SORT(sorted));
|
|
Packit |
76ec6a |
model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (filtered));
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
if (app->settings->get_boolean (GSM_SETTING_SHOW_DEPENDENCIES)) {
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
ProcInfo *parent = 0;
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
if (not forced)
|
|
Packit |
76ec6a |
parent = app->processes.find(info->ppid);
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
if (parent) {
|
|
Packit |
76ec6a |
GtkTreePath *parent_node = gtk_tree_model_get_path(model, &parent->node);
|
|
Packit |
76ec6a |
gtk_tree_store_insert(GTK_TREE_STORE(model), &info->node, &parent->node, 0);
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
GtkTreePath *filtered_parent = gtk_tree_model_filter_convert_child_path_to_path (GTK_TREE_MODEL_FILTER (filtered), parent_node);
|
|
Packit |
76ec6a |
if (filtered_parent != NULL) {
|
|
Packit |
76ec6a |
GtkTreePath *sorted_parent = gtk_tree_model_sort_convert_child_path_to_path (GTK_TREE_MODEL_SORT (sorted), filtered_parent);
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
if (sorted_parent != NULL) {
|
|
Packit |
76ec6a |
if (!gtk_tree_view_row_expanded(GTK_TREE_VIEW(app->tree), sorted_parent)
|
|
Packit |
76ec6a |
#ifdef __linux__
|
|
Packit |
76ec6a |
// on linuxes we don't want to expand kthreadd by default (always has pid 2)
|
|
Packit |
76ec6a |
&& (parent->pid != 2)
|
|
Packit |
76ec6a |
#endif
|
|
Packit |
76ec6a |
)
|
|
Packit |
76ec6a |
gtk_tree_view_expand_row(GTK_TREE_VIEW(app->tree), sorted_parent, FALSE);
|
|
Packit |
76ec6a |
gtk_tree_path_free (sorted_parent);
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
gtk_tree_path_free (filtered_parent);
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
gtk_tree_path_free (parent_node);
|
|
Packit |
76ec6a |
} else
|
|
Packit |
76ec6a |
gtk_tree_store_insert(GTK_TREE_STORE(model), &info->node, NULL, 0);
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
else
|
|
Packit |
76ec6a |
gtk_tree_store_insert (GTK_TREE_STORE (model), &info->node, NULL, 0);
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
gtk_tree_store_set (GTK_TREE_STORE (model), &info->node,
|
|
Packit |
76ec6a |
COL_POINTER, info,
|
|
Packit |
76ec6a |
COL_NAME, info->name.c_str(),
|
|
Packit |
76ec6a |
COL_ARGS, info->arguments.c_str(),
|
|
Packit |
76ec6a |
COL_TOOLTIP, info->tooltip.c_str(),
|
|
Packit |
76ec6a |
COL_PID, info->pid,
|
|
Packit |
76ec6a |
COL_SECURITYCONTEXT, info->security_context.c_str(),
|
|
Packit |
76ec6a |
-1);
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
app->pretty_table->set_icon(*info);
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
procman_debug("inserted %d%s", info->pid, (forced ? " (forced)" : ""));
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
/* Removing a node with children - make sure the children are queued
|
|
Packit |
76ec6a |
** to be readded.
|
|
Packit |
76ec6a |
*/
|
|
Packit |
76ec6a |
template<typename List>
|
|
Packit |
76ec6a |
static void
|
|
Packit |
76ec6a |
remove_info_from_tree (GsmApplication *app, GtkTreeModel *model,
|
|
Packit |
76ec6a |
ProcInfo& current, List &orphans, unsigned lvl = 0)
|
|
Packit |
76ec6a |
{
|
|
Packit |
76ec6a |
GtkTreeIter child_node;
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
if (std::find(orphans.begin(), orphans.end(), ¤t) != orphans.end()) {
|
|
Packit |
76ec6a |
procman_debug("[%u] %d already removed from tree", lvl, int(current.pid));
|
|
Packit |
76ec6a |
return;
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
procman_debug("[%u] pid %d, %d children", lvl, int(current.pid),
|
|
Packit |
76ec6a |
gtk_tree_model_iter_n_children(model, ¤t.node));
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
// it is not possible to iterate&erase over a treeview so instead we
|
|
Packit |
76ec6a |
// just pop one child after another and recursively remove it and
|
|
Packit |
76ec6a |
// its children
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
while (gtk_tree_model_iter_children(model, &child_node, ¤t.node)) {
|
|
Packit |
76ec6a |
ProcInfo *child = 0;
|
|
Packit |
76ec6a |
gtk_tree_model_get(model, &child_node, COL_POINTER, &child, -1);
|
|
Packit |
76ec6a |
remove_info_from_tree(app, model, *child, orphans, lvl + 1);
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
g_assert(not gtk_tree_model_iter_has_child(model, ¤t.node));
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
orphans.push_back(¤t;;
|
|
Packit |
76ec6a |
gtk_tree_store_remove(GTK_TREE_STORE(model), ¤t.node);
|
|
Packit |
76ec6a |
procman::poison(current.node, 0x69);
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
static std::string
|
|
Packit |
76ec6a |
get_proc_kernel_wchan(glibtop_proc_kernel& obj) {
|
|
Packit |
76ec6a |
char buf[40] = {0};
|
|
Packit |
76ec6a |
g_strlcpy(buf, obj.wchan, sizeof(buf));
|
|
Packit |
76ec6a |
buf[sizeof(buf)-1] = '\0';
|
|
Packit |
76ec6a |
return buf;
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
static void
|
|
Packit |
76ec6a |
update_info (GsmApplication *app, ProcInfo *info)
|
|
Packit |
76ec6a |
{
|
|
Packit |
76ec6a |
glibtop_proc_state procstate;
|
|
Packit |
76ec6a |
glibtop_proc_uid procuid;
|
|
Packit |
76ec6a |
glibtop_proc_time proctime;
|
|
Packit |
76ec6a |
glibtop_proc_kernel prockernel;
|
|
Packit |
76ec6a |
glibtop_proc_io procio;
|
|
Packit |
76ec6a |
gdouble update_interval_seconds = app->config.update_interval / 1000;
|
|
Packit |
76ec6a |
glibtop_get_proc_kernel(&prockernel, info->pid);
|
|
Packit |
76ec6a |
info->wchan = get_proc_kernel_wchan(prockernel);
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
glibtop_get_proc_state (&procstate, info->pid);
|
|
Packit |
76ec6a |
info->status = procstate.state;
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
glibtop_get_proc_uid (&procuid, info->pid);
|
|
Packit |
76ec6a |
glibtop_get_proc_time (&proctime, info->pid);
|
|
Packit |
76ec6a |
glibtop_get_proc_io (&procio, info->pid);
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
get_process_memory_info(info);
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
info->set_user(procstate.uid);
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
// if the cpu time has increased reset the status to running
|
|
Packit |
76ec6a |
// regardless of kernel state (#606579)
|
|
Packit |
76ec6a |
guint64 difference = proctime.rtime - info->cpu_time;
|
|
Packit |
76ec6a |
if (difference > 0)
|
|
Packit |
76ec6a |
info->status = GLIBTOP_PROCESS_RUNNING;
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
guint cpu_scale = 100;
|
|
Packit |
76ec6a |
if (not app->config.solaris_mode)
|
|
Packit |
76ec6a |
cpu_scale *= app->config.num_cpus;
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
info->pcpu = difference * cpu_scale / app->cpu_total_time;
|
|
Packit |
76ec6a |
info->pcpu = MIN(info->pcpu, cpu_scale);
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
app->processes.cpu_times[info->pid] = info->cpu_time = proctime.rtime;
|
|
Packit |
76ec6a |
info->nice = procuid.nice;
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
info->disk_write_bytes_current = (procio.disk_wbytes - info->disk_write_bytes_total)/update_interval_seconds;
|
|
Packit |
76ec6a |
info->disk_read_bytes_current = (procio.disk_rbytes - info->disk_read_bytes_total)/update_interval_seconds;
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
info->disk_write_bytes_total = procio.disk_wbytes;
|
|
Packit |
76ec6a |
info->disk_read_bytes_total = procio.disk_rbytes;
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
// set the ppid only if one can exist
|
|
Packit |
76ec6a |
// i.e. pid=0 can never have a parent
|
|
Packit |
76ec6a |
if (info->pid > 0) {
|
|
Packit |
76ec6a |
info->ppid = procuid.ppid;
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
g_assert(info->pid != info->ppid);
|
|
Packit |
76ec6a |
g_assert(info->ppid != -1 || info->pid == 0);
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
/* get cgroup data */
|
|
Packit |
76ec6a |
get_process_cgroup_info(*info);
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
procman::get_process_systemd_info(info);
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
ProcInfo::ProcInfo(pid_t pid)
|
|
Packit |
76ec6a |
: node(),
|
|
Packit |
76ec6a |
pixbuf(),
|
|
Packit |
76ec6a |
pid(pid),
|
|
Packit |
76ec6a |
ppid(-1),
|
|
Packit |
76ec6a |
uid(-1)
|
|
Packit |
76ec6a |
{
|
|
Packit |
76ec6a |
ProcInfo * const info = this;
|
|
Packit |
76ec6a |
glibtop_proc_state procstate;
|
|
Packit |
76ec6a |
glibtop_proc_time proctime;
|
|
Packit |
76ec6a |
glibtop_proc_args procargs;
|
|
Packit |
76ec6a |
gchar** arguments;
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
glibtop_get_proc_state (&procstate, pid);
|
|
Packit |
76ec6a |
glibtop_get_proc_time (&proctime, pid);
|
|
Packit |
76ec6a |
arguments = glibtop_get_proc_argv (&procargs, pid, 0);
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
/* FIXME : wrong. name and arguments may change with exec* */
|
|
Packit |
76ec6a |
get_process_name (info, procstate.cmd, static_cast<const GStrv>(arguments));
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
std::string tooltip = make_string(g_strjoinv(" ", arguments));
|
|
Packit |
76ec6a |
if (tooltip.empty())
|
|
Packit |
76ec6a |
tooltip = procstate.cmd;
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
info->tooltip = make_string(g_markup_escape_text(tooltip.c_str(), -1));
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
info->arguments = make_string(g_strescape(tooltip.c_str(), "\\\""));
|
|
Packit |
76ec6a |
g_strfreev(arguments);
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
guint64 cpu_time = proctime.rtime;
|
|
Packit |
76ec6a |
auto app = GsmApplication::get();
|
|
Packit |
76ec6a |
auto it = app->processes.cpu_times.find(pid);
|
|
Packit |
76ec6a |
if (it != app->processes.cpu_times.end())
|
|
Packit |
76ec6a |
{
|
|
Packit |
76ec6a |
if (proctime.rtime >= it->second)
|
|
Packit |
76ec6a |
cpu_time = it->second;
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
info->cpu_time = cpu_time;
|
|
Packit |
76ec6a |
info->start_time = proctime.start_time;
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
get_process_selinux_context (info);
|
|
Packit |
76ec6a |
get_process_cgroup_info(*info);
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
get_process_systemd_info(info);
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
static void
|
|
Packit |
76ec6a |
refresh_list (GsmApplication *app, const pid_t* pid_list, const guint n)
|
|
Packit |
76ec6a |
{
|
|
Packit |
76ec6a |
typedef std::list<ProcInfo*> ProcList;
|
|
Packit |
76ec6a |
ProcList addition;
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
GtkTreeModel *model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (
|
|
Packit |
76ec6a |
gtk_tree_model_sort_get_model(GTK_TREE_MODEL_SORT (
|
|
Packit |
76ec6a |
gtk_tree_view_get_model (GTK_TREE_VIEW(app->tree))))));
|
|
Packit |
76ec6a |
guint i;
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
// Add or update processes in the process list
|
|
Packit |
76ec6a |
for(i = 0; i < n; ++i) {
|
|
Packit |
76ec6a |
ProcInfo *info = app->processes.find(pid_list[i]);
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
if (!info) {
|
|
Packit |
76ec6a |
info = app->processes.add(pid_list[i]);
|
|
Packit |
76ec6a |
addition.push_back(info);
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
update_info (app, info);
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
// Remove dead processes from the process list and from the
|
|
Packit |
76ec6a |
// tree. children are queued to be readded at the right place
|
|
Packit |
76ec6a |
// in the tree.
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
const std::set<pid_t> pids(pid_list, pid_list + n);
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
auto it = std::begin(app->processes);
|
|
Packit |
76ec6a |
while (it != std::end(app->processes)) {
|
|
Packit |
76ec6a |
auto& info = it->second;
|
|
Packit |
76ec6a |
if (pids.find(info.pid) == pids.end()) {
|
|
Packit |
76ec6a |
procman_debug("ripping %d", info.pid);
|
|
Packit |
76ec6a |
remove_info_from_tree(app, model, info, addition);
|
|
Packit |
76ec6a |
addition.remove(&info;;
|
|
Packit |
76ec6a |
it = app->processes.erase(it);
|
|
Packit |
76ec6a |
} else {
|
|
Packit |
76ec6a |
++it;
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
// INVARIANT
|
|
Packit |
76ec6a |
// pid_list == ProcInfo::all + addition
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
if (app->settings->get_boolean (GSM_SETTING_SHOW_DEPENDENCIES)) {
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
// insert process in the tree. walk through the addition list
|
|
Packit |
76ec6a |
// (new process + process that have a new parent). This loop
|
|
Packit |
76ec6a |
// handles the dependencies because we cannot insert a process
|
|
Packit |
76ec6a |
// until its parent is in the tree.
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
std::set<pid_t> in_tree(pids);
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
for (ProcList::iterator it(addition.begin()); it != addition.end(); ++it)
|
|
Packit |
76ec6a |
in_tree.erase((*it)->pid);
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
while (not addition.empty()) {
|
|
Packit |
76ec6a |
procman_debug("looking for %d parents", int(addition.size()));
|
|
Packit |
76ec6a |
ProcList::iterator it(addition.begin());
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
while (it != addition.end()) {
|
|
Packit |
76ec6a |
procman_debug("looking for %d's parent with ppid %d",
|
|
Packit |
76ec6a |
int((*it)->pid), int((*it)->ppid));
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
// inserts the process in the treeview if :
|
|
Packit |
76ec6a |
// - it has no parent (ppid = -1),
|
|
Packit |
76ec6a |
// ie it is for example the [kernel] on FreeBSD
|
|
Packit |
76ec6a |
// - it is init
|
|
Packit |
76ec6a |
// - its parent is already in tree
|
|
Packit |
76ec6a |
// - its parent is unreachable
|
|
Packit |
76ec6a |
//
|
|
Packit |
76ec6a |
// rounds == 2 means that addition contains processes with
|
|
Packit |
76ec6a |
// unreachable parents
|
|
Packit |
76ec6a |
//
|
|
Packit |
76ec6a |
// FIXME: this is broken if the unreachable parent becomes active
|
|
Packit |
76ec6a |
// i.e. it gets active or changes ower
|
|
Packit |
76ec6a |
// so we just clear the tree on __each__ update
|
|
Packit |
76ec6a |
// see proctable_update (ProcData * const procdata)
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
if ((*it)->ppid <= 0 or in_tree.find((*it)->ppid) != in_tree.end()) {
|
|
Packit |
76ec6a |
insert_info_to_tree(*it, app);
|
|
Packit |
76ec6a |
in_tree.insert((*it)->pid);
|
|
Packit |
76ec6a |
it = addition.erase(it);
|
|
Packit |
76ec6a |
continue;
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
ProcInfo *parent = app->processes.find((*it)->ppid);
|
|
Packit |
76ec6a |
// if the parent is unreachable
|
|
Packit |
76ec6a |
if (not parent) {
|
|
Packit |
76ec6a |
// or std::find(addition.begin(), addition.end(), parent) == addition.end()) {
|
|
Packit |
76ec6a |
insert_info_to_tree(*it, app, true);
|
|
Packit |
76ec6a |
in_tree.insert((*it)->pid);
|
|
Packit |
76ec6a |
it = addition.erase(it);
|
|
Packit |
76ec6a |
continue;
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
++it;
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
else {
|
|
Packit |
76ec6a |
// don't care of the tree
|
|
Packit |
76ec6a |
for (auto& v : addition) insert_info_to_tree(v, app);
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
for (auto& v : app->processes) update_info_mutable_cols(&v.second);
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
void
|
|
Packit |
76ec6a |
proctable_update (GsmApplication *app)
|
|
Packit |
76ec6a |
{
|
|
Packit |
76ec6a |
pid_t* pid_list;
|
|
Packit |
76ec6a |
glibtop_proclist proclist;
|
|
Packit |
76ec6a |
glibtop_cpu cpu;
|
|
Packit |
76ec6a |
int which = 0;
|
|
Packit |
76ec6a |
int arg = 0;
|
|
Packit |
76ec6a |
auto whose_processes = app->settings->get_string(GSM_SETTING_SHOW_WHOSE_PROCESSES);
|
|
Packit |
76ec6a |
if (whose_processes == "all") {
|
|
Packit |
76ec6a |
which = GLIBTOP_KERN_PROC_ALL;
|
|
Packit |
76ec6a |
arg = 0;
|
|
Packit |
76ec6a |
} else if (whose_processes == "active") {
|
|
Packit |
76ec6a |
which = GLIBTOP_KERN_PROC_ALL | GLIBTOP_EXCLUDE_IDLE;
|
|
Packit |
76ec6a |
arg = 0;
|
|
Packit |
76ec6a |
} else if (whose_processes == "user") {
|
|
Packit |
76ec6a |
which = GLIBTOP_KERN_PROC_UID;
|
|
Packit |
76ec6a |
arg = getuid ();
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
pid_list = glibtop_get_proclist (&proclist, which, arg);
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
/* FIXME: total cpu time elapsed should be calculated on an individual basis here
|
|
Packit |
76ec6a |
** should probably have a total_time_last gint in the ProcInfo structure */
|
|
Packit |
76ec6a |
glibtop_get_cpu (&cpu);
|
|
Packit |
76ec6a |
app->cpu_total_time = MAX(cpu.total - app->cpu_total_time_last, 1);
|
|
Packit |
76ec6a |
app->cpu_total_time_last = cpu.total;
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
// FIXME: not sure if glibtop always returns a sorted list of pid
|
|
Packit |
76ec6a |
// but it is important otherwise refresh_list won't find the parent
|
|
Packit |
76ec6a |
std::sort(pid_list, pid_list + proclist.number);
|
|
Packit |
76ec6a |
refresh_list (app, pid_list, proclist.number);
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
// juggling with tree scroll position to fix https://bugzilla.gnome.org/show_bug.cgi?id=92724
|
|
Packit |
76ec6a |
GtkTreePath* current_top;
|
|
Packit |
76ec6a |
if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(app->tree), 0,0, ¤t_top, NULL, NULL, NULL)) {
|
|
Packit |
76ec6a |
GtkAdjustment *vadjustment = GTK_ADJUSTMENT (gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (app->tree)));
|
|
Packit |
76ec6a |
gdouble current_max = gtk_adjustment_get_upper(vadjustment);
|
|
Packit |
76ec6a |
gdouble current_value = gtk_adjustment_get_value(vadjustment);
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
if (app->top_of_tree) {
|
|
Packit |
76ec6a |
// if the visible cell from the top of the tree is still the same, as last time
|
|
Packit |
76ec6a |
if (gtk_tree_path_compare (app->top_of_tree, current_top) == 0) {
|
|
Packit |
76ec6a |
//but something from the scroll parameters has changed compared to the last values
|
|
Packit |
76ec6a |
if (app->last_vscroll_value == 0 && current_value != 0) {
|
|
Packit |
76ec6a |
// the tree was scrolled to top, and something has been added above the current top row
|
|
Packit |
76ec6a |
gtk_tree_view_scroll_to_point(GTK_TREE_VIEW(app->tree), -1, 0);
|
|
Packit |
76ec6a |
} else if (current_max > app->last_vscroll_max && app->last_vscroll_max == app->last_vscroll_value) {
|
|
Packit |
76ec6a |
// the tree was scrolled to bottom, something has been added below the current bottom row
|
|
Packit |
76ec6a |
gtk_tree_view_scroll_to_point(GTK_TREE_VIEW(app->tree), -1, current_max);
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
gtk_tree_path_free(app->top_of_tree);
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
app->top_of_tree = current_top;
|
|
Packit |
76ec6a |
app->last_vscroll_value = current_value;
|
|
Packit |
76ec6a |
app->last_vscroll_max = current_max;
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
g_free (pid_list);
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
/* proclist.number == g_list_length(procdata->info) == g_hash_table_size(procdata->pids) */
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
void
|
|
Packit |
76ec6a |
proctable_free_table (GsmApplication * const app)
|
|
Packit |
76ec6a |
{
|
|
Packit |
76ec6a |
app->processes.clear();
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
void
|
|
Packit |
76ec6a |
ProcInfo::set_icon(Glib::RefPtr<Gdk::Pixbuf> icon)
|
|
Packit |
76ec6a |
{
|
|
Packit |
76ec6a |
this->pixbuf = icon;
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
GtkTreeModel *model;
|
|
Packit |
76ec6a |
model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (
|
|
Packit |
76ec6a |
gtk_tree_model_sort_get_model(GTK_TREE_MODEL_SORT(
|
|
Packit |
76ec6a |
gtk_tree_view_get_model (GTK_TREE_VIEW(GsmApplication::get()->tree))))));
|
|
Packit |
76ec6a |
gtk_tree_store_set(GTK_TREE_STORE(model), &this->node,
|
|
Packit |
76ec6a |
COL_PIXBUF, (this->pixbuf ? this->pixbuf->gobj() : NULL),
|
|
Packit |
76ec6a |
-1);
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
void
|
|
Packit |
76ec6a |
proctable_freeze (GsmApplication *app)
|
|
Packit |
76ec6a |
{
|
|
Packit |
76ec6a |
if (app->timeout) {
|
|
Packit |
76ec6a |
g_source_remove (app->timeout);
|
|
Packit |
76ec6a |
app->timeout = 0;
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
void
|
|
Packit |
76ec6a |
proctable_thaw (GsmApplication *app)
|
|
Packit |
76ec6a |
{
|
|
Packit |
76ec6a |
if (app->timeout)
|
|
Packit |
76ec6a |
return;
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
app->timeout = g_timeout_add (app->config.update_interval,
|
|
Packit |
76ec6a |
cb_timeout,
|
|
Packit |
76ec6a |
app);
|
|
Packit |
76ec6a |
}
|
|
Packit |
76ec6a |
|
|
Packit |
76ec6a |
void
|
|
Packit |
76ec6a |
proctable_reset_timeout (GsmApplication *app)
|
|
Packit |
76ec6a |
{
|
|
Packit |
76ec6a |
proctable_freeze (app);
|
|
Packit |
76ec6a |
proctable_thaw (app);
|
|
Packit |
76ec6a |
}
|