~ubuntu-branches/ubuntu/trusty/sysprof/trusty

« back to all changes in this revision

Viewing changes to sysprof.c

  • Committer: Bazaar Package Importer
  • Author(s): Ritesh Raj Sarraf
  • Date: 2011-06-13 23:05:39 UTC
  • mfrom: (8.1.2 experimental)
  • Revision ID: james.westby@ubuntu.com-20110613230539-426qhsc3k996edou
Tags: 1.1.6-2
Upload to unstable 

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/* Sysprof -- Sampling, systemwide CPU profiler
2
2
 * Copyright 2004, Red Hat, Inc.
3
 
 * Copyright 2004, 2005, 2006, 2007, Soeren Sandmann
 
3
 * Copyright 2004, 2005, 2006, 2007, 2008, Soeren Sandmann
4
4
 *
5
5
 * This program is free software; you can redistribute it and/or modify
6
6
 * it under the terms of the GNU General Public License as published by
16
16
 * along with this program; if not, write to the Free Software
17
17
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
18
 */
19
 
 
20
19
#include <config.h>
21
20
 
22
 
#include <stdio.h>
23
21
#include <gtk/gtk.h>
24
 
#include <stdlib.h>
25
 
#include <fcntl.h>
26
 
#include <unistd.h>
27
22
#include <glade/glade.h>
28
23
#include <errno.h>
29
24
#include <glib/gprintf.h>
30
 
#include <sys/wait.h>
31
 
#include <sys/types.h>
 
25
#include <string.h>
 
26
#include <stdlib.h>
32
27
 
33
 
#include "binfile.h"
34
 
#include "watch.h"
35
 
#include "module/sysprof-module.h"
36
 
#include "stackstash.h"
 
28
#include "footreestore.h"
 
29
#include "treeviewutils.h"
37
30
#include "profile.h"
38
 
#include "treeviewutils.h"
 
31
#include "collector.h"
39
32
 
40
33
/* FIXME - not10 */
41
34
#define _(a) a
53
46
 
54
47
struct Application
55
48
{
56
 
    int                 input_fd;
 
49
    Collector *         collector;
 
50
 
57
51
    State               state;
58
 
    StackStash *        stash;
59
 
    
 
52
    GdkPixbuf *         icon;
 
53
 
60
54
    GtkWidget *         main_window;
61
 
    GdkPixbuf *         icon;
62
 
    
 
55
 
63
56
    GtkTreeView *       object_view;
64
57
    GtkTreeView *       callers_view;
65
58
    GtkTreeView *       descendants_view;
66
 
    
 
59
 
67
60
    GtkWidget *         start_button;
68
61
    GtkWidget *         profile_button;
69
62
    GtkWidget *         reset_button;
70
63
    GtkWidget *         save_as_button;
71
64
    GtkWidget *         dummy_button;
72
 
    
 
65
 
73
66
    GtkWidget *         start_item;
74
67
    GtkWidget *         profile_item;
75
68
    GtkWidget *         reset_item;
76
69
    GtkWidget *         save_as_item;
77
70
    GtkWidget *         open_item;
78
 
    
 
71
    GtkWidget *         screenshot_item;
 
72
    GtkWidget *         about_item;
 
73
    GtkWidget *         quit_item;
 
74
    GtkWidget *         hpaned;
 
75
    GtkWidget *         vpaned;
 
76
 
 
77
    GtkTreeSelection *  object_selection;
 
78
 
79
79
    GtkWidget *         samples_label;
80
 
    
 
80
    GtkWidget *         samples_hbox;
 
81
 
 
82
    gboolean            screenshot_window_visible;
 
83
    GtkWidget *         screenshot_textview;
 
84
    GtkWidget *         screenshot_close_button;
 
85
    GtkWidget *         screenshot_window;
 
86
 
81
87
    Profile *           profile;
82
88
    ProfileDescendant * descendants;
83
89
    ProfileCaller *     callers;
84
 
    
85
 
    int                 n_samples;
86
 
    
 
90
 
87
91
    int                 timeout_id;
88
 
    int                 generating_profile;
 
92
    int                 update_screenshot_id;
89
93
 
90
94
    char *              loaded_profile;
91
 
    
92
 
    gboolean            profile_from_file; /* FIXME - not10: This is a kludge. Figure out how
93
 
                                            * to maintain the application model properly
94
 
                                            *
95
 
                                            * The fundamental issue is that the state of
96
 
                                            * widgets is controlled by two different
97
 
                                            * entities:
98
 
                                            *
99
 
                                            *   The user clicks on them, changing their
100
 
                                            *   state.
101
 
                                            *
102
 
                                            *   The application model changes, changing their
103
 
                                            *   state.
104
 
                                            *
105
 
                                            * Model/View/Controller is a possibility.
106
 
                                            */
107
 
    GTimeVal            latest_reset;
 
95
 
 
96
    gboolean            inhibit_forced_redraw;
108
97
};
109
98
 
110
 
static gboolean
111
 
show_samples_timeout (gpointer data)
 
99
static void update_screenshot_window (Application *app);
 
100
 
 
101
static void
 
102
show_samples (Application *app)
112
103
{
113
 
    Application *app = data;
114
104
    char *label;
 
105
    int n_samples;
115
106
 
116
107
    switch (app->state)
117
108
    {
118
109
    case INITIAL:
119
 
        label = g_strdup ("Samples: 0");
 
110
        n_samples = 0;
120
111
        break;
121
 
        
 
112
 
122
113
    case PROFILING:
 
114
        n_samples = collector_get_n_samples (app->collector);
 
115
        break;
 
116
 
123
117
    case DISPLAYING:
124
 
        label = g_strdup_printf ("Samples: %d", app->n_samples);
 
118
        n_samples = profile_get_size (app->profile);
125
119
        break;
126
120
 
127
121
    default:
128
122
        g_assert_not_reached();
129
123
        break;
130
124
    }
131
 
    
 
125
 
 
126
    label = g_strdup_printf ("%d", n_samples);
 
127
 
132
128
    gtk_label_set_label (GTK_LABEL (app->samples_label), label);
133
 
    
 
129
 
134
130
    g_free (label);
135
 
    
 
131
}
 
132
 
 
133
static gboolean
 
134
show_samples_timeout (gpointer data)
 
135
{
 
136
    Application *app = data;
 
137
 
 
138
    show_samples (app);
 
139
 
136
140
    app->timeout_id = 0;
137
 
    
 
141
 
138
142
    return FALSE;
139
143
}
140
144
 
152
156
    gboolean sensitive_save_as_button;
153
157
    gboolean sensitive_start_button;
154
158
    gboolean sensitive_tree_views;
155
 
    gboolean sensitive_samples_label;
 
159
    gboolean sensitive_samples_hbox;
156
160
    gboolean sensitive_reset_button;
157
 
    
 
161
 
158
162
    GtkWidget *active_radio_button;
159
 
    
 
163
 
 
164
    gboolean has_samples;
 
165
 
160
166
    switch (app->state)
161
167
    {
162
168
    case INITIAL:
165
171
        sensitive_start_button = TRUE;
166
172
        sensitive_reset_button = FALSE;
167
173
        sensitive_tree_views = FALSE;
168
 
        sensitive_samples_label = FALSE;
 
174
        sensitive_samples_hbox = FALSE;
169
175
        active_radio_button = app->dummy_button;
170
176
        break;
171
 
        
 
177
 
172
178
    case PROFILING:
173
 
        sensitive_profile_button = (app->n_samples > 0);
174
 
        sensitive_save_as_button = (app->n_samples > 0);
175
 
        sensitive_reset_button = (app->n_samples > 0);
 
179
        has_samples = (collector_get_n_samples (app->collector) > 0);
 
180
 
 
181
        sensitive_profile_button = has_samples;
 
182
        sensitive_save_as_button = has_samples;
 
183
        sensitive_reset_button = has_samples;
176
184
        sensitive_start_button = TRUE;
177
185
        sensitive_tree_views = FALSE;
178
 
        sensitive_samples_label = TRUE;
 
186
        sensitive_samples_hbox = TRUE;
179
187
        active_radio_button = app->start_button;
180
188
        break;
181
 
        
 
189
 
182
190
    case DISPLAYING:
183
191
        sensitive_profile_button = TRUE;
184
192
        sensitive_save_as_button = TRUE;
185
193
        sensitive_start_button = TRUE;
186
194
        sensitive_tree_views = TRUE;
187
195
        sensitive_reset_button = TRUE;
188
 
        sensitive_samples_label = FALSE;
 
196
        sensitive_samples_hbox = FALSE;
189
197
        active_radio_button = app->profile_button;
190
198
        break;
191
199
 
193
201
        g_assert_not_reached();
194
202
        break;
195
203
    }
196
 
    
197
 
    gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (active_radio_button), TRUE);
 
204
 
 
205
    gtk_toggle_tool_button_set_active (
 
206
        GTK_TOGGLE_TOOL_BUTTON (active_radio_button), TRUE);
198
207
 
199
208
    /* "profile" widgets */
200
209
    gtk_widget_set_sensitive (GTK_WIDGET (app->profile_button),
201
210
                              sensitive_profile_button);
202
211
    gtk_widget_set_sensitive (GTK_WIDGET (app->profile_item),
203
212
                              sensitive_profile_button);
204
 
    
 
213
 
205
214
    /* "save as" widgets */
206
215
    gtk_widget_set_sensitive (GTK_WIDGET (app->save_as_button),
207
216
                              sensitive_save_as_button);
213
222
                              sensitive_start_button);
214
223
    gtk_widget_set_sensitive (GTK_WIDGET (app->start_item),
215
224
                              sensitive_start_button);
216
 
    
 
225
 
217
226
#if 0
218
 
    /* FIXME - not10: gtk+ doesn't handle changes in sensitivity in response 
 
227
    /* FIXME - not10: gtk+ doesn't handle changes in sensitivity in response
219
228
     * to a click on the same button very well
220
229
     */
