~ubuntu-branches/ubuntu/raring/sysprof/raring-proposed

« back to all changes in this revision

Viewing changes to .pc/better_help_for_missing_module.patch/sysprof.c

  • Committer: Bazaar Package Importer
  • Author(s): Ritesh Raj Sarraf
  • Date: 2010-06-13 15:09:31 UTC
  • Revision ID: james.westby@ubuntu.com-20100613150931-7ny43o6qd7a81961
Tags: 1.0.12-2
* Take maintenance (Closes: #445205)
* Update Standards Version to 3.8.4 (No changes required) 
* Add homepage and Vcs details 
* Add misc:Depends to make it lintian clean 
* Update module version to current package version 
* Drop autotools-dev and automake1.9 from build depends 

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Sysprof -- Sampling, systemwide CPU profiler
 
2
 * Copyright 2004, Red Hat, Inc.
 
3
 * Copyright 2004, 2005, 2006, 2007, Soeren Sandmann
 
4
 *
 
5
 * This program is free software; you can redistribute it and/or modify
 
6
 * it under the terms of the GNU General Public License as published by
 
7
 * the Free Software Foundation; either version 2 of the License, or
 
8
 * (at your option) any later version.
 
9
 *
 
10
 * This program is distributed in the hope that it will be useful,
 
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 * GNU General Public License for more details.
 
14
 *
 
15
 * You should have received a copy of the GNU General Public License
 
16
 * along with this program; if not, write to the Free Software
 
17
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
18
 */
 
19
 
 
20
#include <config.h>
 
21
 
 
22
#include <stdio.h>
 
23
#include <gtk/gtk.h>
 
24
#include <stdlib.h>
 
25
#include <fcntl.h>
 
26
#include <unistd.h>
 
27
#include <glade/glade.h>
 
28
#include <errno.h>
 
29
#include <glib/gprintf.h>
 
30
#include <sys/wait.h>
 
31
#include <sys/types.h>
 
32
 
 
33
#include "binfile.h"
 
34
#include "watch.h"
 
35
#include "module/sysprof-module.h"
 
36
#include "stackstash.h"
 
37
#include "profile.h"
 
38
#include "treeviewutils.h"
 
39
 
 
40
/* FIXME - not10 */
 
41
#define _(a) a
 
42
 
 
43
#define APPLICATION_NAME "System Profiler"
 
44
 
 
45
typedef struct Application Application;
 
46
 
 
47
typedef enum
 
48
{
 
49
    INITIAL,
 
50
    DISPLAYING,
 
51
    PROFILING
 
52
} State;
 
53
 
 
54
struct Application
 
55
{
 
56
    int                 input_fd;
 
57
    State               state;
 
58
    StackStash *        stash;
 
59
    
 
60
    GtkWidget *         main_window;
 
61
    GdkPixbuf *         icon;
 
62
    
 
63
    GtkTreeView *       object_view;
 
64
    GtkTreeView *       callers_view;
 
65
    GtkTreeView *       descendants_view;
 
66
    
 
67
    GtkWidget *         start_button;
 
68
    GtkWidget *         profile_button;
 
69
    GtkWidget *         reset_button;
 
70
    GtkWidget *         save_as_button;
 
71
    GtkWidget *         dummy_button;
 
72
    
 
73
    GtkWidget *         start_item;
 
74
    GtkWidget *         profile_item;
 
75
    GtkWidget *         reset_item;
 
76
    GtkWidget *         save_as_item;
 
77
    GtkWidget *         open_item;
 
78
    
 
79
    GtkWidget *         samples_label;
 
80
    
 
81
    Profile *           profile;
 
82
    ProfileDescendant * descendants;
 
83
    ProfileCaller *     callers;
 
84
    
 
85
    int                 n_samples;
 
86
    
 
87
    int                 timeout_id;
 
88
    int                 generating_profile;
 
89
 
 
90
    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;
 
108
};
 
109
 
 
110
static gboolean
 
111
show_samples_timeout (gpointer data)
 
112
{
 
113
    Application *app = data;
 
114
    char *label;
 
115
 
 
116
    switch (app->state)
 
117
    {
 
118
    case INITIAL:
 
119
        label = g_strdup ("Samples: 0");
 
120
        break;
 
121
        
 
122
    case PROFILING:
 
123
    case DISPLAYING:
 
124
        label = g_strdup_printf ("Samples: %d", app->n_samples);
 
125
        break;
 
126
 
 
127
    default:
 
128
        g_assert_not_reached();
 
129
        break;
 
130
    }
 
131
    
 
132
    gtk_label_set_label (GTK_LABEL (app->samples_label), label);
 
133
    
 
134
    g_free (label);
 
135
    
 
136
    app->timeout_id = 0;
 
137
    
 
138
    return FALSE;
 
139
}
 
140
 
 
141
static void
 
142
queue_show_samples (Application *app)
 
143
{
 
144
    if (!app->timeout_id)
 
145
        app->timeout_id = g_timeout_add (225, show_samples_timeout, app);
 
146
}
 
147
 
 
148
static void
 
149
update_sensitivity (Application *app)
 
150
{
 
151
    gboolean sensitive_profile_button;
 
152
    gboolean sensitive_save_as_button;
 
153
    gboolean sensitive_start_button;
 
154
    gboolean sensitive_tree_views;
 
155
    gboolean sensitive_samples_label;
 
156
    gboolean sensitive_reset_button;
 
157
    
 
158
    GtkWidget *active_radio_button;
 
159
    
 
160
    switch (app->state)
 
161
    {
 
162
    case INITIAL:
 
163
        sensitive_profile_button = FALSE;
 
164
        sensitive_save_as_button = FALSE;
 
165
        sensitive_start_button = TRUE;
 
166
        sensitive_reset_button = FALSE;
 
167
        sensitive_tree_views = FALSE;
 
168
        sensitive_samples_label = FALSE;
 
169
        active_radio_button = app->dummy_button;
 
170
        break;
 
171
        
 
172
    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);
 
176
        sensitive_start_button = TRUE;
 
177
        sensitive_tree_views = FALSE;
 
178
        sensitive_samples_label = TRUE;
 
179
        active_radio_button = app->start_button;
 
180
        break;
 
181
        
 
182
    case DISPLAYING:
 
183
        sensitive_profile_button = TRUE;
 
184
        sensitive_save_as_button = TRUE;
 
185
        sensitive_start_button = TRUE;
 
186
        sensitive_tree_views = TRUE;
 
187
        sensitive_reset_button = TRUE;
 
188
        sensitive_samples_label = FALSE;
 
189
        active_radio_button = app->profile_button;
 
190
        break;
 
191
 
 
192
    default:
 
193
        g_assert_not_reached();
 
194
        break;
 
195
    }
 
196
    
 
197
    gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (active_radio_button), TRUE);
 
