1 /* -*- mode: C; c-file-style: "linux" -*- */
3 /* MemProf -- memory profiler and leak detector
4 * Copyright 1999, 2000, 2001, Red Hat, Inc.
5 * Copyright 2002, Kristian Rietveld
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 #include <glade/glade.h>
24 #include <glib/gi18n.h>
27 #include "treeviewutils.h"
29 static ProcessWindow
*iter_get_process_window (GtkTreeIter
*iter
);
38 static GtkWidget
*tree_window
;
39 static GtkWidget
*tree_view
;
40 static GtkTreeStore
*store
;
42 extern char *glade_file
;
45 make_menu_item (const char *label
, GCallback cb
)
47 GtkWidget
*menu_item
= gtk_menu_item_new_with_label (label
);
48 g_signal_connect (menu_item
, "activate", cb
, NULL
);
49 gtk_widget_show (menu_item
);
54 static ProcessWindow
*
55 get_process_window (GtkWidget
*menu_item
)
57 return g_object_get_data (G_OBJECT (menu_item
->parent
), "process-window");
61 show_cb (GtkWidget
*widget
)
63 ProcessWindow
*pwin
= get_process_window (widget
);
65 process_window_show (pwin
);
69 hide_cb (GtkWidget
*widget
)
71 ProcessWindow
*pwin
= get_process_window (widget
);
73 process_window_hide (pwin
);
77 tree_detach_cb (GtkWidget
*widget
)
79 ProcessWindow
*pwin
= get_process_window (widget
);
81 process_window_maybe_detach (pwin
);
85 tree_kill_cb (GtkWidget
*widget
)
87 ProcessWindow
*pwin
= get_process_window (widget
);
89 process_window_maybe_kill (pwin
);
93 popup_menu (ProcessWindow
*pwin
, gint button
, guint32 time
)
95 static GtkWidget
*menu
= NULL
;
96 static GtkWidget
*show_item
= NULL
;
97 static GtkWidget
*hide_item
= NULL
;
100 menu
= gtk_menu_new ();
102 show_item
= make_menu_item (_("Show"), G_CALLBACK (show_cb
));
103 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), show_item
);
105 hide_item
= make_menu_item (_("Hide"), G_CALLBACK (hide_cb
));
106 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), hide_item
);
108 gtk_menu_shell_append (GTK_MENU_SHELL (menu
),
109 make_menu_item (_("Kill"), G_CALLBACK (tree_kill_cb
)));
111 gtk_menu_shell_append (GTK_MENU_SHELL (menu
),
112 make_menu_item (_("Detach"), G_CALLBACK (tree_detach_cb
)));
115 if (process_window_visible (pwin
)) {
116 gtk_widget_set_sensitive (show_item
, FALSE
);
117 gtk_widget_set_sensitive (hide_item
, TRUE
);
119 gtk_widget_set_sensitive (show_item
, TRUE
);
120 gtk_widget_set_sensitive (hide_item
, FALSE
);
123 g_object_set_data (G_OBJECT (menu
), "process-window", pwin
);
124 gtk_menu_popup (GTK_MENU (menu
), NULL
, NULL
, NULL
, NULL
, button
, time
);
128 button_press_cb (GtkWidget
*widget
, GdkEventButton
*event
, gpointer data
)
130 GtkTreeView
*tree_view
= GTK_TREE_VIEW (widget
);
131 GtkTreeModel
*model
= GTK_TREE_MODEL (store
);
134 if (event
->button
== 3 &&
135 event
->window
== gtk_tree_view_get_bin_window (tree_view
) &&
136 gtk_tree_view_get_path_at_pos (tree_view
,
138 &path
, NULL
, NULL
, NULL
)) {
141 gtk_tree_model_get_iter (model
, &iter
, path
);
142 popup_menu (iter_get_process_window (&iter
), event
->button
, event
->time
);
149 row_activated_cb (GtkTreeView
*tree_view
,
151 GtkTreeViewColumn
*column
)
153 GtkTreeModel
*model
= GTK_TREE_MODEL (store
);
156 gtk_tree_model_get_iter (model
, &iter
, path
);
157 process_window_show (iter_get_process_window (&iter
));
161 ensure_tree_window (void)
164 GladeXML
*xml
= glade_xml_new (glade_file
, "TreeWindow", NULL
);
166 tree_window
= glade_xml_get_widget (xml
, "TreeWindow");
167 gtk_window_set_default_size (GTK_WINDOW (tree_window
), 400, 300);
168 g_signal_connect (tree_window
, "delete_event",
169 G_CALLBACK (hide_and_check_quit
), NULL
);
171 tree_view
= glade_xml_get_widget (xml
, "TreeWindow-tree-view");
173 store
= gtk_tree_store_new (4,
174 G_TYPE_INT
, /* PID_COLUMN */
175 G_TYPE_STRING
, /* CMDLINE_COLUMN */
176 G_TYPE_STRING
, /* STATUS_COLUMN */
177 G_TYPE_POINTER
/* PWIN_COLUMN */);
178 gtk_tree_view_set_model (GTK_TREE_VIEW (tree_view
), GTK_TREE_MODEL (store
));
180 add_plain_text_column (GTK_TREE_VIEW (tree_view
), _("PID"), PID_COLUMN
);
181 add_plain_text_column (GTK_TREE_VIEW (tree_view
), _("Command Line"), CMDLINE_COLUMN
);
182 add_plain_text_column (GTK_TREE_VIEW (tree_view
), _("Status"), STATUS_COLUMN
);
184 g_signal_connect (tree_view
, "button_press_event",
185 G_CALLBACK (button_press_cb
), NULL
);
186 g_signal_connect (tree_view
, "row_activated",
187 G_CALLBACK (row_activated_cb
), NULL
);
192 tree_window_show (void)
194 ensure_tree_window ();
196 gtk_widget_show (tree_window
);
197 gdk_window_show (tree_window
->window
); /* Raise */
200 static ProcessWindow
*
201 iter_get_process_window (GtkTreeIter
*iter
)
203 GtkTreeModel
*model
= GTK_TREE_MODEL (store
);
206 gtk_tree_model_get (model
, iter
, PWIN_COLUMN
, &pwin
, -1);
212 iter_set_process_window (GtkTreeIter
*iter
,
215 gtk_tree_store_set (store
, iter
, PWIN_COLUMN
, pwin
, -1);
219 find_by_process_recurse (MPProcess
*process
,
223 GtkTreeModel
*model
= GTK_TREE_MODEL (store
);
224 GtkTreeIter children
;
227 ProcessWindow
*pwin
= iter_get_process_window (parent
);
228 MPProcess
*row_process
= process_window_get_process (pwin
);
230 if (row_process
== process
) {
236 if (gtk_tree_model_iter_children (model
, &children
, parent
)) {
238 if (find_by_process_recurse (process
, iter
, &children
))
240 } while (gtk_tree_model_iter_next (model
, &children
));
248 find_by_process (MPProcess
*process
,
251 return find_by_process_recurse (process
, iter
, NULL
);
255 update_process (GtkTreeIter
*iter
)
257 ProcessWindow
*pwin
= iter_get_process_window (iter
);
258 MPProcess
*process
= process_window_get_process (pwin
);
259 char *cmdline
= process_get_cmdline (process
);
260 char *status
= process_get_status_text (process
);
262 gtk_tree_store_set (store
, iter
,
263 PID_COLUMN
, (int)process
->pid
,
264 CMDLINE_COLUMN
, cmdline
,
265 STATUS_COLUMN
, status
,
273 status_changed_cb (MPProcess
*process
)
277 if (find_by_process (process
, &iter
))
278 update_process (&iter
);
282 tree_window_add (ProcessWindow
*window
)
285 GtkTreeIter
*parent
= NULL
;
286 GtkTreeIter tmp_parent
;
289 ensure_tree_window ();
291 process
= process_window_get_process (window
);
292 if (process
->parent
) {
293 if (find_by_process (process
, &tmp_parent
))
294 parent
= &tmp_parent
;
297 gtk_tree_store_append (store
, &new, parent
);
298 iter_set_process_window (&new, window
);
299 update_process (&new);
301 g_signal_connect (G_OBJECT (process
), "status_changed",
302 G_CALLBACK (status_changed_cb
), NULL
);
306 copy_subtree (GtkTreeIter
*subtree
,
307 GtkTreeIter
*new_parent
)
309 GtkTreeModel
*model
= GTK_TREE_MODEL (store
);
311 GtkTreeIter children
;
313 gtk_tree_store_append (store
, &new, new_parent
);
314 iter_set_process_window (&new, iter_get_process_window (subtree
));
315 update_process (&new);
317 if (gtk_tree_model_iter_children (model
, &children
, subtree
)) {
319 copy_subtree (&children
, &new);
320 while (gtk_tree_model_iter_next (model
, &children
));
325 copy_children_to_grandparent (GtkTreeIter
*parent
)
327 GtkTreeModel
*model
= GTK_TREE_MODEL (store
);
328 GtkTreeIter tmp_parent
;
329 GtkTreeIter children
;
330 GtkTreeIter
*grandparent
;
332 if (gtk_tree_model_iter_parent (model
, &tmp_parent
, parent
))
333 grandparent
= &tmp_parent
;
337 if (gtk_tree_model_iter_children (model
, &children
, parent
)) {
339 copy_subtree (&children
, grandparent
);
340 } while (gtk_tree_model_iter_next (model
, &children
));
345 tree_window_remove (ProcessWindow
*window
)
350 ensure_tree_window ();
352 process
= process_window_get_process (window
);
353 find_by_process (process
, &iter
);
355 copy_children_to_grandparent (&iter
);
356 gtk_tree_store_remove (store
, &iter
);
358 g_signal_handlers_disconnect_by_func (G_OBJECT (process
), G_CALLBACK (status_changed_cb
), NULL
);