221
230
    gtk_widget_set_sensitive (GTK_WIDGET (app->reset_button),
223
232
    gtk_widget_set_sensitive (GTK_WIDGET (app->reset_item),
224
233
                              sensitive_reset_button);
225
234
#endif
226
 
    
 
235
 
227
236
    gtk_widget_set_sensitive (GTK_WIDGET (app->object_view), sensitive_tree_views);
228
237
    gtk_widget_set_sensitive (GTK_WIDGET (app->callers_view), sensitive_tree_views);
229
238
    gtk_widget_set_sensitive (GTK_WIDGET (app->descendants_view), sensitive_tree_views);
230
 
    gtk_widget_set_sensitive (GTK_WIDGET (app->samples_label), sensitive_samples_label);
231
 
 
232
 
    queue_show_samples (app);
 
239
    gtk_widget_set_sensitive (GTK_WIDGET (app->samples_hbox), sensitive_samples_hbox);
 
240
 
 
241
    if (app->screenshot_window_visible)
 
242
        gtk_widget_show (app->screenshot_window);
 
243
    else
 
244
        gtk_widget_hide (app->screenshot_window);
 
245
 
 
246
    gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (app->screenshot_item),
 
247
                                    app->screenshot_window_visible);
 
248
 
 
249
    show_samples (app);
233
250
}
234
251
 
235
252
static void
236
 
set_busy (GtkWidget *widget, gboolean busy)
 
253
set_busy (GtkWidget *widget,
 
254
          gboolean   busy)
237
255
{
238
256
    GdkCursor *cursor;
239
 
    
 
257
    GdkWindow *window;
 
258
 
240
259
    if (busy)
241
260
        cursor = gdk_cursor_new (GDK_WATCH);
242
261
    else
243
262
        cursor = NULL;
244
263
 
245
 
    gdk_window_set_cursor (widget->window, cursor);
246
 
    
 
264
    if (GTK_IS_TEXT_VIEW (widget))
 
265
        window = gtk_text_view_get_window (GTK_TEXT_VIEW (widget), GTK_TEXT_WINDOW_TEXT);
 
266
    else
 
267
        window = widget->window;
 
268
 
 
269
    gdk_window_set_cursor (window, cursor);
 
270
 
247
271
    if (cursor)
248
272
        gdk_cursor_unref (cursor);
249
273
 
250
 
    gdk_flush ();
251
 
}
252
 
 
253
 
#if 0
254
 
static gchar *
255
 
get_name (pid_t pid)
256
 
{
257
 
    char *cmdline;
258
 
    char *name = g_strdup_printf ("/proc/%d/cmdline", pid);
259
 
    
260
 
    if (g_file_get_contents (name, &cmdline, NULL, NULL))
261
 
        return cmdline;
262
 
    else
263
 
        return g_strdup ("<unknown>");
264
 
}
265
 
#endif
266
 
 
267
 
#if 0
268
 
static void
269
 
on_timeout (gpointer data)
270
 
{
271
 
    Application *app = data;
272
 
    GList *pids, *list;
273
 
    int mypid = getpid();
274
 
    
275
 
    pids = list_processes ();
276
 
    
277
 
    for (list = pids; list != NULL; list = list->next)
278
 
    {
279
 
        int pid = GPOINTER_TO_INT (list->data);
280
 
        
281
 
        if (pid == mypid)
282
 
            continue;
283
 
        
284
 
        if (get_process_state (pid) == PROCESS_RUNNING)
285
 
        {
286
 
            Process *process;
287
 
            SysprofStackTrace trace;
288
 
            int i;
289
 
            
290
 
            if (!generate_stack_trace (pid, &trace))
291
 
            {
292
 
                continue;
293
 
            }
294
 
            
295
 
            process = process_get_from_pid (pid);
296
 
            
297
 
#if 0
298
 
            process_ensure_map (process, trace.pid, 
299
 
                                (gulong)trace.addresses[i]);
300
 
#endif
301
 
            
302
 
            g_print ("n addr: %d\n", trace.n_addresses);
303
 
            for (i = 0; i < trace.n_addresses; ++i)
304
 
                process_ensure_map (process, trace.pid, 
305
 
                                    (gulong)trace.addresses[i]);
306
 
            g_assert (!app->generating_profile);
307
 
            
308
 
            stack_stash_add_trace (
309
 
                app->stash, process,
310
 
                (gulong *)trace.addresses, trace.n_addresses, 1);
311
 
            
312
 
            app->n_samples++;
313
 
        }
314
 
    }
315
 
    
316
 
    update_sensitivity (app);
317
 
    g_list_free (pids);
318
 
    
319
 
    return TRUE;
320
 
}
321
 
#endif
322
 
 
323
 
static double
324
 
timeval_to_ms (const GTimeVal *timeval)
325
 
{
326
 
  return (timeval->tv_sec * G_USEC_PER_SEC + timeval->tv_usec) / 1000.0;
327
 
}
328
 
 
329
 
static double
330
 
time_diff (const GTimeVal *first,
331
 
           const GTimeVal *second)
332
 
{
333
 
  double first_ms = timeval_to_ms (first);
334
 
  double second_ms = timeval_to_ms (second);
335
 
 
336
 
  return first_ms - second_ms;
337
 
}
338
 
 
339
 
#define RESET_DEAD_PERIOD 250
340
 
 
341
 
static void
342
 
on_read (gpointer data)
343
 
{
344
 
    Application *app = data;
345
 
    SysprofStackTrace trace;
346
 
    GTimeVal now;
347
 
    int rd;
348
 
    
349
 
    rd = read (app->input_fd, &trace, sizeof (trace));
350
 
    
351
 
    if (app->state != PROFILING)
352
 
        return;
353
 
    
354
 
    if (rd == -1 && errno == EWOULDBLOCK)
355
 
        return;
356
 
 
357
 
    g_get_current_time (&now);
358
 
 
359
 
    /* After a reset we ignore samples for a short period so that
360
 
     * a reset will actually cause 'samples' to become 0
361
 
     */
362
 
    if (time_diff (&now, &app->latest_reset) < RESET_DEAD_PERIOD)
363
 
        return;
364
 
    
365
 
#if 0
366
 
    int i;
367
 
    g_print ("pid: %d\n", trace.pid);
368
 
    for (i=0; i < trace.n_addresses; ++i)
369
 
        g_print ("rd: %08x\n", trace.addresses[i]);
370
 
    g_print ("-=-\n");
371
 
#endif
372
 
    
373
 
    if (rd > 0 && !app->generating_profile && trace.n_addresses)
374
 
    {
375
 
        Process *process = process_get_from_pid (trace.pid);
376
 
        int i;
377
 
/*      char *filename = NULL; */
378
 
        
379
 
/*      if (*trace.filename) */
380
 
/*          filename = trace.filename; */
381
 
 
382
 
        for (i = 0; i < trace.n_addresses; ++i)
383
 
        {
384
 
            process_ensure_map (process, trace.pid, 
385
 
                                (gulong)trace.addresses[i]);
386
 
        }
387
 
        g_assert (!app->generating_profile);
388
 
        
389
 
        stack_stash_add_trace (
390
 
            app->stash, process,
391
 
            (gulong *)trace.addresses, trace.n_addresses, 1);
392
 
        
393
 
        app->n_samples++;
394
 
    }
395
 
    
396
 
    update_sensitivity (app);
 
274
    gdk_flush();
397
275
}
398
276
 
399
277
static void
405
283
        new_name = g_path_get_basename (name);
406
284
    else
407
285
        new_name = NULL;
408
 
    
 
286
 
409
287
    if (app->loaded_profile)
410
288
        g_free (app->loaded_profile);
411
289
 
412
290
    app->loaded_profile = new_name;
413
 
    
 
291
 
414
292
    if (app->loaded_profile)
415
293
    {
416
294
        gtk_window_set_title (GTK_WINDOW (app->main_window),
419
297
    else
420
298
    {
421
299
        gtk_window_set_title (GTK_WINDOW (app->main_window),
422
 
                              "System Profiler");
 
300
                              APPLICATION_NAME);
423
301
    }
424
302
}
425
303
 
430
308
    {
431
309
        profile_free (app->profile);
432
310
        app->profile = NULL;
433
 
        
 
311
 
434
312
        gtk_tree_view_set_model (GTK_TREE_VIEW (app->object_view), NULL);
435
313
        gtk_tree_view_set_model (GTK_TREE_VIEW (app->callers_view), NULL);
436
314
        gtk_tree_view_set_model (GTK_TREE_VIEW (app->descendants_view), NULL);
437
315
    }
438
 
    
439
 
    if (app->stash)
440
 
        stack_stash_free (app->stash);
441
 
    app->stash = stack_stash_new ();
442
 
    process_flush_caches ();
443
 
    app->n_samples = 0;
444
 
    queue_show_samples (app);
445
 
    app->profile_from_file = FALSE;
 
316
 
 
317
    collector_reset (app->collector);
 
318
 
446
319
    set_application_title (app, NULL);
447
 
    g_get_current_time (&app->latest_reset);
448
 
}
449
 
 
450
 
static void
451
 
empty_file_descriptor (Application *app)
452
 
{
453
 
    int rd;
454
 
    SysprofStackTrace trace;
455
 
    
456
 
    do
457
 
    {
458
 
        rd = read (app->input_fd, &trace, sizeof (trace));
459
 
        
460
 
    } while (rd != -1); /* until EWOULDBLOCK */
461
 
}
462
 
 
463
 
static gboolean
464
 
start_profiling (gpointer data)
465
 
{
466
 
    Application *app = data;
467
 
    
468
 
    app->state = PROFILING;
469
 
    
470
 
    update_sensitivity (app);
471
 
    
472
 
    /* Make sure samples generated between 'start clicked' and now
473
 
     * are deleted
474
 
     */
475
 
    empty_file_descriptor (app);
476
 
    
477
 
    return FALSE;
478
320
}
479
321
 
480
322
static void
485
327
    va_list args;
486
328
    char *message;
487
329
    GtkWidget *dialog;
488
 
    
 
330
 
489
331
    va_start (args, format);
490
332
    g_vasprintf (&message, format, args);
491
333
    va_end (args);
492
 
    
 
334
 
493
335
    dialog = gtk_message_dialog_new (parent_window ? GTK_WINDOW (parent_window) : NULL,
494
336
                                     GTK_DIALOG_DESTROY_WITH_PARENT,
495
337
                                     GTK_MESSAGE_WARNING,
496
 
                                     GTK_BUTTONS_OK, message);
 
338
                                     GTK_BUTTONS_OK, "%s", message);
497
339
    g_free (message);
498
 
    
 
340
 
499
341
    gtk_window_set_title (GTK_WINDOW (dialog), APPLICATION_NAME " Warning");
500
 
    
 
342
 
501
343
    gtk_dialog_run (GTK_DIALOG (dialog));
502
344
    gtk_widget_destroy (dialog);
503
345
}
504
346
 
505
 
static gboolean
506
 
load_module (void)
507
 