198
 
 
199
    /* "profile" widgets */
 
200
    gtk_widget_set_sensitive (GTK_WIDGET (app->profile_button),
 
201
                              sensitive_profile_button);
 
202
    gtk_widget_set_sensitive (GTK_WIDGET (app->profile_item),
 
203
                              sensitive_profile_button);
 
204
    
 
205
    /* "save as" widgets */
 
206
    gtk_widget_set_sensitive (GTK_WIDGET (app->save_as_button),
 
207
                              sensitive_save_as_button);
 
208
    gtk_widget_set_sensitive (app->save_as_item,
 
209
                              sensitive_save_as_button);
 
210
 
 
211
    /* "start" widgets */
 
212
    gtk_widget_set_sensitive (GTK_WIDGET (app->start_button),
 
213
                              sensitive_start_button);
 
214
    gtk_widget_set_sensitive (GTK_WIDGET (app->start_item),
 
215
                              sensitive_start_button);
 
216
    
 
217
#if 0
 
218
    /* FIXME - not10: gtk+ doesn't handle changes in sensitivity in response 
 
219
     * to a click on the same button very well
 
220
     */
 
221
    gtk_widget_set_sensitive (GTK_WIDGET (app->reset_button),
 
222
                              sensitive_reset_button);
 
223
    gtk_widget_set_sensitive (GTK_WIDGET (app->reset_item),
 
224
                              sensitive_reset_button);
 
225
#endif
 
226
    
 
227
    gtk_widget_set_sensitive (GTK_WIDGET (app->object_view), sensitive_tree_views);
 
228
    gtk_widget_set_sensitive (GTK_WIDGET (app->callers_view), sensitive_tree_views);
 
229
    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);
 
233
}
 
234
 
 
235
static void
 
236
set_busy (GtkWidget *widget, gboolean busy)
 
237
{
 
238
    GdkCursor *cursor;
 
239
    
 
240
    if (busy)
 
241
        cursor = gdk_cursor_new (GDK_WATCH);
 
242
    else
 
243
        cursor = NULL;
 
244
 
 
245
    gdk_window_set_cursor (widget->window, cursor);
 
246
    
 
247
    if (cursor)
 
248
        gdk_cursor_unref (cursor);
 
249
 
 
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);
 
397
}
 
398
 
 
399
static void
 
400
set_application_title (Application *app,
 
401
                       const char * name)
 
402
{
 
403
    char *new_name;
 
404
    if (name)
 
405
        new_name = g_path_get_basename (name);
 
406
    else
 
407
        new_name = NULL;
 
408
    
 
409
    if (app->loaded_profile)
 
410
        g_free (app->loaded_profile);
 
411
 
 
412
    app->loaded_profile = new_name;
 
413
    
 
414
    if (app->loaded_profile)
 
415
    {
 
416
        gtk_window_set_title (GTK_WINDOW (app->main_window),
 
417
                              app->loaded_profile);
 
418
    }
 
419
    else
 
420
    {
 
421
        gtk_window_set_title (GTK_WINDOW (app->main_window),
 
422
                              "System Profiler");
 
423
    }
 
424
}
 
425
 
 
426
static void
 
427
delete_data (Application *app)
 
428
{
 
429
    if (app->profile)
 
430
    {
 
431
        profile_free (app->profile);
 
432
        app->profile = NULL;
 
433
        
 
434
        gtk_tree_view_set_model (GTK_TREE_VIEW (app->object_view), NULL);
 
435
        gtk_tree_view_set_model (GTK_TREE_VIEW (app->callers_view), NULL);
 
436
        gtk_tree_view_set_model (GTK_TREE_VIEW (app->descendants_view), NULL);
 
437
    }
 
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;
 
446
    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
}
 
479
 
 
480
static void
 
481
sorry (GtkWidget *parent_window,
 
482
       const gchar *format,
 
483
       ...)
 
484
{
 
485
    va_list args;
 
486
    char *message;
 
487
    GtkWidget *dialog;
 
488
    
 
489
    va_start (args, format);
 
490
    g_vasprintf (&message, format, args);
 
491
    va_end (args);
 
492
    
 
493
    dialog = gtk_message_dialog_new (parent_window ? GTK_WINDOW (parent_window) : NULL,
 
494
                                     GTK_DIALOG_DESTROY_WITH_PARENT,
 
495
                                     GTK_MESSAGE_WARNING,
 
496
                                     GTK_BUTTONS_OK, message);
 
497
    g_free (message);
 
498
    
 
499
    gtk_window_set_title (GTK_WINDOW (dialog), APPLICATION_NAME " Warning");
 
500
    
 
501
    gtk_dialog_run (GTK_DIALOG (dialog));
 
502
    gtk_widget_destroy (dialog);
 
503
}
 
504
 
 
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
static void
 
527
on_menu_item_activated (GtkWidget *menu_item, GtkWidget *tool_button)
 
528
{
 
529
    GtkToggleToolButton *button = GTK_TOGGLE_TOOL_BUTTON (tool_button);
 
530
 
 
531
    if (!gtk_toggle_tool_button_get_active (button))
 
532
        gtk_toggle_tool_button_set_active (button, TRUE);
 
533
}
 
534
 
 
535
static void
 
536
on_start_toggled (GtkWidget *widget, gpointer data)
 
537
{
 
538
    Application *app = data;
 
539
 
 
540
    if (!gtk_toggle_tool_button_get_active (
 
541
            GTK_TOGGLE_TOOL_BUTTON (app->start_button)))
 
542
        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.");
 
564
                
 
565
                update_sensitivity (app);
 
566
                return;
 
567
            }
 
568
        }
 
569
 
 
570
        app->input_fd = fd;
 
571
        fd_add_watch (app->input_fd, app);
 
572
    }
 
573
    
 
574
    fd_set_read_callback (app->input_fd, on_read);
 
575
    
 
576
    delete_data (app);
 
577
    
 
578
    g_idle_add_full (G_PRIORITY_LOW, start_profiling, app, NULL);
 
579
}
 
