Cleanup whitespace in the Makefile.am
[memprof.git] / src / tree.c
blobd7b72bf727def7d514a4c989ebd66152a851d321
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.
21 /*====*/
23 #include <glade/glade.h>
24 #include <glib/gi18n.h>
26 #include "gui.h"
27 #include "treeviewutils.h"
29 static ProcessWindow *iter_get_process_window (GtkTreeIter *iter);
31 enum {
32 PID_COLUMN,
33 CMDLINE_COLUMN,
34 STATUS_COLUMN,
35 PWIN_COLUMN
38 static GtkWidget *tree_window;
39 static GtkWidget *tree_view;
40 static GtkTreeStore *store;
42 extern char *glade_file;
44 static GtkWidget *
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);
51 return 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");
60 static void
61 show_cb (GtkWidget *widget)
63 ProcessWindow *pwin = get_process_window (widget);
65 process_window_show (pwin);
68 static void
69 hide_cb (GtkWidget *widget)
71 ProcessWindow *pwin = get_process_window (widget);
73 process_window_hide (pwin);
76 static void
77 tree_detach_cb (GtkWidget *widget)
79 ProcessWindow *pwin = get_process_window (widget);
81 process_window_maybe_detach (pwin);
84 static void
85 tree_kill_cb (GtkWidget *widget)
87 ProcessWindow *pwin = get_process_window (widget);
89 process_window_maybe_kill (pwin);
92 static void
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;
99 if (!menu) {
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);
118 } else {
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);
127 static gboolean
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);
132 GtkTreePath *path;
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,
137 event->x, event->y,
138 &path, NULL, NULL, NULL)) {
139 GtkTreeIter iter;
141 gtk_tree_model_get_iter (model, &iter, path);
142 popup_menu (iter_get_process_window (&iter), event->button, event->time);
145 return FALSE;
148 static void
149 row_activated_cb (GtkTreeView *tree_view,
150 GtkTreePath *path,
151 GtkTreeViewColumn *column)
153 GtkTreeModel *model = GTK_TREE_MODEL (store);
154 GtkTreeIter iter;
156 gtk_tree_model_get_iter (model, &iter, path);
157 process_window_show (iter_get_process_window (&iter));
160 static void
161 ensure_tree_window (void)
163 if (!tree_window) {
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);
191 void
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);
204 ProcessWindow *pwin;
206 gtk_tree_model_get (model, iter, PWIN_COLUMN, &pwin, -1);
208 return pwin;
211 static void
212 iter_set_process_window (GtkTreeIter *iter,
213 ProcessWindow *pwin)
215 gtk_tree_store_set (store, iter, PWIN_COLUMN, pwin, -1);
218 static gboolean
219 find_by_process_recurse (MPProcess *process,
220 GtkTreeIter *iter,
221 GtkTreeIter *parent)
223 GtkTreeModel *model = GTK_TREE_MODEL (store);
224 GtkTreeIter children;
226 if (parent) {
227 ProcessWindow *pwin = iter_get_process_window (parent);
228 MPProcess *row_process = process_window_get_process (pwin);
230 if (row_process == process) {
231 *iter = *parent;
232 return TRUE;
236 if (gtk_tree_model_iter_children (model, &children, parent)) {
237 do {
238 if (find_by_process_recurse (process, iter, &children))
239 return TRUE;
240 } while (gtk_tree_model_iter_next (model, &children));
243 return FALSE;
247 static gboolean
248 find_by_process (MPProcess *process,
249 GtkTreeIter *iter)
251 return find_by_process_recurse (process, iter, NULL);
254 static void
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,
266 -1);
268 g_free (cmdline);
269 g_free (status);
272 static void
273 status_changed_cb (MPProcess *process)
275 GtkTreeIter iter;
277 if (find_by_process (process, &iter))
278 update_process (&iter);
281 void
282 tree_window_add (ProcessWindow *window)
284 MPProcess *process;
285 GtkTreeIter *parent = NULL;
286 GtkTreeIter tmp_parent;
287 GtkTreeIter new;
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);
305 static void
306 copy_subtree (GtkTreeIter *subtree,
307 GtkTreeIter *new_parent)
309 GtkTreeModel *model = GTK_TREE_MODEL (store);
310 GtkTreeIter new;
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));
324 static void
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;
334 else
335 grandparent = NULL;
337 if (gtk_tree_model_iter_children (model, &children, parent)) {
338 do {
339 copy_subtree (&children, grandparent);
340 } while (gtk_tree_model_iter_next (model, &children));
344 void
345 tree_window_remove (ProcessWindow *window)
347 GtkTreeIter iter;
348 MPProcess *process;
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);