{
508
 
    int exit_status = -1;
509
 
    char *dummy1, *dummy2;
510
 
 
511
 
    if (g_spawn_command_line_sync ("/sbin/modprobe sysprof-module",
512
 
                                   &dummy1, &dummy2,
513
 
                                   &exit_status,
514
 
                                   NULL))
515
 
    {
516
 
        if (WIFEXITED (exit_status))
517
 
            exit_status = WEXITSTATUS (exit_status);
518
 
 
519
 
        g_free (dummy1);
520
 
        g_free (dummy2);
521
 
    }
522
 
 
523
 
    return (exit_status == 0);
524
 
}
525
 
 
526
347
static void
527
348
on_menu_item_activated (GtkWidget *menu_item, GtkWidget *tool_button)
528
349
{
536
357
on_start_toggled (GtkWidget *widget, gpointer data)
537
358
{
538
359
    Application *app = data;
 
360
    GError *err = NULL;
539
361
 
540
362
    if (!gtk_toggle_tool_button_get_active (
541
363
            GTK_TOGGLE_TOOL_BUTTON (app->start_button)))
 
364
    {
542
365
        return;
543
 
 
544
 
    if (app->input_fd == -1)
545
 
    {
546
 
        int fd;
547
 
 
548
 
        fd = open ("/proc/sysprof-trace", O_RDONLY);
549
 
        if (fd < 0)
550
 
        {
551
 
            load_module();
552
 
 
553
 
            fd = open ("/proc/sysprof-trace", O_RDONLY);
554
 
 
555
 
            if (fd < 0)
556
 
            {
557
 
                sorry (app->main_window,
558
 
                       "Can't open /proc/sysprof-trace. You need to insert\n"
559
 
                       "the sysprof kernel module. Run\n"
560
 
                       "\n"
561
 
                       "       modprobe sysprof-module\n"
562
 
                       "\n"
563
 
                       "as root.\n"
564
 
                       "\n"
565
 
                       "You may need to build and install this module first:\n"
566
 
                       "  1. Install the package sysprof-module-source\n"
567
 
                       "  2. Execute \"m-a a-i sysprof-module\"\n"
568
 
                       "  3. Load the module as described above\n"
569
 
                       "  4. Restart sysprof\n"
570
 
                       "See also /usr/share/doc/sysprof-module-source/README.Debian" );
571
 
                
572
 
                update_sensitivity (app);
573
 
                return;
574
 
            }
575
 
        }
576
 
 
577
 
        app->input_fd = fd;
578
 
        fd_add_watch (app->input_fd, app);
579
 
    }
580
 
    
581
 
    fd_set_read_callback (app->input_fd, on_read);
582
 
    
583
 
    delete_data (app);
584
 
    
585
 
    g_idle_add_full (G_PRIORITY_LOW, start_profiling, app, NULL);
 
366
    }
 
367
 
 
368
    if (collector_start (app->collector, &err))
 
369
    {
 
370
        delete_data (app);
 
371
 
 
372
        app->state = PROFILING;
 
373
    }
 
374
    else
 
375
    {
 
376
        sorry (app->main_window, err->message); 
 
377
 
 
378
        g_error_free (err);
 
379
    }
 
380
 
 
381
    update_screenshot_window (app);
 
382
    update_sensitivity (app);
586
383
}
587
384
 
588
385
enum
605
402
{
606
403
    DESCENDANTS_NAME,
607
404
    DESCENDANTS_SELF,
608
 
    DESCENDANTS_NON_RECURSE,
609
 
    DESCENDANTS_TOTAL,
 
405
    DESCENDANTS_CUMULATIVE,
610
406
    DESCENDANTS_OBJECT
611
407
};
612
408
 
613
 
static ProfileObject *
 
409
static char *
614
410
get_current_object (Application *app)
615
411
{
616
 
    GtkTreeSelection *selection;
617
412
    GtkTreeModel *model;
618
413
    GtkTreeIter selected;
619
 
    ProfileObject *object;
620
 
    
621
 
    selection = gtk_tree_view_get_selection (app->object_view);
622
 
    
623
 
    if (gtk_tree_selection_get_selected (selection, &model, &selected))
 
414
    char *object;
 
415
 
 
416
    if (gtk_tree_selection_get_selected (app->object_selection, &model, &selected))
624
417
    {
625
418
        gtk_tree_model_get (model, &selected,
626
419
                            OBJECT_OBJECT, &object,
640
433
    GtkListStore *list_store;
641
434
    Profile *profile = app->profile;
642
435
    GList *objects;
643
 
    
 
436
 
644
437
    if (profile)
645
438
    {
646
 
        gpointer sort_state;
647
 
        
648
439
        list_store = gtk_list_store_new (4,
649
440
                                         G_TYPE_STRING,
650
441
                                         G_TYPE_DOUBLE,
651
442
                                         G_TYPE_DOUBLE,
652
443
                                         G_TYPE_POINTER);
653
 
        
 
444
 
654
445
        objects = profile_get_objects (profile);
655
446
        for (list = objects; list != NULL; list = list->next)
656
447
        {
657
448
            ProfileObject *object = list->data;
658
449
            GtkTreeIter iter;
659
450
            double profile_size = profile_get_size (profile);
660
 
            
 
451
 
661
452
            gtk_list_store_append (list_store, &iter);
662
 
            
 
453
 
663
454
            gtk_list_store_set (list_store, &iter,
664
455
                                OBJECT_NAME, object->name,
665
456
                                OBJECT_SELF, 100.0 * object->self / profile_size,
666
457
                                OBJECT_TOTAL, 100.0 * object->total / profile_size,
667
 
                                OBJECT_OBJECT, object,
 
458
#if 0
 
459
                                OBJECT_SELF, (double)object->self,
 
460
                                OBJECT_TOTAL, (double)object->total,
 
461
#endif
 
462
                                OBJECT_OBJECT, object->name,
668
463
                                -1);
669
464
        }
 
465
        g_list_foreach (objects, (GFunc)g_free, NULL);
670
466
        g_list_free (objects);
671
 
        
672
 
        sort_state = save_sort_state (app->object_view);
673
 
        
674
 
        gtk_tree_view_set_model (app->object_view, GTK_TREE_MODEL (list_store));
675
 
        
676
 
        if (sort_state)
677
 
        {
678
 
            restore_sort_state (app->object_view, sort_state);
679
 
        }
680
 
        else
681
 
        {
682
 
            gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (list_store),
683
 
                                                  OBJECT_TOTAL,
684
 
                                                  GTK_SORT_DESCENDING);
685
 
        }
686
 
        
 
467
 
 
468
        tree_view_set_model_with_default_sort (app->object_view, GTK_TREE_MODEL (list_store),
 
469
                                               OBJECT_TOTAL, GTK_SORT_DESCENDING);
 
470
 
687
471
        g_object_unref (G_OBJECT (list_store));
688
472
    }
689
 
    
 
473
 
690
474
    gtk_tree_view_columns_autosize (app->object_view);
691
475
}
692
476
 
693
477
static void
694
 
add_node (GtkTreeStore      *store,
 
478
add_node (FooTreeStore      *store,
695
479
          int                size,
696
480
          const GtkTreeIter *parent,
697
481
          ProfileDescendant *node)
698
482
{
699
483
    GtkTreeIter iter;
700
 
    
 
484
 
701
485
    if (!node)
702
486
        return;
703
487
    
704
 
    gtk_tree_store_insert (store, &iter, (GtkTreeIter *)parent, 0);
 
488
    foo_tree_store_insert (store, &iter, (GtkTreeIter *)parent, 0);
705
489
    
706
 
    gtk_tree_store_set (store, &iter,
707
 
                        DESCENDANTS_NAME, node->object->name,
 
490
    foo_tree_store_set (store, &iter,
 
491
                        DESCENDANTS_NAME, node->name,
708
492
                        DESCENDANTS_SELF, 100 * (node->self)/(double)size,
709
 
                        DESCENDANTS_NON_RECURSE, 100 * (node->non_recursion)/(double)size,
710
 
                        DESCENDANTS_TOTAL, 100 * (node->total)/(double)size,
711
 
                        DESCENDANTS_OBJECT, node->object,
 
493
                        DESCENDANTS_CUMULATIVE, 100 * (node->cumulative)/(double)size,
 
494
#if 0
 
495
                        DESCENDANTS_SELF, (double)node->self,
 
496
                        DESCENDANTS_CUMULATIVE, (double)node->non_recursion,
 
497
#endif
 
498
                        DESCENDANTS_OBJECT, node->name,
712
499
                        -1);
713
 
    
 
500
 
714
501
    add_node (store, size, parent, node->siblings);
715
502
    add_node (store, size, &iter, node->children);
716
503
}
718
505
static void
719
506
fill_descendants_tree (Application *app)
720
507
{
721
 
    GtkTreeStore *tree_store;
722
 
    gpointer sort_state;
723
 
    
724
 
    sort_state = save_sort_state (app->descendants_view);
725
 
    
 
508
    FooTreeStore *tree_store;
 
509
 
726
510
    if (app->descendants)
727
511
    {
728
512
        profile_descendant_free (app->descendants);
729
513
        app->descendants = NULL;
730
514
    }
731
 
    
 
515
 
732
516
    tree_store =
733
 
        gtk_tree_store_new (5,
 
517
        foo_tree_store_new (4,
734
518
                            G_TYPE_STRING,
735
519
                            G_TYPE_DOUBLE,
736
520
                            G_TYPE_DOUBLE,
737
 
                            G_TYPE_DOUBLE,
738
521
                            G_TYPE_POINTER);
739
 
    
 
522
 
740
523
    if (app->profile)
741
524
    {
742
 
        ProfileObject *object = get_current_object (app);
 
525
        char *object = get_current_object (app);
743
526
        if (object)
744
527
        {
745
528
            app->descendants =
748
531
                      profile_get_size (app->profile), NULL, app->descendants);
749
532
        }
750
533
    }
751
 
    
752
 
    gtk_tree_view_set_model (
753
 
        app->descendants_view, GTK_TREE_MODEL (tree_store));
754
 
    
 
534
 
 
535
    tree_view_set_model_with_default_sort (app->descendants_view, GTK_TREE_MODEL (tree_store),
 
536
                                           DESCENDANTS_CUMULATIVE, GTK_SORT_DESCENDING);
 
537
 
755
538
    g_object_unref (G_OBJECT (tree_store));
756
 
    
757
 
    if (!sort_state)
758
 
    {
759
 
        gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (tree_store),
760
 
                                              DESCENDANTS_NON_RECURSE,
761
 
                                              GTK_SORT_DESCENDING);
762
 
    }
763
 
    else
764
 
    {
765
 
        restore_sort_state (app->descendants_view, sort_state);
766
 
    }
767
 
    
 
539
 
768
540
    gtk_tree_view_columns_autosize (app->descendants_view);
769
541
}
770
542
 
771
543
static void
772
 
add_callers (GtkListStore *list_store,
773
 
             Profile *profile,
 
544
add_callers (GtkListStore  *list_store,
 
545
             Profile       *profile,
774
546
             ProfileCaller *callers)
775
547
{
776
548
    while (callers)
778
550
        gchar *name;
779
551
        GtkTreeIter iter;
780
552
        double profile_size = profile_get_size (profile);
781
 
        
782
 
        if (callers->object)
783
 
            name = callers->object->name;
 
553
 
 
554
        if (callers->name)
 
555
            name = callers->name;
784
556
        else
785
557
            name = "<spontaneous>";
786
 
        
 
558
 
787
559
        gtk_list_store_append (list_store, &iter);
788
560
        gtk_list_store_set (
789
561
            list_store, &iter,
790
562
            CALLERS_NAME, name,
791
563
            CALLERS_SELF, 100.0 * callers->self / profile_size,
792
564
            CALLERS_TOTAL, 100.0 * callers->total / profile_size,
793
 
            CALLERS_OBJECT, callers->object,
 
565
#if 0
 
566
            CALLERS_SELF, (double)callers->self,
 
567
            CALLERS_TOTAL, (double)callers->total,
 
568
#endif
 
569
            CALLERS_OBJECT, callers->name,
794
570
            -1);
795
 
        
 
571
 
796
572
        callers = callers->next;
797
573
    }
798
574
}
801
577
fill_callers_list (Application *app)
802
578
{
803
579
    GtkListStore *list_store;
804
 
    gpointer sort_state;
805
 
    
806
 
    sort_state = save_sort_state (app->descendants_view);
807
 
    
 
580
 
808
581
    if (app->callers)
809
582
    {
810
583
        profile_caller_free (app->callers);
811
584
        app->callers = NULL;
812
585
    }
813
 
    
 
586
 
814
587
    list_store =
815
588
        gtk_list_store_new (4,
816
589
                            G_TYPE_STRING,
817
590
                            G_TYPE_DOUBLE,
818
591
                            G_TYPE_DOUBLE,
819
592
                            G_TYPE_POINTER);
820
 
    
 
593
 
821
594
    if (app->profile)
822
595
    {
823
 
        ProfileObject *object = get_current_object (app);
 
596
        char *object = get_current_object (app);
824
597
        if (object)
825
598
        {
826
599
            app->callers = profile_list_callers (app->profile, object);
827
600
            add_callers (list_store, app->profile, app->callers);
828
601
        }
829
602
    }
830
 
    
831
 
    gtk_tree_view_set_model (
832
 
        app->callers_view, GTK_TREE_MODEL (list_store));
833
 
    
 
603
 
 
604
    tree_view_set_model_with_default_sort (app->callers_view, GTK_TREE_MODEL (list_store),
 
605
                                           CALLERS_TOTAL, GTK_SORT_DESCENDING);
 
606
 
834
607
    g_object_unref (G_OBJECT (list_store));
835
 
    
836
 
    if (!sort_state)
837
 
    {
838
 
        gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (list_store),
839
 
                                              CALLERS_TOTAL,
840
 
                                              GTK_SORT_DESCENDING);
841
 
    }
842
 
    else
843
 
    {
844
 
        restore_sort_state (app->callers_view, sort_state);
845
 
    }
846
 
    
 
608
 
847
609
    gtk_tree_view_columns_autosize (app->callers_view);
848
610
}
849
611
 
850
612
static void
851
 
fill_lists (Application *app)
 
613
enter_display_mode (Application *app)
852
614
{
 
615
    app->state = DISPLAYING;
 
616
 
 
617
    update_sensitivity (app);
 
618
 
 
619
    app->inhibit_forced_redraw = TRUE;
 
620
 
853
621
    fill_main_list (app);
854
 
    fill_callers_list (app);
855
 
    fill_descendants_tree (app);
 
622
 
 
623
    /* This has the side effect of selecting the first row, which in turn causes
 
624
     * the other lists to be filled out
 
625
     */
 
626
    gtk_widget_grab_focus (GTK_WIDGET (app->object_view));
 
627
 
 
628
    app->inhibit_forced_redraw = FALSE;
856
629
}
857
630
 
858
631
static void
860
633
{
861
634
    if (app->profile)
862
635
        return;
863
 
    
864
 
    app->profile = profile_new (app->stash);
865
 
 
866
 
    fill_lists (app);
867
 
    
868
 
    app->state = DISPLAYING;
869
 
    
870
 
    update_sensitivity (app);
 
636
 
 
637
    collector_stop (app->collector);
 
638
 
 
639
    app->profile = collector_create_profile (app->collector);
 
640
 
 
641
    collector_reset (app->collector);
 
642
 
 
643
    enter_display_mode (app);
871
644
}
872
645
 
873
646
static void
875
648
{
876
649
#define OSLASH "\303\270"
877
650
    Application *app = data;
 
651
    char *name_property;
 
652
 
 
653
    if (gtk_minor_version >= 12)
 
654
        name_property = "program-name";
 
655
    else
 
656
        name_property = "name";
878
657
 
879
658
    gtk_show_about_dialog (GTK_WINDOW (app->main_window),
880
659
                           "logo", app->icon,
881
 
                           "name", APPLICATION_NAME,
882
 
                           "copyright", "Copyright 2004-2008, S"OSLASH"ren Sandmann",
 
660
                           name_property, APPLICATION_NAME,
 
661
                           "copyright", "Copyright 2004-2009, S"OSLASH"ren Sandmann",
883
662
                           "version", PACKAGE_VERSION,
884
663
                           NULL);
885
664
}
892
671
    if (gtk_toggle_tool_button_get_active (GTK_TOGGLE_TOOL_BUTTON (app->profile_button)))
893
672
    {
894
673
        set_busy (app->main_window, TRUE);
895
 
        if (app->profile && !app->profile_from_file)
896
 
        {
897
 
            profile_free (app->profile);
898
 
            app->profile = NULL;
899
 
        }
900
 
        
901
674
        ensure_profile (app);
902
675
        set_busy (app->main_window, FALSE);
903
676
    }
909
682
    Application *app = data;
910
683
 
911
684
    set_busy (app->main_window, TRUE);
912
 
    
 
685
 
913
686
    delete_data (app);
914
 
    
 
687
 
915
688
    if (app->state == DISPLAYING)
 
689
    {
916
690
        app->state = INITIAL;
917
 
    
 
691
        collector_stop (app->collector);
 
692
    }
 
693
 
918
694
    update_sensitivity (app);
919
695
 
920
696
    set_busy (app->main_window, FALSE);
928
704
    gchar *utf8_file_name;
929
705
    AtkObject *obj;
930
706
    gint ret;
931
 
    
 
707
 
932
708
    utf8_file_name = g_filename_to_utf8 (filename, -1, NULL, NULL, NULL);
933
709
    msgbox = gtk_message_dialog_new (window,
934
710
                                     (GtkDialogFlags)GTK_DIALOG_DESTROY_WITH_PARENT,
937
713
                                     _("A file named \"%s\" already exists."),
938
714
                                     utf8_file_name);
939
715
    g_free (utf8_file_name);
940
 
    
 
716
 
941
717
    gtk_message_dialog_format_secondary_text (
942
718
        GTK_MESSAGE_DIALOG (msgbox),
943
719
        _("Do you want to replace it with the one you are saving?"));
944
 
    
 
720
 
945
721
    gtk_dialog_add_button (GTK_DIALOG (msgbox),
946
722
                           GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
947
 
    
 
723
 
948
724
    gtk_dialog_add_button (GTK_DIALOG (msgbox),
949
725
                           _("_Replace"), GTK_RESPONSE_YES);
950
 
    
 
726
 
951
727
    gtk_dialog_set_default_response (GTK_DIALOG (msgbox),
952
728
                                     GTK_RESPONSE_CANCEL);
953
 
    
 
729
 
954
730
    obj = gtk_widget_get_accessible (msgbox);
955
 
    
 
731
 
956
732
    if (GTK_IS_ACCESSIBLE (obj))
957
733
        atk_object_set_name (obj, _("Question"));
958
 
    
 
734
 
959
735
    ret = gtk_dialog_run (GTK_DIALOG (msgbox));
960
736
    gtk_widget_destroy (msgbox);
961
 
    
 
737
 
962
738
    return (ret == GTK_RESPONSE_YES);
963
 
    
964
739
}
965
740
 
966
741
static void
969
744
{
970
745
    Application *app = data;
971
746
    GtkWidget *dialog;
972
 
    
 
747
 
973
748
    ensure_profile (app);
974
 
    
 
749
 
975
750
    set_busy (app->main_window, TRUE);
976
 
    
 
751
 
977
752
    dialog = gtk_file_chooser_dialog_new ("Save As",
978
753
                                          GTK_WINDOW (app->main_window),
979
754
                                          GTK_FILE_CHOOSER_ACTION_SAVE,
980
755
                                          GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
981
756
                                          GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
982
757
                                          NULL);
983
 
    
 
758
 
984
759
    gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);
985
760
    gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
986
 
    
 
761
 
987
762
    set_busy (app->main_window, FALSE);
988
 
    
989
 
 retry:
 
763
 
 
764
retry:
990
765
    if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
991
766
    {
992
767
        GError *err = NULL;
993
768
        gchar *filename;
994
 
        
 
769
 
995
770
        filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
996
 
        
 
771
 
997
772
        if (g_file_test (filename, G_FILE_TEST_EXISTS)          &&
998
773
            !overwrite_file (GTK_WINDOW (app->main_window), filename))
999
774
        {
1000
775
            g_free (filename);
1001
776
            goto retry;
1002
777
        }
1003
 
        
 
778
 
1004
779
        set_busy (dialog, TRUE);
1005
780
        if (!profile_save (app->profile, filename, &err))
1006
781
        {
1015
790
        set_busy (dialog, FALSE);
1016
791
        g_free (filename);
1017
792
    }
1018
 
    
 
793
 
1019
794
    gtk_widget_destroy (dialog);
1020
795
}
1021
796
 
1026
801
{
1027
802
    g_return_if_fail (name != NULL);
1028
803
    g_return_if_fail (profile != NULL);
1029
 
    
1030
 
    set_busy (app->main_window, TRUE);
1031
 
    
 
804
 
 
805
    collector_stop (app->collector);
 
806
 
1032
807
    delete_data (app);
1033
 
        
1034
 
    app->state = DISPLAYING;
1035
 
    
1036
 
    app->n_samples = profile_get_size (profile);
1037
 
    
 
808
 
1038
809
    app->profile = profile;
1039
 
    app->profile_from_file = TRUE;
1040
 
    
1041
 
    fill_lists (app);
1042
810
 
1043
811
    set_application_title (app, name);
1044
 
    
1045
 
    update_sensitivity (app);
1046
 
    
1047
 
    set_busy (app->main_window, FALSE);
 
812
 
 
813
    enter_display_mode (app);
1048
814
}
1049
815
 
1050
816
static void
1057
823
           filename,
1058
824
           err->message);
1059
825
}
1060
 
            
 