580
 
 
581
enum
 
582
{
 
583
    OBJECT_NAME,
 
584
    OBJECT_SELF,
 
585
    OBJECT_TOTAL,
 
586
    OBJECT_OBJECT
 
587
};
 
588
 
 
589
enum
 
590
{
 
591
    CALLERS_NAME,
 
592
    CALLERS_SELF,
 
593
    CALLERS_TOTAL,
 
594
    CALLERS_OBJECT
 
595
};
 
596
 
 
597
enum
 
598
{
 
599
    DESCENDANTS_NAME,
 
600
    DESCENDANTS_SELF,
 
601
    DESCENDANTS_NON_RECURSE,
 
602
    DESCENDANTS_TOTAL,
 
603
    DESCENDANTS_OBJECT
 
604
};
 
605
 
 
606
static ProfileObject *
 
607
get_current_object (Application *app)
 
608
{
 
609
    GtkTreeSelection *selection;
 
610
    GtkTreeModel *model;
 
611
    GtkTreeIter selected;
 
612
    ProfileObject *object;
 
613
    
 
614
    selection = gtk_tree_view_get_selection (app->object_view);
 
615
    
 
616
    if (gtk_tree_selection_get_selected (selection, &model, &selected))
 
617
    {
 
618
        gtk_tree_model_get (model, &selected,
 
619
                            OBJECT_OBJECT, &object,
 
620
                            -1);
 
621
        return object;
 
622
    }
 
623
    else
 
624
    {
 
625
        return NULL;
 
626
    }
 
627
}
 
628
 
 
629
static void
 
630
fill_main_list (Application *app)
 
631
{
 
632
    GList *list;
 
633
    GtkListStore *list_store;
 
634
    Profile *profile = app->profile;
 
635
    GList *objects;
 
636
    
 
637
    if (profile)
 
638
    {
 
639
        gpointer sort_state;
 
640
        
 
641
        list_store = gtk_list_store_new (4,
 
642
                                         G_TYPE_STRING,
 
643
                                         G_TYPE_DOUBLE,
 
644
                                         G_TYPE_DOUBLE,
 
645
                                         G_TYPE_POINTER);
 
646
        
 
647
        objects = profile_get_objects (profile);
 
648
        for (list = objects; list != NULL; list = list->next)
 
649
        {
 
650
            ProfileObject *object = list->data;
 
651
            GtkTreeIter iter;
 
652
            double profile_size = profile_get_size (profile);
 
653
            
 
654
            gtk_list_store_append (list_store, &iter);
 
655
            
 
656
            gtk_list_store_set (list_store, &iter,
 
657
                                OBJECT_NAME, object->name,
 
658
                                OBJECT_SELF, 100.0 * object->self / profile_size,
 
659
                                OBJECT_TOTAL, 100.0 * object->total / profile_size,
 
660
                                OBJECT_OBJECT, object,
 
661
                                -1);
 
662
        }
 
663
        g_list_free (objects);
 
664
        
 
665
        sort_state = save_sort_state (app->object_view);
 
666
        
 
667
        gtk_tree_view_set_model (app->object_view, GTK_TREE_MODEL (list_store));
 
668
        
 
669
        if (sort_state)
 
670
        {
 
671
            restore_sort_state (app->object_view, sort_state);
 
672
        }
 
673
        else
 
674
        {
 
675
            gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (list_store),
 
676
                                                  OBJECT_TOTAL,
 
677
                                                  GTK_SORT_DESCENDING);
 
678
        }
 
679
        
 
680
        g_object_unref (G_OBJECT (list_store));
 
681
    }
 
682
    
 
683
    gtk_tree_view_columns_autosize (app->object_view);
 
684
}
 
685
 
 
686
static void
 
687
add_node (GtkTreeStore      *store,
 
688
          int                size,
 
689
          const GtkTreeIter *parent,
 
690
          ProfileDescendant *node)
 
691
{
 
692
    GtkTreeIter iter;
 
693
    
 
694
    if (!node)
 
695
        return;
 
696
    
 
697
    gtk_tree_store_insert (store, &iter, (GtkTreeIter *)parent, 0);
 
698
    
 
699
    gtk_tree_store_set (store, &iter,
 
700
                        DESCENDANTS_NAME, node->object->name,
 
701
                        DESCENDANTS_SELF, 100 * (node->self)/(double)size,
 
702
                        DESCENDANTS_NON_RECURSE, 100 * (node->non_recursion)/(double)size,
 
703
                        DESCENDANTS_TOTAL, 100 * (node->total)/(double)size,
 
704
                        DESCENDANTS_OBJECT, node->object,
 
705
                        -1);
 
706
    
 
707
    add_node (store, size, parent, node->siblings);
 
708
    add_node (store, size, &iter, node->children);
 
709
}
 
710
 
 
711
static void
 
712
fill_descendants_tree (Application *app)
 
713
{
 
714
    GtkTreeStore *tree_store;
 
715
    gpointer sort_state;
 
716
    
 
717
    sort_state = save_sort_state (app->descendants_view);
 
718
    
 
719
    if (app->descendants)
 
720
    {
 
721
        profile_descendant_free (app->descendants);
 
722
        app->descendants = NULL;
 
723
    }
 
724
    
 
725
    tree_store =
 
726
        gtk_tree_store_new (5,
 
727
                            G_TYPE_STRING,
 
728
                            G_TYPE_DOUBLE,
 
729
                            G_TYPE_DOUBLE,
 
730
                            G_TYPE_DOUBLE,
 
731
                            G_TYPE_POINTER);
 
732
    
 
733
    if (app->profile)
 
734
    {
 
735
        ProfileObject *object = get_current_object (app);
 
736
        if (object)
 
737
        {
 
738
            app->descendants =
 
739
                profile_create_descendants (app->profile, object);
 
740
            add_node (tree_store,
 
741
                      profile_get_size (app->profile), NULL, app->descendants);
 
742
        }
 
743
    }
 
744
    
 
745
    gtk_tree_view_set_model (
 
746
        app->descendants_view, GTK_TREE_MODEL (tree_store));
 
747
    
 
748
    g_object_unref (G_OBJECT (tree_store));
 
749
    
 
750
    if (!sort_state)
 
751
    {
 
752
        gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (tree_store),
 
753
                                              DESCENDANTS_NON_RECURSE,
 
754
                                              GTK_SORT_DESCENDING);
 
755
    }
 
756
    else
 