826
 
1061
827
static void
1062
828
on_open_clicked (gpointer widget,
1063
829
                 gpointer data)
1068
834
    GtkWidget *dialog;
1069
835
 
1070
836
    set_busy (app->main_window, TRUE);
1071
 
    
 
837
 
1072
838
    dialog = gtk_file_chooser_dialog_new ("Open",
1073
839
                                          GTK_WINDOW (app->main_window),
1074
840
                                          GTK_FILE_CHOOSER_ACTION_OPEN,
1075
841
                                          GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1076
842
                                          GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
1077
843
                                          NULL);
1078
 
    
 
844
 
1079
845
    gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
1080
846
 
1081
847
    set_busy (app->main_window, FALSE);
1082
 
    
1083
 
 retry:
 
848
 
 
849
retry:
1084
850
    if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
1085
851
    {
1086
852
        GError *err = NULL;
1087
 
        
 
853
 
1088
854
        filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
1089
855
 
1090
856
        set_busy (dialog, TRUE);
1091
857
 
1092
858
        profile = profile_load (filename, &err);
1093
 
        
 
859
 
1094
860
        if (!profile)
1095
861
        {
1096
862
            set_busy (dialog, FALSE);
1098
864
            show_could_not_open (app, filename, err);
1099
865
            g_error_free (err);
1100
866
            g_free (filename);
1101
 
            
 
867
 
1102
868
            filename = NULL;
1103
869
            goto retry;
1104
870
        }
1105
 
        
 
871
 
1106
872
        set_busy (dialog, FALSE);
1107
873
    }
1108
874
 
1112
878
    {
1113
879
        g_assert (filename);
1114
880
        set_loaded_profile (app, filename, profile);
1115
 
    
 
881
 
1116
882
        g_free (filename);
1117
883
    }
1118
884
}
1119
885
 
1120
886
static void
1121
 
on_delete (GtkWidget *window)
 
887
on_delete (GtkWidget *window,
 
888
           Application *app)
1122
889
{
 
890
    /* Workaround for http://bugzilla.gnome.org/show_bug.cgi?id=317775
 
891
     *
 
892
     * Without it, the read callbacks can fire _after_ gtk_main_quit()
 
893
     * has been called and cause stuff to be called on destroyed widgets.
 
894
     */
 
895
    while (gtk_main_iteration ())
 
896
        ;
 
897
 
1123
898
    gtk_main_quit ();
1124
899
}
1125
900
 
1145
920
    gtk_tree_model_get (model, &iter,
1146
921
                        OBJECT_TOTAL, &top_value,
1147
922
                        -1);
1148
 
    
 
923
 
1149
924
    while (all_paths && n_rows < max_rows)
1150
925
    {
1151
926
        GtkTreeIter best_iter;
1161
936
        {
1162
937
            GtkTreePath *path = list->data;
1163
938
            GtkTreeIter iter;
1164
 
            double value;
 
939
 
1165
940
            g_assert (path != NULL);
 
941
 
1166
942
            if (gtk_tree_model_get_iter (model, &iter, path))
1167
943
            {
 
944
                double value;
1168
945
                gtk_tree_model_get (model, &iter,
1169
946
                                    OBJECT_TOTAL, &value,
1170
947
                                    -1);
1171
 
            }
1172
 
            if (value >= best_value)
1173
 
            {
1174
 
                best_value = value;
1175
 
                best_path = path;
1176
948
 
1177
 
                gtk_tree_model_get_iter (model, &best_iter, path);
 
949
                if (value >= best_value)
 
950
                {
 
951
                    best_value = value;
 
952
                    best_path = path;
 
953
                    best_iter = iter;
 
954
                }
1178
955
            }
1179
956
        }
1180
957
 
1181
 
        gtk_tree_model_get_iter (model, &iter, best_path);
1182
 
 
1183
958
        n_children = gtk_tree_model_iter_n_children (model, &best_iter);
1184
 
        
 
959
 
1185
960
        if (n_children && (best_value / top_value) > 0.04 &&
1186
 
            (n_children + gtk_tree_path_get_depth (best_path)) / (double)max_rows < (best_value / top_value) )
 
961
            (n_children + gtk_tree_path_get_depth (best_path)) /
 
962
            (double)max_rows < (best_value / top_value) )
1187
963
        {
1188
 
            gtk_tree_view_expand_row (GTK_TREE_VIEW (app->descendants_view), best_path, FALSE);
 
964
            gtk_tree_view_expand_row (
 
965
                GTK_TREE_VIEW (app->descendants_view), best_path, FALSE);
1189
966
            n_rows += n_children;
1190
967
 
1191
968
            if (gtk_tree_path_get_depth (best_path) < 4)
1200
977
                    path = gtk_tree_path_copy (path);
1201
978
                    gtk_tree_path_next (path);
1202
979
                }
 
980
 
1203
981
                gtk_tree_path_free (path);
1204
982
            }
1205
983
        }
1206
984
 
1207
985
        all_paths = g_list_remove (all_paths, best_path);
 
986
 
 
987
        if (!all_paths && n_rows == 1)
 
988
        {
 
989
            /* Always expand at least once */
 
990
            gtk_tree_view_expand_row (GTK_TREE_VIEW (app->descendants_view),
 
991
                                      best_path, FALSE);
 
992
        }
 
993
 
1208
994
        gtk_tree_path_free (best_path);
1209
995
    }
1210
996
 
1211
997
    for (list = all_paths; list != NULL; list = list->next)
1212
998
        gtk_tree_path_free (list->data);
1213
 
    
 
999
 
1214
1000
    g_list_free (all_paths);
1215
1001
}
1216
1002
 
1217
1003
static void
 
1004
get_data (GtkTreeView *view,
 
1005
          GtkTreeIter *iter,
 
1006
          gchar **name,
 
1007
          double *self,
 
1008
          double *cumulative)
 
1009
{
 
1010
    char *dummy1;
 
1011
    double dummy2;
 
1012
    double dummy3;
 
1013
 
 
1014
    GtkTreeModel *model = gtk_tree_view_get_model (view);
 
1015
    gtk_tree_model_get (
 
1016
        model, iter,
 
1017
        DESCENDANTS_NAME, name? name : &dummy1,
 
1018
        DESCENDANTS_SELF, self? self : &dummy2,
 
1019
        DESCENDANTS_CUMULATIVE, cumulative? cumulative : &dummy3,
 
1020
        -1);
 
1021
}
 
1022
 
 
1023
static int
 
1024
get_indent (GtkTreePath *path)
 
1025
{
 
1026
    return 2 * (gtk_tree_path_get_depth (path) - 1);
 
1027
}
 
1028
 
 
1029
static void
 
1030
compute_text_width (GtkTreeView  *view,
 
1031
                    GtkTreePath  *path,
 
1032
                    GtkTreeIter  *iter,
 
1033
                    gpointer      data)
 
1034
{
 
1035
    int *width = data;
 
1036
    char *name;
 
1037
 
 
1038
    get_data (view, iter, &name, NULL, NULL);
 
1039
 
 
1040
    *width = MAX (g_utf8_strlen (name, -1) + get_indent (path), *width);
 
1041
 
 
1042
    g_free (name);
 
1043
}
 
1044
 
 
1045
typedef struct
 
1046
{
 
1047
    int max_width;
 
1048
    GString *text;
 
1049
} AddTextInfo;
 
1050
 
 
1051
static void
 
1052
set_monospace (GtkWidget *widget)
 
1053
{
 
1054
    PangoFontDescription *desc =
 
1055
        pango_font_description_from_string ("monospace");
 
1056
 
 
1057
    gtk_widget_modify_font (widget, desc);
 
1058
 
 
1059
    pango_font_description_free (desc);
 
1060
}
 
1061
 
 
1062
static void
 
1063
add_text (GtkTreeView *view,
 
1064
          GtkTreePath *path,
 
1065
          GtkTreeIter *iter,
 
1066
          gpointer     data)
 
1067
{
 
1068
    AddTextInfo *info = data;
 
1069
    char *name;
 
1070
    double self;
 
1071
    double cumulative;
 
1072
    int indent;
 
1073
    int i;
 
1074
 
 
1075
    get_data (view, iter, &name, &self, &cumulative);
 
1076
 
 
1077
    indent = get_indent (path);
 
1078
 
 
1079
    for (i = 0; i < indent; ++i)
 
1080
        g_string_append_c (info->text, ' ');
 
1081
 
 
1082
    g_string_append_printf (info->text, "%-*s %6.2f%% %6.2f%%\n",
 
1083
                            info->max_width - indent, name, self, cumulative);
 
1084
 
 
1085
    g_free (name);
 
1086
}
 
1087
 
 
1088
static gboolean
 
1089
update_screenshot_window_idle (gpointer data)
 
1090
{
 
1091
    Application *app = data;
 
1092
    GtkTextBuffer *text_buffer;
 
1093
 
 
1094
    if (!app->screenshot_window_visible)
 
1095
        return FALSE;
 
1096
 
 
1097
    text_buffer =
 
1098
        gtk_text_view_get_buffer (GTK_TEXT_VIEW (app->screenshot_textview));
 
1099
 
 
1100
    gtk_text_buffer_set_text (text_buffer, "", -1);
 
1101
 
 
1102
    if (app->descendants)
 
1103
    {
 
1104
        AddTextInfo info;
 
1105
 
 
1106
        info.max_width = 0;
 
1107
        info.text = g_string_new ("");
 
1108
 
 
1109
        tree_view_foreach_visible (app->descendants_view,
 
1110
                                   compute_text_width,
 
1111
                                   &info.max_width);
 
1112
 
 
1113
        tree_view_foreach_visible (app->descendants_view,
 
1114
                                   add_text,
 
1115
                                   &info);
 
1116
 
 
1117
        gtk_text_buffer_set_text (text_buffer, info.text->str, -1);
 
1118
 
 
1119
        set_monospace (app->screenshot_textview);
 
1120
 
 
1121
        g_string_free (info.text, TRUE);
 
1122
    }
 
1123
 
 
1124
    app->update_screenshot_id = 0;
 
1125
 
 
1126
    if (app->screenshot_window_visible)
 
1127
    {
 
1128
        set_busy (app->screenshot_window, FALSE);
 
1129
        set_busy (app->screenshot_textview, FALSE);
 
1130
    }
 
1131
 
 
1132
    return FALSE;
 
1133
}
 