757
    {
 
758
        restore_sort_state (app->descendants_view, sort_state);
 
759
    }
 
760
    
 
761
    gtk_tree_view_columns_autosize (app->descendants_view);
 
762
}
 
763
 
 
764
static void
 
765
add_callers (GtkListStore *list_store,
 
766
             Profile *profile,
 
767
             ProfileCaller *callers)
 
768
{
 
769
    while (callers)
 
770
    {
 
771
        gchar *name;
 
772
        GtkTreeIter iter;
 
773
        double profile_size = profile_get_size (profile);
 
774
        
 
775
        if (callers->object)
 
776
            name = callers->object->name;
 
777
        else
 
778
            name = "<spontaneous>";
 
779
        
 
780
        gtk_list_store_append (list_store, &iter);
 
781
        gtk_list_store_set (
 
782
            list_store, &iter,
 
783
            CALLERS_NAME, name,
 
784
            CALLERS_SELF, 100.0 * callers->self / profile_size,
 
785
            CALLERS_TOTAL, 100.0 * callers->total / profile_size,
 
786
            CALLERS_OBJECT, callers->object,
 
787
            -1);
 
788
        
 
789
        callers = callers->next;
 
790
    }
 
791
}
 
792
 
 
793
static void
 
794
fill_callers_list (Application *app)
 
795
{
 
796
    GtkListStore *list_store;
 
797
    gpointer sort_state;
 
798
    
 
799
    sort_state = save_sort_state (app->descendants_view);
 
800
    
 
801
    if (app->callers)
 
802
    {
 
803
        profile_caller_free (app->callers);
 
804
        app->callers = NULL;
 
805
    }
 
806
    
 
807
    list_store =
 
808
        gtk_list_store_new (4,
 
809
                            G_TYPE_STRING,
 
810
                            G_TYPE_DOUBLE,
 
811
                            G_TYPE_DOUBLE,
 
812
                            G_TYPE_POINTER);
 
813
    
 
814
    if (app->profile)
 
815
    {
 
816
        ProfileObject *object = get_current_object (app);
 
817
        if (object)
 
818
        {
 
819
            app->callers = profile_list_callers (app->profile, object);
 
820
            add_callers (list_store, app->profile, app->callers);
 
821
        }
 
822
    }
 
823
    
 
824
    gtk_tree_view_set_model (
 
825
        app->callers_view, GTK_TREE_MODEL (list_store));
 
826
    
 
827
    g_object_unref (G_OBJECT (list_store));
 
828
    
 
829
    if (!sort_state)
 
830
    {
 
831
        gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (list_store),
 
832
                                              CALLERS_TOTAL,
 
833
                                              GTK_SORT_DESCENDING);
 
834
    }
 
835
    else
 
836
    {
 
837
        restore_sort_state (app->callers_view, sort_state);
 
838
    }
 
839
    
 
840
    gtk_tree_view_columns_autosize (app->callers_view);
 
841
}
 
842
 
 
843
static void
 
844
fill_lists (Application *app)
 
845
{
 
846
    fill_main_list (app);
 
847
    fill_callers_list (app);
 
848
    fill_descendants_tree (app);
 
849
}
 
850
 
 
851
static void
 
852
ensure_profile (Application *app)
 
853
{
 
854
    if (app->profile)
 
855
        return;
 
856
    
 
857
    app->profile = profile_new (app->stash);
 
858
 
 
859
    fill_lists (app);
 
860
    
 
861
    app->state = DISPLAYING;
 
862
    
 
863
    update_sensitivity (app);
 
864
}
 
865
 
 
866
static void
 
867
on_about_activated (GtkWidget *widget, gpointer data)
 
868
{
 
869
#define OSLASH "\303\270"
 
870
    Application *app = data;
 
871
 
 
872
    gtk_show_about_dialog (GTK_WINDOW (app->main_window),
 
873
                           "logo", app->icon,
 
874
                           "name", APPLICATION_NAME,
 
875
                           "copyright", "Copyright 2004-2008, S"OSLASH"ren Sandmann",
 
876
                           "version", PACKAGE_VERSION,
 
877
                           NULL);
 
878
}
 
879
 
 
880
static void
 
881
on_profile_toggled (GtkWidget *widget, gpointer data)
 
882
{
 
883
    Application *app = data;
 
884
 
 
885
    if (gtk_toggle_tool_button_get_active (GTK_TOGGLE_TOOL_BUTTON (app->profile_button)))
 
886
    {
 
887
        set_busy (app->main_window, TRUE);
 
888
        if (app->profile && !app->profile_from_file)
 
889
        {
 
890
            profile_free (app->profile);
 
891
            app->profile = NULL;
 
892
        }
 
893
        
 
894
        ensure_profile (app);
 
895
        set_busy (app->main_window, FALSE);
 
896
    }
 
897
}
 
898
 
 
899
static void
 
900
on_reset_clicked (gpointer widget, gpointer data)
 
901
{
 
902
    Application *app = data;
 
903
 
 
904
    set_busy (app->main_window, TRUE);
 
905
    
 
906
    delete_data (app);
 
907
    
 
908
    if (app->state == DISPLAYING)
 
909
        app->state = INITIAL;
 
910
    
 
911
    update_sensitivity (app);
 
912
 
 
913
    set_busy (app->main_window, FALSE);
 
914
}
 
915
 
 
916
static gboolean
 
917
overwrite_file (GtkWindow *window,
 
918
                const char *filename)
 