1134
 
 
1135
static void
 
1136
update_screenshot_window (Application *app)
 
1137
{
 
1138
    /* We do this in an idle handler to deal with the case where
 
1139
     * someone presses Shift-RightArrow on the root of a huge
 
1140
     * profile. This causes a ton of 'expanded' notifications,
 
1141
     * each of which would cause us to traverse the tree and
 
1142
     * update the screenshot window.
 
1143
     */
 
1144
    if (app->update_screenshot_id)
 
1145
        g_source_remove (app->update_screenshot_id);
 
1146
 
 
1147
    if (app->screenshot_window_visible)
 
1148
    {
 
1149
        /* don't swamp the X server with cursor change requests */
 
1150
        if (!app->update_screenshot_id)
 
1151
        {
 
1152
            set_busy (app->screenshot_window, TRUE);
 
1153
            set_busy (app->screenshot_textview, TRUE);
 
1154
        }
 
1155
    }
 
1156
 
 
1157
    app->update_screenshot_id = g_idle_add (
 
1158
        update_screenshot_window_idle, app);
 
1159
}
 
1160
 
 
1161
static void
 
1162
on_descendants_row_expanded_or_collapsed (GtkTreeView *tree,
 
1163
                                          GtkTreeIter *iter,
 
1164
                                          GtkTreePath *path,
 
1165
                                          Application *app)
 
1166
{
 
1167
    update_screenshot_window (app);
 
1168
}
 
1169
 
 
1170
static void
1218
1171
on_object_selection_changed (GtkTreeSelection *selection,
1219
 
                             gpointer data)
 
1172
                             gpointer          data)
1220
1173
{
1221
1174
    Application *app = data;
1222
1175
 
1223
1176
    set_busy (app->main_window, TRUE);
1224
1177
 
1225
 
    gdk_window_process_all_updates ();
1226
 
    
 
1178
    update_screenshot_window (app);
 
1179
 
 
1180
    if (!app->inhibit_forced_redraw)
 
1181
        gdk_window_process_all_updates (); /* Display updated selection */
 
1182
 
1227
1183
    fill_descendants_tree (app);
1228
1184
    fill_callers_list (app);
1229
1185
 
1230
1186
    if (get_current_object (app))
1231
1187
        expand_descendants_tree (app);
1232
 
    
 
1188
 
1233
1189
    set_busy (app->main_window, FALSE);
1234
1190
}
1235
1191
 
1236
1192
static void
1237
1193
really_goto_object (Application *app,
1238
 
                    ProfileObject *object)
 
1194
                    char *object)
1239
1195
{
1240
1196
    GtkTreeModel *profile_objects;
1241
1197
    GtkTreeIter iter;
1242
1198
    gboolean found = FALSE;
1243
 
    
 
1199
 
1244
1200
    profile_objects = gtk_tree_view_get_model (app->object_view);
1245
 
    
 
1201
 
1246
1202
    if (gtk_tree_model_get_iter_first (profile_objects, &iter))
1247
1203
    {
1248
1204
        do
1249
1205
        {
1250
 
            ProfileObject *profile_object;
1251
 
            
 
1206
            char *list_object;
 
1207
 
1252
1208
            gtk_tree_model_get (profile_objects, &iter,
1253
 
                                OBJECT_OBJECT, &profile_object,
 
1209
                                OBJECT_OBJECT, &list_object,
1254
1210
                                -1);
1255
 
            
1256
 
            if (profile_object == object)
 
1211
 
 
1212
            if (list_object == object)
1257
1213
            {
1258
1214
                found = TRUE;
1259
1215
                break;
1261
1217
        }
1262
1218
        while (gtk_tree_model_iter_next (profile_objects, &iter));
1263
1219
    }
1264
 
    
 
1220
 
1265
1221
    if (found)
1266
1222
    {
1267
1223
        GtkTreePath *path =
1268
1224
            gtk_tree_model_get_path (profile_objects, &iter);
1269
 
        
 
1225
 
1270
1226
        gtk_tree_view_set_cursor (app->object_view, path, 0, FALSE);
1271
1227
    }
1272
1228
}
1279
1235
{
1280
1236
    GtkTreeIter iter;
1281
1237
    GtkTreeModel *model = gtk_tree_view_get_model (tree_view);
1282
 
    ProfileObject *object;
1283
 
    
 
1238
    char *object;
 
1239
 
1284
1240
    if (!gtk_tree_model_get_iter (model, &iter, path))
1285
1241
        return;
1286
 
    
 
1242
 
1287
1243
    gtk_tree_model_get (model, &iter, column, &object, -1);
1288
 
    
 
1244
 
1289
1245
    if (!object)
1290
1246
        return;
1291
 
    
 
1247
 
1292
1248
    really_goto_object (app, object);
1293
 
    
1294
1249
}
1295
1250
 
1296
1251
static void
1300
1255
                              gpointer data)
1301
1256
{
1302
1257
    Application *app = data;
1303
 
    
 
1258
 
1304
1259
    goto_object (app, tree_view, path, DESCENDANTS_OBJECT);
1305
 
    
 
1260
 
1306
1261
    gtk_widget_grab_focus (GTK_WIDGET (app->descendants_view));
1307
1262
}
1308
1263
 
1313
1268
                          gpointer data)
1314
1269
{
1315
1270
    Application *app = data;
1316
 
    
 
1271
 
1317
1272
    goto_object (app, tree_view, path, CALLERS_OBJECT);
1318
1273
 
1319
1274
    gtk_widget_grab_focus (GTK_WIDGET (app->callers_view));
1320
1275
}
1321
1276
 
1322
1277
static void
 
1278
on_screenshot_activated (GtkCheckMenuItem *menu_item,
 
1279
                         Application      *app)
 
1280
{
 
1281
    app->screenshot_window_visible = gtk_check_menu_item_get_active (menu_item);
 
1282
 
 
1283
    update_screenshot_window (app);
 
1284
 
 
1285
    update_sensitivity (app);
 
1286
}
 
1287
 
 
1288
static void
 
1289
on_screenshot_window_delete (GtkWidget   *window,
 
1290
                             GdkEvent    *event,
 
1291
                             Application *app)
 
1292
{
 
1293
    app->screenshot_window_visible = FALSE;
 
1294
 
 
1295
    update_sensitivity (app);
 
1296
}
 
1297
 
 
1298
static void
 
1299
on_screenshot_close_button_clicked (GtkWidget *widget,
 
1300
                                    Application *app)
 
1301
{
 
1302
    app->screenshot_window_visible = FALSE;
 
1303
 
 
1304
    update_sensitivity (app);
 
1305
}
 
1306
 
 
1307
static void
1323
1308
set_sizes (GtkWindow *window,
 
1309
           GtkWindow *screenshot_window,
1324
1310
           GtkWidget *hpaned,
1325
1311
           GtkWidget *vpaned)
1326
1312
{
1329
1315
    GdkRectangle monitor;
1330
1316
    int width, height;
1331
1317
    GtkWidget *widget = GTK_WIDGET (window);
1332
 
    
 
1318
 
1333
1319
    screen = gtk_widget_get_screen (widget);
1334
1320
    monitor_num = gdk_screen_get_monitor_at_window (screen, widget->window);
1335
 
    
 
1321
 
1336
1322
    gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
1337
 
    
 
1323
 
1338
1324
    width = monitor.width * 3 / 4;
1339
1325
    height = monitor.height * 3 / 4;
1340
 
    
 
1326
 
1341
1327
    gtk_window_resize (window, width, height);
1342
 
    
 
1328
 
1343
1329
    gtk_paned_set_position (GTK_PANED (vpaned), height / 2);
1344
 
    gtk_paned_set_position (GTK_PANED (hpaned), width / 2);
 
1330
    gtk_paned_set_position (GTK_PANED (hpaned), width * 3 / 8);
 
1331
 
 
1332
    width = monitor.width * 5 / 8;
 
1333
    height = monitor.height * 5 / 8;
 
1334
 
 
1335
    gtk_window_resize (screenshot_window, width, height);
 
1336
}
 
1337
 
 
1338
#define GLADE_FILE DATADIR "/sysprof.glade"
 
1339
 
 
1340
static void
 
1341
gather_widgets (Application *app)
 
1342
{
 
1343
    typedef struct
 
1344
    {
 
1345
        void *location;
 
1346
        const char *name;
 
1347
    } WidgetInfo;
 
1348
 
 
1349
    const WidgetInfo widgets[] =
 
1350
        {
 
1351
            { &app->main_window, "main_window" },
 
1352
            { &app->start_button, "start_button" },
 
1353
            { &app->profile_button, "profile_button" },
 
1354
            { &app->reset_button, "reset_button" },
 
1355
            { &app->save_as_button, "save_as_button" },
 
1356
            { &app->dummy_button, "dummy_button" },
 
1357
            { &app->samples_label, "samples_label" },
 
1358
            { &app->samples_hbox, "samples_hbox" },
 
1359
            { &app->start_item, "start_item" },
 
1360
            { &app->profile_item, "profile_item" },
 
1361
            { &app->reset_item, "reset_item" },
 
1362
            { &app->open_item, "open_item" },
 
1363
            { &app->save_as_item, "save_as_item" },
 
1364
            { &app->screenshot_item, "screenshot_item" },
 
1365
            { &app->quit_item, "quit" },
 
1366
            { &app->about_item, "about" },
 
1367
            { &app->object_view, "object_view" },
 
1368
            { &app->callers_view, "callers_view" },
 
1369
            { &app->descendants_view, "descendants_view" },
 
1370
            { &app->screenshot_window, "screenshot_window" },
 
1371
            { &app->screenshot_textview, "screenshot_textview" },
 
1372
            { &app->screenshot_close_button, "screenshot_close_button" },
 
1373
            { &app->vpaned, "vpaned" },
 
1374
            { &app->hpaned, "hpaned" },
 
1375
        };
 
1376
 
 
1377
    GladeXML *xml = glade_xml_new (GLADE_FILE, NULL, NULL);
 
1378
    int i;
 
1379
 
 
1380
    for (i = 0; i < G_N_ELEMENTS (widgets); ++i)
 
1381
    {
 
1382
        const WidgetInfo *info = &(widgets[i]);
 
1383
 
 
1384
        *(GtkWidget **)(info->location) = glade_xml_get_widget (xml, info->name);
 
1385
 
 
1386
        g_assert (GTK_IS_WIDGET (*(GtkWidget **)info->location));
 
1387
    }
 
1388
 
 
1389
    g_object_unref (xml);
 
1390
}
 
1391
 
 
1392
static void
 
1393
connect_signals (Application *app)
 
1394
{
 
1395
    typedef struct
 
1396
    {
 
1397
        gpointer object;
 
1398
        const char *signal;
 
1399
        gpointer callback;
 
1400
        gpointer data;
 
1401
    } SignalInfo;
 
1402
 
 
1403
    const SignalInfo signals[] =
 
1404
        {
 
1405
            { app->main_window, "delete_event", on_delete, NULL },
 
1406
            { app->start_button, "toggled", on_start_toggled, app },
 
1407
            { app->profile_button, "toggled", on_profile_toggled, app },
 
1408
            { app->reset_button, "clicked", on_reset_clicked, app },
 
1409
            { app->save_as_button, "clicked", on_save_as_clicked, app },
 
1410
            { app->start_item, "activate", on_menu_item_activated, app->start_button },
 
1411
            { app->profile_item, "activate", on_menu_item_activated, app->profile_button },
 
1412
            { app->reset_item, "activate", on_reset_clicked, app },
 
1413
            { app->open_item, "activate", on_open_clicked, app },
 
1414
            { app->save_as_item, "activate", on_save_as_clicked, app },
 
1415
            { app->screenshot_item, "activate", on_screenshot_activated, app },
 
1416
            { app->quit_item, "activate", on_delete, NULL },
 
1417
            { app->about_item, "activate", on_about_activated, app },
 
1418
            { app->object_selection, "changed", on_object_selection_changed, app },
 
1419
            { app->callers_view, "row-activated", on_callers_row_activated, app },
 
1420
            { app->descendants_view, "row-activated", on_descendants_row_activated, app },
 
1421
            { app->descendants_view, "row-expanded", on_descendants_row_expanded_or_collapsed, app },
 
1422
            { app->descendants_view, "row-collapsed", on_descendants_row_expanded_or_collapsed, app },
 
1423
            { app->screenshot_window, "delete_event", on_screenshot_window_delete, app },
 
1424
            { app->screenshot_close_button, "clicked", on_screenshot_close_button_clicked, app },
 
1425
        };
 
1426
 
 
1427
    int i;
 
1428
 
 
1429
    for (i = 0; i < G_N_ELEMENTS (signals); ++i)
 
1430
    {
 
1431
        const SignalInfo *info = &(signals[i]);
 
1432
 
 
1433
        g_signal_connect (info->object, info->signal, info->callback, info->data);
 
1434
    }
1345
1435
}
1346
1436
 
1347
1437
static void
1361
1451
}
1362
1452
 
1363
1453
static void
 
1454
set_icons (Application *app)
 
1455
{
 
1456
    const char *icon_files [] = {
 
1457
        PIXMAPDIR "/sysprof-icon-16.png",
 
1458
        PIXMAPDIR "/sysprof-icon-24.png",
 
1459
        PIXMAPDIR "/sysprof-icon-32.png",
 
1460
        PIXMAPDIR "/sysprof-icon-48.png",
 
1461
        NULL
 
1462
    };
 
1463
    GList *pixbufs = NULL;
 
1464
    int i;
 
1465
 
 
1466
    for (i = 0; icon_files[i] != NULL; ++i)
 
1467
    {
 
1468
        const char *file = icon_files[i];
 
1469
        GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file (file, NULL);
 
1470
 
 
1471
        if (pixbuf)
 
1472
        {
 
1473
            pixbufs = g_list_prepend (pixbufs, pixbuf);
 
1474
 
 
1475
            if (i == 3) /* 48 x 48 */
 
1476
                app->icon = g_object_ref (pixbuf);
 
1477
        }
 
1478
        else
 
1479
        {
 
1480
            g_warning ("Could not open %s\n", file);
 
1481
        }
 
1482
    }
 
1483
 
 
1484
    gtk_window_set_icon_list (GTK_WINDOW (app->main_window), pixbufs);
 
1485
 
 
1486
    g_list_foreach (pixbufs, (GFunc)g_object_unref, NULL);
 
1487
    g_list_free (pixbufs);
 
1488
}
 
1489
 
 
1490
#define PCT_FORMAT "%.2f<span size='smaller'><span size='smaller'> </span>%%</span>"
 
1491
 
 
1492
static gboolean
1364
1493
build_gui (Application *app)
1365
1494
{
1366
 
    GladeXML *xml;
1367
 
    GtkTreeSelection *selection;
1368
1495
    GtkTreeViewColumn *col;
1369
1496
 
1370
1497
    set_shadows ();
1371
 
    
1372
 
    xml = glade_xml_new (DATADIR "/sysprof.glade", NULL, NULL);
1373
 
    
 
1498
 
 
1499
    if (!g_file_test (GLADE_FILE, G_FILE_TEST_EXISTS))
 
1500
    {
 
1501
        sorry (NULL,
 
1502
               "Sysprof was not compiled or installed correctly.\n"
 
1503
               "\n"
 
1504
               "Running \"make install\" may solve this problem.\n");
 
1505
 
 
1506
        return FALSE;
 
1507
    }
 
1508
 
 
1509
    gather_widgets (app);
 
1510
 
 
1511
    g_assert (app->main_window);
 
1512
 
1374
1513
    /* Main Window */
1375
 
    app->main_window = glade_xml_get_widget (xml, "main_window");
1376
 
    app->icon = gdk_pixbuf_new_from_file (PIXMAPDIR "/sysprof-icon.png", NULL);
 
1514
    set_icons (app);
1377
1515
 
1378
 
    gtk_window_set_icon (GTK_WINDOW (app->main_window), app->icon);
1379
 
    
1380
 
    g_signal_connect (G_OBJECT (app->main_window), "delete_event",
1381
 
                      G_CALLBACK (on_delete), NULL);
1382
 
    
1383
1516
    gtk_widget_realize (GTK_WIDGET (app->main_window));
1384
 
    set_sizes (GTK_WINDOW (app->main_window),
1385
 
               glade_xml_get_widget (xml, "hpaned"),
1386
 
               glade_xml_get_widget (xml, "vpaned"));
1387
 
    
 
1517
 
1388
1518
    /* Tool items */
1389
 
    
1390
 
    app->start_button = glade_xml_get_widget (xml, "start_button");
1391
 
    app->profile_button = glade_xml_get_widget (xml, "profile_button");
1392
 
    app->reset_button = glade_xml_get_widget (xml, "reset_button");
1393
 
    app->save_as_button = glade_xml_get_widget (xml, "save_as_button");
1394
 
    app->dummy_button = glade_xml_get_widget (xml, "dummy_button");
1395
 
    
1396
1519
    gtk_toggle_tool_button_set_active (
1397
1520
        GTK_TOGGLE_TOOL_BUTTON (app->profile_button), FALSE);
1398
 
    
1399
 
    g_signal_connect (G_OBJECT (app->start_button), "toggled",
1400
 
                      G_CALLBACK (on_start_toggled), app);
1401
 
    
1402
 
    g_signal_connect (G_OBJECT (app->profile_button), "toggled",
1403
 
                      G_CALLBACK (on_profile_toggled), app);
1404
 
    
1405
 
    g_signal_connect (G_OBJECT (app->reset_button), "clicked",
1406
 
                      G_CALLBACK (on_reset_clicked), app);
1407
 
    
1408
 
    g_signal_connect (G_OBJECT (app->save_as_button), "clicked",
1409
 
                      G_CALLBACK (on_save_as_clicked), app);
1410
 
 
1411
 
    
1412
 
    app->samples_label = glade_xml_get_widget (xml, "samples_label");
1413
 
    
1414
 
    /* Menu items */
1415
 
    app->start_item = glade_xml_get_widget (xml, "start_item");
1416
 
    app->profile_item = glade_xml_get_widget (xml, "profile_item");
1417
 
    app->reset_item = glade_xml_get_widget (xml, "reset_item");
1418
 
    app->open_item = glade_xml_get_widget (xml, "open_item");
1419
 
    app->save_as_item = glade_xml_get_widget (xml, "save_as_item");
1420
 
    
1421
 
    g_assert (app->start_item);
1422
 
    g_assert (app->profile_item);
1423
 
    g_assert (app->save_as_item);
1424
 
    g_assert (app->open_item);
1425
 
    
1426
 
    g_signal_connect (G_OBJECT (app->start_item), "activate",
1427
 
                      G_CALLBACK (on_menu_item_activated), app->start_button);
1428
 
    
1429
 
    g_signal_connect (G_OBJECT (app->profile_item), "activate",
1430
 
                      G_CALLBACK (on_menu_item_activated), app->profile_button);
1431
 
    
1432
 
    g_signal_connect (G_OBJECT (app->reset_item), "activate",
1433
 
                      G_CALLBACK (on_reset_clicked), app);
1434
 
 
1435
 
    g_signal_connect (G_OBJECT (app->open_item), "activate",
1436
 
                      G_CALLBACK (on_open_clicked), app);
1437
 
    
1438
 
    g_signal_connect (G_OBJECT (app->save_as_item), "activate",
1439
 
                      G_CALLBACK (on_save_as_clicked), app);
1440
 
 
1441
 
    g_signal_connect (G_OBJECT (glade_xml_get_widget (xml, "quit")), "activate",
1442
 
                      G_CALLBACK (on_delete), NULL);
1443
 
 
1444
 
    g_signal_connect (G_OBJECT (glade_xml_get_widget (xml, "about")), "activate",
1445
 
                      G_CALLBACK (on_about_activated), app);
1446
 
    
 
1521
 
1447
1522
    /* TreeViews */
1448
 
    
 
1523
 
1449
1524
    /* object view */
1450
 
    app->object_view = (GtkTreeView *)glade_xml_get_widget (xml, "object_view");
1451
1525
    gtk_tree_view_set_enable_search (app->object_view, FALSE);
1452
 
    col = add_plain_text_column (app->object_view, _("Functions"), OBJECT_NAME);
1453
 
    add_double_format_column (app->object_view, _("Self"), OBJECT_SELF, "%.2f ");
1454
 
    add_double_format_column (app->object_view, _("Total"), OBJECT_TOTAL, "%.2f ");
1455
 
    selection = gtk_tree_view_get_selection (app->object_view);
1456
 
    g_signal_connect (selection, "changed", G_CALLBACK (on_object_selection_changed), app);
 
1526
    col = add_plain_text_column (app->object_view, _("Functions"),
 
1527
                                 OBJECT_NAME);
 
1528
    add_double_format_column (app->object_view, _("Self"),
 
1529
                              OBJECT_SELF, PCT_FORMAT);
 
1530
    add_double_format_column (app->object_view, _("Total"),
 
1531
                              OBJECT_TOTAL, PCT_FORMAT);
 
1532
    app->object_selection = gtk_tree_view_get_selection (app->object_view);
1457
1533
    gtk_tree_view_column_set_expand (col, TRUE);
1458
 
    
 
1534
 
1459
1535
    /* callers view */
1460
 
    app->callers_view = (GtkTreeView *)glade_xml_get_widget (xml, "callers_view");
1461
1536
    gtk_tree_view_set_enable_search (app->callers_view, FALSE);
1462
 
    col = add_plain_text_column (app->callers_view, _("Callers"), CALLERS_NAME);
1463
 
    add_double_format_column (app->callers_view, _("Self"), CALLERS_SELF, "%.2f ");
1464
 
    add_double_format_column (app->callers_view, _("Total"), CALLERS_TOTAL, "%.2f ");
1465
 
    g_signal_connect (app->callers_view, "row-activated",
1466
 
                      G_CALLBACK (on_callers_row_activated), app);
 
1537
    col = add_plain_text_column (app->callers_view, _("Callers"),
 
1538
                                 CALLERS_NAME);
 
1539
    add_double_format_column (app->callers_view, _("Self"),
 
1540
                              CALLERS_SELF, PCT_FORMAT);
 
1541
    add_double_format_column (app->callers_view, _("Total"),
 
1542
                              CALLERS_TOTAL, PCT_FORMAT);
1467
1543
    gtk_tree_view_column_set_expand (col, TRUE);
1468
 
    
 
1544
 
1469
1545
    /* descendants view */
1470
 
    app->descendants_view = (GtkTreeView *)glade_xml_get_widget (xml, "descendants_view");
1471
1546
    gtk_tree_view_set_enable_search (app->descendants_view, FALSE);
1472
 
    col = add_plain_text_column (app->descendants_view, _("Descendants"), DESCENDANTS_NAME);
1473
 
    add_double_format_column (app->descendants_view, _("Self"), DESCENDANTS_SELF, "%.2f ");
1474
 
    add_double_format_column (app->descendants_view, _("Cumulative"), DESCENDANTS_NON_RECURSE, "%.2f ");
1475
 
    g_signal_connect (app->descendants_view, "row-activated",
1476
 
                      G_CALLBACK (on_descendants_row_activated), app);
 
1547
    col = add_plain_text_column (app->descendants_view, _("Descendants"),
 
1548
                                 DESCENDANTS_NAME);
 
1549
    add_double_format_column (app->descendants_view, _("Self"),
 
1550
                              DESCENDANTS_SELF, PCT_FORMAT);
 
1551
    add_double_format_column (app->descendants_view, _("Cumulative"),
 
1552
                              DESCENDANTS_CUMULATIVE, PCT_FORMAT);
1477
1553
    gtk_tree_view_column_set_expand (col, TRUE);
1478
 
    
1479
 
    gtk_widget_grab_focus (GTK_WIDGET (app->object_view));
 
1554
 
 
1555
    /* screenshot window */
 
1556
 
 
1557
    /* set sizes */
 
1558
    set_sizes (GTK_WINDOW (app->main_window),
 
1559
               GTK_WINDOW (app->screenshot_window),
 
1560
               app->hpaned, app->vpaned);
 
1561
 
 
1562
    /* hide/show widgets */
1480
1563
    gtk_widget_show_all (app->main_window);
1481
1564
    gtk_widget_hide (app->dummy_button);
1482
 
    
1483
 
    /* Statusbar */
 
1565
    gtk_widget_hide (app->screenshot_window);
 
1566
 
 
1567
    gtk_widget_grab_focus (GTK_WIDGET (app->object_view));
1484
1568
    queue_show_samples (app);
 
1569
 
 
1570
    connect_signals (app);
 
1571
 
 
1572
    return TRUE;
 
1573
}
 