919
{
 
920
    GtkWidget *msgbox;
 
921
    gchar *utf8_file_name;
 
922
    AtkObject *obj;
 
923
    gint ret;
 
924
    
 
925
    utf8_file_name = g_filename_to_utf8 (filename, -1, NULL, NULL, NULL);
 
926
    msgbox = gtk_message_dialog_new (window,
 
927
                                     (GtkDialogFlags)GTK_DIALOG_DESTROY_WITH_PARENT,
 
928
                                     GTK_MESSAGE_QUESTION,
 
929
                                     GTK_BUTTONS_NONE,
 
930
                                     _("A file named \"%s\" already exists."),
 
931
                                     utf8_file_name);
 
932
    g_free (utf8_file_name);
 
933
    
 
934
    gtk_message_dialog_format_secondary_text (
 
935
        GTK_MESSAGE_DIALOG (msgbox),
 
936
        _("Do you want to replace it with the one you are saving?"));
 
937
    
 
938
    gtk_dialog_add_button (GTK_DIALOG (msgbox),
 
939
                           GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
 
940
    
 
941
    gtk_dialog_add_button (GTK_DIALOG (msgbox),
 
942
                           _("_Replace"), GTK_RESPONSE_YES);
 
943
    
 
944
    gtk_dialog_set_default_response (GTK_DIALOG (msgbox),
 
945
                                     GTK_RESPONSE_CANCEL);
 
946
    
 
947
    obj = gtk_widget_get_accessible (msgbox);
 
948
    
 
949
    if (GTK_IS_ACCESSIBLE (obj))
 
950
        atk_object_set_name (obj, _("Question"));
 
951
    
 
952
    ret = gtk_dialog_run (GTK_DIALOG (msgbox));
 
953
    gtk_widget_destroy (msgbox);
 
954
    
 
955
    return (ret == GTK_RESPONSE_YES);
 
956
    
 
957
}
 
958
 
 
959
static void
 
960
on_save_as_clicked (gpointer widget,
 
961
                    gpointer data)
 
962
{
 
963
    Application *app = data;
 
964
    GtkWidget *dialog;
 
965
    
 
966
    ensure_profile (app);
 
967
    
 
968
    set_busy (app->main_window, TRUE);
 
969
    
 
970
    dialog = gtk_file_chooser_dialog_new ("Save As",
 
971
                                          GTK_WINDOW (app->main_window),
 
972
                                          GTK_FILE_CHOOSER_ACTION_SAVE,
 
973
                                          GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
 
974
                                          GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
 
975
                                          NULL);
 
976
    
 
977
    gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);
 
978
    gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
 
979
    
 
980
    set_busy (app->main_window, FALSE);
 
981
    
 
982
 retry:
 
983
    if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
 
984
    {
 
985
        GError *err = NULL;
 
986
        gchar *filename;
 
987
        
 
988
        filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
 
989
        
 
990
        if (g_file_test (filename, G_FILE_TEST_EXISTS)          &&
 
991
            !overwrite_file (GTK_WINDOW (app->main_window), filename))
 
992
        {
 
993
            g_free (filename);
 
994
            goto retry;
 
995
        }
 
996
        
 
997
        set_busy (dialog, TRUE);
 
998
        if (!profile_save (app->profile, filename, &err))
 
999
        {
 
1000
            sorry (app->main_window, "Could not save %s: %s",
 
1001
                   filename, err->message);
 
1002
 
 
1003
            set_busy (dialog, FALSE);
 
1004
            g_free (filename);
 
1005
            goto retry;
 
1006
        }
 
1007
        set_application_title (app, filename);
 
1008
        set_busy (dialog, FALSE);
 
1009
        g_free (filename);
 
1010
    }
 
1011
    
 
1012
    gtk_widget_destroy (dialog);
 
1013
}
 
1014
 
 
1015
static void
 
1016
set_loaded_profile (Application *app,
 
1017
                    const char  *name,
 
1018
                    Profile     *profile)
 
1019
{
 
1020
    g_return_if_fail (name != NULL);
 
1021
    g_return_if_fail (profile != NULL);
 
1022
    
 
1023
    set_busy (app->main_window, TRUE);
 
1024
    
 
1025
    delete_data (app);
 
1026
        
 
1027
    app->state = DISPLAYING;
 
1028
    
 
1029
    app->n_samples = profile_get_size (profile);
 
1030
    
 
1031
    app->profile = profile;
 
1032
    app->profile_from_file = TRUE;
 
1033
    
 
1034
    fill_lists (app);
 
1035
 
 
1036
    set_application_title (app, name);
 
1037
    
 
1038
    update_sensitivity (app);
 
1039
    
 
1040
    set_busy (app->main_window, FALSE);
 
1041
}
 
1042
 
 
1043
static void
 
1044
show_could_not_open (Application *app,
 
1045
                     const char *filename,
 
1046
                     GError *err)
 
1047
{
 
1048
    sorry (app->main_window,
 
1049
           "Could not open %s: %s",
 
1050
           filename,
 
1051
           err->message);
 
1052
}
 
1053
            
 
1054
static void
 
1055
on_open_clicked (gpointer widget,
 
1056
                 gpointer data)
 
1057
{
 
1058
    Application *app = data;
 
1059
    gchar *filename = NULL;
 
1060
    Profile *profile = NULL;
 
1061
    GtkWidget *dialog;
 
1062
 
 
1063
    set_busy (app->main_window, TRUE);
 
1064
    
 
1065
    dialog = gtk_file_chooser_dialog_new ("Open",
 
1066
                                          GTK_WINDOW (app->main_window),
 
1067
                                          GTK_FILE_CHOOSER_ACTION_OPEN,
 
1068
                                          GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
 
1069
                                          GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
 
1070
                                          NULL);
 
1071
    
 
1072
    gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
 
1073
 
 
1074
    set_busy (app->main_window, FALSE);
 
1075
    
 
1076
 retry:
 
1077
    if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
 
1078
    {
 
1079
        GError *err = NULL;
 
1080
        
 
1081
        filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
 
1082
 
 
1083
        set_busy (dialog, TRUE);
 
1084
 
 
1085
        profile = profile_load (filename, &err);
 
1086
        
 
1087
        if (!profile)
 
1088
        {
 
1089
            set_busy (dialog, FALSE);
 
1090
 
 
1091
            show_could_not_open (app, filename, err);
 
1092
            g_error_free (err);
 
1093
            g_free (filename);
 
1094
            
 
1095
            filename = NULL;
 
1096
            goto retry;
 
1097
        }
 
1098
        
 
1099
        set_busy (dialog, FALSE);
 
1100
    }
 
1101
 
 
1102
    gtk_widget_destroy (dialog);
 
1103
 
 
1104
    if (profile)
 
1105
    {
 
1106
        g_assert (filename);
 
1107
        set_loaded_profile (app, filename, profile);
 
1108
    
 
1109
        g_free (filename);
 
1110
    }
 
1111
}
 
1112
 
 
1113
static void
 
1114
on_delete (GtkWidget *window)
 
1115
{
 
1116
    gtk_main_quit ();
 
1117
}
 
1118
 
 
1119
static void
 
1120
expand_descendants_tree (Application *app)
 