1574
 
 
1575
static void
 
1576
on_new_sample (gboolean first_sample,
 
1577
               gpointer data)
 
1578
{
 
1579
    Application *app = data;
 
1580
 
 
1581
    if (app->state == PROFILING && first_sample)
 
1582
        update_sensitivity (app);
 
1583
    else
 
1584
        queue_show_samples (app);
1485
1585
}
1486
1586
 
1487
1587
static Application *
1488
1588
application_new (void)
1489
1589
{
1490
1590
    Application *app = g_new0 (Application, 1);
1491
 
    
1492
 
    app->stash = stack_stash_new ();
1493
 
    app->input_fd = -1;
 
1591
 
 
1592
    app->collector = collector_new (FALSE, on_new_sample, app);
1494
1593
    app->state = INITIAL;
1495
1594
 
1496
 
    g_get_current_time (&app->latest_reset);
1497
 
    
1498
1595
    return app;
1499
1596
}
1500
1597
 
1514
1611
    Profile *profile;
1515
1612
 
1516
1613
    set_busy (app->main_window, TRUE);
1517
 
    
 
1614
 
1518
1615
    profile = profile_load (filename, &err);
1519
 
    
1520
 
    set_busy (app->main_window, FALSE);
1521
 
    
 
1616
 
1522
1617
    if (profile)
1523
1618
    {
1524
1619
        set_loaded_profile (app, filename, profile);
 
1620
 
 
1621
        gdk_window_process_all_updates ();
 
1622
        set_busy (app->main_window, FALSE);
1525
1623
    }
1526
1624
    else
1527
1625
    {
 
1626
        set_busy (app->main_window, FALSE);
 
1627
 
1528
1628
        show_could_not_open (app, filename, err);
1529
1629
        g_error_free (err);
1530
1630
    }
1531
1631
 
 
1632
    g_free (file_open_data);
 
1633
 
1532
1634
    return FALSE;
1533
1635
}
1534
1636
 
 
1637
static const char *
 
1638
process_options (int           argc,
 
1639
                 char        **argv)
 
1640
{
 
1641
    int i;
 
1642
    gboolean show_version = FALSE;
 
1643
    const char *filename = NULL;
 
1644
 
 
1645
    for (i = 1; i < argc; ++i)
 
1646
    {
 
1647
        char *option = argv[i];
 
1648
 
 
1649
        if (strcmp (option, "--version") == 0)
 
1650
        {
 
1651
            show_version = TRUE;
 
1652
        }
 
1653
        else if (!filename)
 
1654
        {
 
1655
            filename = argv[i];
 
1656
        }
 
1657
    }
 
1658
 
 
1659
    if (show_version)
 
1660
    {
 
1661
        g_print ("%s %s\n", APPLICATION_NAME, PACKAGE_VERSION);
 
1662
 
 
1663
        exit (1);
 
1664
    }
 
1665
 
 
1666
    return filename;
 
1667
}
 
1668
 
 
1669
static void
 
1670
apply_workarounds (void)
 
1671
{
 
1672
 
 
1673
    /* Disable gslice, since it
 
1674
     *
 
1675
     *  - confuses valgrind
 
1676
     *  - caches too much memory
 
1677
     *  - hides memory access bugs
 
1678
     *  - is not faster than malloc
 
1679
     *
 
1680
     * Note that g_slice_set_config() is broken in some versions of
 
1681
     * GLib (and 'declared internal' according to Tim), so we use the
 
1682
     * environment variable instead.
 
1683
     */
 
1684
    if (!getenv ("G_SLICE"))
 
1685
        putenv ("G_SLICE=always_malloc");
 
1686
 
 
1687
    /* Accessibility prevents sysprof from working reliably, so
 
1688
     * disable it. Specifically, it
 
1689
     *
 
1690
     *  - causes large amounts of time to be spent in sysprof itself
 
1691
     *    whenever the label is updated.
 
1692
     *  - sometimes hangs at shutdown
 
1693
     *  - does long-running roundtrip requests that prevents
 
1694
     *    reading the event buffers, resulting in lost events.
 
1695
     */
 
1696
    putenv ("NO_GAIL=1");
 
1697
    putenv ("NO_AT_BRIDGE=1");
 
1698
}
 
1699
 
1535
1700
int
1536
 
main (int argc, char **argv)
 
1701
main (int    argc,
 
1702
      char **argv)
1537
1703
{
1538
1704
    Application *app;
1539
 
    
 
1705
    const char *filename;
 
1706
 
 
1707
    apply_workarounds();
 
1708
 
 
1709
    filename = process_options (argc, argv);
 
1710
 
1540
1711
    gtk_init (&argc, &argv);
1541
 
    
 
1712
 
1542
1713
    app = application_new ();
1543
 
    
1544
 
#if 0
1545
 
    nice (-19);
1546
 
    g_timeout_add (10, on_timeout, app);
1547
 
#endif
1548
 
    
1549
 
    build_gui (app);
1550
 
    
 
1714
 
 
1715
    if (!build_gui (app))
 
1716
        return -1;
 
1717
 
1551
1718
    update_sensitivity (app);
1552
1719
 
1553
 
    if (argc > 1)
 
1720
    if (filename)
1554
1721
    {
1555
1722
        FileOpenData *file_open_data = g_new0 (FileOpenData, 1);
1556
 
 
1557
 
        file_open_data->filename = argv[1];
 
1723
        file_open_data->filename = filename;
1558
1724
        file_open_data->app = app;
1559
1725
 
1560
 
        g_idle_add (load_file, file_open_data);
 
1726
        /* This has to run at G_PRIORITY_LOW because of bug 350517
 
1727
         */
 
1728
        g_idle_add_full (G_PRIORITY_LOW, load_file, file_open_data, NULL);
1561
1729
    }
1562
1730
 
1563
1731
    gtk_main ();
1564
 
    
 
1732
 
1565
1733
    return 0;
1566
1734
}