1121
{
 
1122
    GtkTreeModel *model = gtk_tree_view_get_model (app->descendants_view);
 
1123
    GtkTreeIter iter;
 
1124
    GList *all_paths = NULL;
 
1125
    int n_rows;
 
1126
    int max_rows = 40; /* FIXME */
 
1127
    double top_value = 0.0;
 
1128
    GtkTreePath *first_path;
 
1129
    GList *list;
 
1130
 
 
1131
    first_path = gtk_tree_path_new_first();
 
1132
 
 
1133
    all_paths = g_list_prepend (all_paths, first_path);
 
1134
 
 
1135
    n_rows = 1;
 
1136
 
 
1137
    gtk_tree_model_get_iter (model, &iter, first_path);
 
1138
    gtk_tree_model_get (model, &iter,
 
1139
                        OBJECT_TOTAL, &top_value,
 
1140
                        -1);
 
1141
    
 
1142
    while (all_paths && n_rows < max_rows)
 
1143
    {
 
1144
        GtkTreeIter best_iter;
 
1145
        GtkTreePath *best_path;
 
1146
        double best_value;
 
1147
        int n_children;
 
1148
        int i;
 
1149
 
 
1150
        best_value = 0.0;
 
1151
        best_path = NULL;
 
1152
 
 
1153
        for (list = all_paths; list != NULL; list = list->next)
 
1154
        {
 
1155
            GtkTreePath *path = list->data;
 
1156
            GtkTreeIter iter;
 
1157
            double value;
 
1158
            g_assert (path != NULL);
 
1159
            if (gtk_tree_model_get_iter (model, &iter, path))
 
1160
            {
 
1161
                gtk_tree_model_get (model, &iter,
 
1162
                                    OBJECT_TOTAL, &value,
 
1163
                                    -1);
 
1164
            }
 
1165
            if (value >= best_value)
 
1166
            {
 
1167
                best_value = value;
 
1168
                best_path = path;
 
1169
 
 
1170
                gtk_tree_model_get_iter (model, &best_iter, path);
 
1171
            }
 
1172
        }
 
1173
 
 
1174
        gtk_tree_model_get_iter (model, &iter, best_path);
 
1175
 
 
1176
        n_children = gtk_tree_model_iter_n_children (model, &best_iter);
 
1177
        
 
1178
        if (n_children && (best_value / top_value) > 0.04 &&
 
1179
            (n_children + gtk_tree_path_get_depth (best_path)) / (double)max_rows < (best_value / top_value) )
 
1180
        {
 
1181
            gtk_tree_view_expand_row (GTK_TREE_VIEW (app->descendants_view), best_path, FALSE);
 
1182
            n_rows += n_children;
 
1183
 
 
1184
            if (gtk_tree_path_get_depth (best_path) < 4)
 
1185
            {
 
1186
                GtkTreePath *path = gtk_tree_path_copy (best_path);
 
1187
                gtk_tree_path_down (path);
 
1188
 
 
1189
                for (i = 0; i < n_children; ++i)
 
1190
                {
 
1191
                    all_paths = g_list_prepend (all_paths, path);
 
1192
 
 
1193
                    path = gtk_tree_path_copy (path);
 
1194
                    gtk_tree_path_next (path);
 
1195
                }
 
1196
                gtk_tree_path_free (path);
 
1197
            }
 
1198
        }
 
1199
 
 
1200
        all_paths = g_list_remove (all_paths, best_path);
 
1201
        gtk_tree_path_free (best_path);
 
1202
    }
 
1203
 
 
1204
    for (list = all_paths; list != NULL; list = list->next)
 
1205
        gtk_tree_path_free (list->data);
 
1206
    
 
1207
    g_list_free (all_paths);
 
1208
}
 
1209
 
 
1210
static void
 
1211
on_object_selection_changed (GtkTreeSelection *selection,
 
1212
                             gpointer data)
 
1213
{
 
1214
    Application *app = data;
 
1215
 
 
1216
    set_busy (app->main_window, TRUE);
 
1217
 
 
1218
    gdk_window_process_all_updates ();
 
1219
    
 
1220
    fill_descendants_tree (app);
 
1221
    fill_callers_list (app);
 
1222
 
 
1223
    if (get_current_object (app))
 
1224
        expand_descendants_tree (app);
 
1225
    
 
1226
    set_busy (app->main_window, FALSE);
 
1227
}
 
1228
 
 
1229
static void
 
1230
really_goto_object (Application *app,
 
1231
                    ProfileObject *object)
 
1232
{
 
1233
    GtkTreeModel *profile_objects;
 
1234
    GtkTreeIter iter;
 
1235
    gboolean found = FALSE;
 
1236
    
 
1237
    profile_objects = gtk_tree_view_get_model (app->object_view);
 
1238
    
 
1239
    if (gtk_tree_model_get_iter_first (profile_objects, &iter))
 
1240
    {
 
1241
        do
 
1242
        {
 
1243
            ProfileObject *profile_object;
 
1244
            
 
1245
            gtk_tree_model_get (profile_objects, &iter,
 
1246
                                OBJECT_OBJECT, &profile_object,
 
1247
                                -1);
 
1248
            
 
1249
            if (profile_object == object)
 
1250
            {
 
1251
                found = TRUE;
 
1252
                break;
 
1253
            }
 
1254
        }
 
1255
        while (gtk_tree_model_iter_next (profile_objects, &iter));
 
1256
    }
 
1257
    
 
1258
    if (found)
 
1259
    {
 
1260
        GtkTreePath *path =
 
1261
            gtk_tree_model_get_path (profile_objects, &iter);
 
1262
        
 
1263
        gtk_tree_view_set_cursor (app->object_view, path, 0, FALSE);
 
1264
    }
 
1265
}
 
1266
 
 
1267
static void
 
1268
goto_object (Application *app,
 
1269
             GtkTreeView *tree_view,
 
1270
             GtkTreePath *path,
 
1271
             gint         column)
 
1272
{
 
1273
    GtkTreeIter iter;
 
1274
    GtkTreeModel *model = gtk_tree_view_get_model (tree_view);
 
1275
    ProfileObject *object;
 
1276
    
 
1277
    if (!gtk_tree_model_get_iter (model, &iter, path))
 
1278
        return;
 
1279
    
 
1280
    gtk_tree_model_get (model, &iter, column, &object, -1);
 
1281
    
 
1282
    if (!object)
 
1283
        return;
 
1284
    
 
1285
    really_goto_object (app, object);
 
1286
    
 
1287
}
 
1288
 
 
1289
static void
 
1290
on_descendants_row_activated (GtkTreeView *tree_view,
 
1291
                              GtkTreePath *path,
 
1292
                              GtkTreeViewColumn *column,
 
1293
                              gpointer data)
 
1294
{
 
1295
    Application *app = data;
 
1296
    
 
1297
    goto_object (app, tree_view, path, DESCENDANTS_OBJECT);
 
1298
    
 
1299
    gtk_widget_grab_focus (GTK_WIDGET (app->descendants_view));
 
1300
}
 
1301
 
 
1302
static void
 
1303
on_callers_row_activated (GtkTreeView *tree_view,
 
1304
                          GtkTreePath *path,
 
1305
                          GtkTreeViewColumn *column,
 
1306
                          gpointer data)
 
1307
{
 
1308
    Application *app = data;
 
1309
    
 
1310
    goto_object (app, tree_view, path, CALLERS_OBJECT);
 
1311
 
 
1312
    gtk_widget_grab_focus (GTK_WIDGET (app->callers_view));
 
1313
}
 
1314
 
 
1315
static void
 
1316
set_sizes (GtkWindow *window,
 
1317
           GtkWidget *hpaned,
 
1318
           GtkWidget *vpaned)
 
1319
{
 
1320
    GdkScreen *screen;
 
1321
    int monitor_num;
 
1322
    GdkRectangle monitor;
 
1323
    int width, height;
 
1324
    GtkWidget *widget = GTK_WIDGET (window);
 
1325
    
 
1326
    screen = gtk_widget_get_screen (widget);
 
1327
    monitor_num = gdk_screen_get_monitor_at_window (screen, widget->window);
 
1328
    
 
1329
    gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
 
1330
    
 
1331
    width = monitor.width * 3 / 4;
 
1332
    height = monitor.height * 3 / 4;
 
1333
    
 
1334
    gtk_window_resize (window, width, height);
 
1335
    
 
1336
    gtk_paned_set_position (GTK_PANED (vpaned), height / 2);
 
1337
    gtk_paned_set_position (GTK_PANED (hpaned), width / 2);
 
1338
}
 
1339
 
 
1340
static void
 
1341
set_shadows (void)
 
1342
{
 
1343
    /* Get rid of motif out-bevels */
 
1344
    gtk_rc_parse_string (
 
1345
        "style \"blah\" "
 
1346
        "{ "
 
1347
        "   GtkToolbar::shadow_type = none "
 
1348
        "   GtkMenuBar::shadow_type = none "
 
1349
        "   GtkMenuBar::internal_padding = 2 "
 
1350
        "} "
 
1351
        "widget \"*toolbar\" style : rc \"blah\"\n"
 
1352
        "widget \"*menubar\" style : rc \"blah\"\n"
 
1353
        );
 
1354
}
 
1355
 
 
1356
static void
 
1357
build_gui (Application *app)
 
1358
{
 
1359
    GladeXML *xml;
 
1360
    GtkTreeSelection *selection;
 
1361
    GtkTreeViewColumn *col;
 
1362
 
 
1363
    set_shadows ();
 
1364
    
 
1365
    xml = glade_xml_new (DATADIR "/sysprof.glade", NULL, NULL);
 
1366
    
 
1367
    /* Main Window */
 
1368
    app->main_window = glade_xml_get_widget (xml, "main_window");
 
1369
    app->icon = gdk_pixbuf_new_from_file (PIXMAPDIR "/sysprof-icon.png", NULL);
 
1370
 
 
1371
    gtk_window_set_icon (GTK_WINDOW (app->main_window), app->icon);
 
1372
    
 
1373
    g_signal_connect (G_OBJECT (app->main_window), "delete_event",
 
1374
                      G_CALLBACK (on_delete), NULL);
 
1375
    
 
1376
    gtk_widget_realize (GTK_WIDGET (app->main_window));
 
1377
    set_sizes (GTK_WINDOW (app->main_window),
 
1378
               glade_xml_get_widget (xml, "hpaned"),
 
1379
               glade_xml_get_widget (xml, "vpaned"));
 
1380
    
 
1381
    /* Tool items */
 
1382
    
 
1383
    app->start_button = glade_xml_get_widget (xml, "start_button");
 
1384
    app->profile_button = glade_xml_get_widget (xml, "profile_button");
 
1385
    app->reset_button = glade_xml_get_widget (xml, "reset_button");
 
1386
    app->save_as_button = glade_xml_get_widget (xml, "save_as_button");
 
1387
    app->dummy_button = glade_xml_get_widget (xml, "dummy_button");
 
1388
    
 
1389
    gtk_toggle_tool_button_set_active (
 
1390
        GTK_TOGGLE_TOOL_BUTTON (app->profile_button), FALSE);
 
1391
    
 
1392
    g_signal_connect (G_OBJECT (app->start_button), "toggled",
 
1393
                      G_CALLBACK (on_start_toggled), app);
 
1394
    
 
1395
    g_signal_connect (G_OBJECT (app->profile_button), "toggled",
 
1396
                      G_CALLBACK (on_profile_toggled), app);
 
1397
    
 
1398
    g_signal_connect (G_OBJECT (app->reset_button), "clicked",
 
1399
                      G_CALLBACK (on_reset_clicked), app);
 
1400
    
 
1401
    g_signal_connect (G_OBJECT (app->save_as_button), "clicked",
 
1402
                      G_CALLBACK (on_save_as_clicked), app);
 
1403
 
 
1404
    
 
1405
    app->samples_label = glade_xml_get_widget (xml, "samples_label");
 
1406
    
 
1407
    /* Menu items */
 
1408
    app->start_item = glade_xml_get_widget (xml, "start_item");
 
1409
    app->profile_item = glade_xml_get_widget (xml, "profile_item");
 
1410
    app->reset_item = glade_xml_get_widget (xml, "reset_item");
 
1411
    app->open_item = glade_xml_get_widget (xml, "open_item");
 
1412
    app->save_as_item = glade_xml_get_widget (xml, "save_as_item");
 
1413
    
 
1414
    g_assert (app->start_item);
 
1415
    g_assert (app->profile_item);
 
1416
    g_assert (app->save_as_item);
 
1417
    g_assert (app->open_item);
 
1418
    
 
1419
    g_signal_connect (G_OBJECT (app->start_item), "activate",
 
1420
                      G_CALLBACK (on_menu_item_activated), app->start_button);
 
1421
    
 
1422
    g_signal_connect (G_OBJECT (app->profile_item), "activate",
 
1423
                      G_CALLBACK (on_menu_item_activated), app->profile_button);
 
1424
    
 
1425
    g_signal_connect (G_OBJECT (app->reset_item), "activate",
 
1426
                      G_CALLBACK (on_reset_clicked), app);
 
1427
 
 
1428
    g_signal_connect (G_OBJECT (app->open_item), "activate",
 
1429
                      G_CALLBACK (on_open_clicked), app);
 
1430
    
 
1431
    g_signal_connect (G_OBJECT (app->save_as_item), "activate",
 
1432
                      G_CALLBACK (on_save_as_clicked), app);
 
1433
 
 
1434
    g_signal_connect (G_OBJECT (glade_xml_get_widget (xml, "quit")), "activate",
 
1435
                      G_CALLBACK (on_delete), NULL);
 
1436
 
 
1437
    g_signal_connect (G_OBJECT (glade_xml_get_widget (xml, "about")), "activate",
 
1438
                      G_CALLBACK (on_about_activated), app);
 
1439
    
 
1440
    /* TreeViews */
 
1441
    
 
1442
    /* object view */
 
1443
    app->object_view = (GtkTreeView *)glade_xml_get_widget (xml, "object_view");
 
1444
    gtk_tree_view_set_enable_search (app->object_view, FALSE);
 
1445
    col = add_plain_text_column (app->object_view, _("Functions"), OBJECT_NAME);
 
1446
    add_double_format_column (app->object_view, _("Self"), OBJECT_SELF, "%.2f ");
 
1447
    add_double_format_column (app->object_view, _("Total"), OBJECT_TOTAL, "%.2f ");
 
1448
    selection = gtk_tree_view_get_selection (app->object_view);
 
1449
    g_signal_connect (selection, "changed", G_CALLBACK (on_object_selection_changed), app);
 
1450
    gtk_tree_view_column_set_expand (col, TRUE);
 
1451
    
 
1452
    /* callers view */
 
1453
    app->callers_view = (GtkTreeView *)glade_xml_get_widget (xml, "callers_view");
 
1454
    gtk_tree_view_set_enable_search (app->callers_view, FALSE);
 
1455
    col = add_plain_text_column (app->callers_view, _("Callers"), CALLERS_NAME);
 
1456
    add_double_format_column (app->callers_view, _("Self"), CALLERS_SELF, "%.2f ");
 
1457
    add_double_format_column (app->callers_view, _("Total"), CALLERS_TOTAL, "%.2f ");
 
1458
    g_signal_connect (app->callers_view, "row-activated",
 
1459
                      G_CALLBACK (on_callers_row_activated), app);
 
1460
    gtk_tree_view_column_set_expand (col, TRUE);
 
1461
    
 
1462
    /* descendants view */
 
1463
    app->descendants_view = (GtkTreeView *)glade_xml_get_widget (xml, "descendants_view");
 
1464
    gtk_tree_view_set_enable_search (app->descendants_view, FALSE);
 
1465
    col = add_plain_text_column (app->descendants_view, _("Descendants"), DESCENDANTS_NAME);
 
1466
    add_double_format_column (app->descendants_view, _("Self"), DESCENDANTS_SELF, "%.2f ");
 
1467
    add_double_format_column (app->descendants_view, _("Cumulative"), DESCENDANTS_NON_RECURSE, "%.2f ");
 
1468
    g_signal_connect (app->descendants_view, "row-activated",
 
1469
                      G_CALLBACK (on_descendants_row_activated), app);
 
1470
    gtk_tree_view_column_set_expand (col, TRUE);
 
1471
    
 
1472
    gtk_widget_grab_focus (GTK_WIDGET (app->object_view));
 
1473
    gtk_widget_show_all (app->main_window);
 
1474
    gtk_widget_hide (app->dummy_button);
 
1475
    
 
1476
    /* Statusbar */
 
1477
    queue_show_samples (app);
 
1478
}
 
1479
 
 
1480
static Application *
 
1481
application_new (void)
 
1482
{
 
1483
    Application *app = g_new0 (Application, 1);
 
1484
    
 
1485
    app->stash = stack_stash_new ();
 
1486
    app->input_fd = -1;
 
1487
    app->state = INITIAL;
 
1488
 
 
1489
    g_get_current_time (&app->latest_reset);
 
1490
    
 
1491
    return app;
 
1492
}
 
1493
 
 
1494
typedef struct
 
1495
{
 
1496
    const char *filename;
 
1497
    Application *app;
 
1498
} FileOpenData;
 
1499
 
 
1500
static gboolean
 
1501
load_file (gpointer data)
 
1502
{
 
1503
    FileOpenData *file_open_data = data;
 
1504
    const char *filename = file_open_data->filename;
 
1505
    Application *app = file_open_data->app;
 
1506
    GError *err = NULL;
 
1507
    Profile *profile;
 
1508
 
 
1509
    set_busy (app->main_window, TRUE);
 
1510
    
 
1511
    profile = profile_load (filename, &err);
 
1512
    
 
1513
    set_busy (app->main_window, FALSE);
 
1514
    
 
1515
    if (profile)
 
1516
    {
 
1517
        set_loaded_profile (app, filename, profile);
 
1518
    }
 
1519
    else
 
1520
    {
 
1521
        show_could_not_open (app, filename, err);
 
1522
        g_error_free (err);
 
1523
    }
 
1524
 
 
1525
    return FALSE;
 
1526
}
 
1527
 
 
1528
int
 
1529
main (int argc, char **argv)
 
1530
{
 
1531
    Application *app;
 
1532
    
 
1533
    gtk_init (&argc, &argv);
 
1534
    
 
1535
    app = application_new ();
 
1536
    
 
1537
#if 0
 
1538
    nice (-19);
 
1539
    g_timeout_add (10, on_timeout, app);
 
1540
#endif
 
1541
    
 
1542
    build_gui (app);
 
1543
    
 
1544
    update_sensitivity (app);
 
1545
 
 
1546
    if (argc > 1)
 
1547
    {
 
1548
        FileOpenData *file_open_data = g_new0 (FileOpenData, 1);
 
1549
 
 
1550
        file_open_data->filename = argv[1];
 
1551
        file_open_data->app = app;
 
1552
 
 
1553
        g_idle_add (load_file, file_open_data);
 
1554
    }
 
1555
 
 
1556
    gtk_main ();
 
1557
    
 
1558
    return 0;
 
1559
}