summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/allocators-store.c91
-rw-r--r--src/allocators.c2
-rw-r--r--src/allocators.h10
-rw-r--r--src/app.c9
-rw-r--r--src/blockmap.c4
-rw-r--r--src/callgraph-treemap.c2
-rw-r--r--src/callgraph.c8
-rw-r--r--src/frames.c4
-rw-r--r--src/lwp.c4
-rw-r--r--src/minibfd/binfile.c21
-rw-r--r--src/odin.h2
-rw-r--r--src/spacetime.c2
-rw-r--r--src/summary-chart.c90
-rw-r--r--src/summary-view.c22
-rw-r--r--src/summary.c83
-rw-r--r--src/timeline.c513
-rw-r--r--src/utils.c10
17 files changed, 635 insertions, 242 deletions
diff --git a/src/allocators-store.c b/src/allocators-store.c
index 41e30c1..3625484 100644
--- a/src/allocators-store.c
+++ b/src/allocators-store.c
@@ -34,7 +34,12 @@ struct _allocators_store {
} ht;
struct _sum_allocator *sums;
+ guint filter_serial;
+ GList *filters;
+
Chunk *sum_allocator_chunks;
+
+ guint update;
};
typedef struct _allocators_store_class {
@@ -437,6 +442,8 @@ allocators_store_new_sum (AllocatorsStore *store, const gchar *fn)
sum->sorted = FALSE;
sum->blocks = NULL;
sum->largest = NULL;
+ sum->filter_serial = 0;
+ sum->filtered = FALSE;
sum->frame = fn;
@@ -467,13 +474,36 @@ allocators_store_reset_sums (AllocatorsStore *store)
}
}
+static void
+_allocators_store_filter_sum (AllocatorsStore *store,
+ struct _sum_allocator *sum)
+{
+ GList *l;
+
+ if (sum->filter_serial == store->filter_serial)
+ return;
+
+ sum->filter_serial = store->filter_serial;
+
+ if (store->filters == NULL) {
+ sum->filtered = FALSE;
+ return;
+ }
+
+ for (l = store->filters; l != NULL; l = g_list_next (l))
+ if (g_regex_match (l->data, sum->frame, 0, NULL))
+ break;
+
+ sum->filtered = l == NULL;
+}
+
struct _GtkTreePath { /* XXX */
gint depth;
gint *indices;
};
-void
-allocators_store_update (AllocatorsStore *store)
+static gboolean
+_allocators_store_update (AllocatorsStore *store)
{
GtkTreePath path;
GtkTreeIter iter;
@@ -515,7 +545,9 @@ allocators_store_update (AllocatorsStore *store)
allocators = g_ptr_array_new ();
path.depth = 1;
for (sum = store->sums; sum != NULL; sum = sum->next) {
- if (sum->count) {
+ _allocators_store_filter_sum (store, sum);
+
+ if (sum->count && ! sum->filtered) {
g_ptr_array_add (allocators, sum);
} else {
if (sum->old_index != (guint) -1 && sum->index != (guint) -1) {
@@ -542,6 +574,52 @@ allocators_store_update (AllocatorsStore *store)
gtk_tree_model_row_inserted ((GtkTreeModel *) store, &path, &iter);
}
}
+
+ store->update = 0;
+ return FALSE;
+}
+
+void
+allocators_store_update (AllocatorsStore *store)
+{
+ if (store->update == 0) {
+ store->update = gdk_threads_add_idle_full (
+ G_PRIORITY_DEFAULT_IDLE,
+ (GSourceFunc) _allocators_store_update,
+ g_object_ref (store),
+ (GDestroyNotify) g_object_unref);
+ }
+}
+
+void
+allocators_store_reset_filters (AllocatorsStore *store)
+{
+ if (++store->filter_serial == 0)
+ store->filter_serial = 1;
+
+ g_list_foreach (store->filters, (GFunc) g_regex_unref, NULL);
+ g_list_free (store->filters);
+ store->filters = NULL;
+
+ allocators_store_update (store);
+}
+
+gboolean
+allocators_store_add_filter (AllocatorsStore *store,
+ const gchar *pattern,
+ GError **error)
+{
+ GRegex *regex = g_regex_new (pattern, G_REGEX_OPTIMIZE, 0, error);
+ if (regex == NULL)
+ return FALSE;
+
+ store->filters = g_list_prepend (store->filters, regex);
+
+ if (++store->filter_serial == 0)
+ store->filter_serial = 1;
+
+ allocators_store_update (store);
+ return TRUE;
}
void
@@ -578,5 +656,10 @@ allocators_store_update_from_allocators (AllocatorsStore *store,
}
}
- allocators_store_update (store);
+ if (store->update) {
+ g_source_remove (store->update);
+ store->update = 0;
+ }
+
+ _allocators_store_update (store);
}
diff --git a/src/allocators.c b/src/allocators.c
index c9ac354..28cec49 100644
--- a/src/allocators.c
+++ b/src/allocators.c
@@ -278,7 +278,7 @@ allocators_query_tooltip (GtkWidget *widget,
main_fn = app_get_main_function (app_get ((GtkWidget *) self));
last = NULL;
- for (m = n; m < MIN (n + 8, A->n_frames); m++) {
+ for (m = n; m < MIN (n + NUM_CALLERS, A->n_frames); m++) {
if (A->frames[m]->function_srcloc != last) {
g_string_append_c (string, '\n');
g_string_append_c (string, '\t');
diff --git a/src/allocators.h b/src/allocators.h
index 839f438..ad9fe59 100644
--- a/src/allocators.h
+++ b/src/allocators.h
@@ -31,7 +31,9 @@ struct _sum_allocator {
gulong min, max;
Allocator *largest;
Block **blocks;
+ guint filter_serial;
gboolean sorted;
+ gboolean filtered;
struct _sum_allocator *next, *ht_next;
};
@@ -86,4 +88,12 @@ allocators_store_update_from_allocators (AllocatorsStore *store,
Allocator *allocators,
gboolean total);
+gboolean
+allocators_store_add_filter (AllocatorsStore *store,
+ const gchar *pattern,
+ GError **error);
+
+void
+allocators_store_reset_filters (AllocatorsStore *store);
+
#endif /* ALLOCATORS_H */
diff --git a/src/app.c b/src/app.c
index bdec047..65d4d60 100644
--- a/src/app.c
+++ b/src/app.c
@@ -1958,7 +1958,10 @@ lwp_events_server_cb (GIOChannel *source,
int fd = g_io_channel_unix_get_fd (io);
gzFile *file = gzdopen (dup (fd), "r");
- update |= lwp_read (file, app);
+ if (lwp_read (file, app)) {
+ update = TRUE;
+ while (lwp_read (file, app)) ;
+ }
gzclose (file);
gnet_unix_socket_delete (client);
@@ -1967,9 +1970,7 @@ lwp_events_server_cb (GIOChannel *source,
} while (client != NULL);
if (update) {
- if (app->client.timeout)
- _reset_timeout (app->client.timeout, 2000);
- else
+ if (app->client.timeout == NULL)
app->client.timeout = _new_timeout (2000, (GSourceFunc) _update_client, app);
}
}
diff --git a/src/blockmap.c b/src/blockmap.c
index 8461a7c..1f6eec9 100644
--- a/src/blockmap.c
+++ b/src/blockmap.c
@@ -676,7 +676,7 @@ block_map_query_tooltip (GtkWidget *widget,
break;
}
last = NULL;
- for (m = n + 1; m < MIN (n + 9, A->n_frames); m++) {
+ for (m = n + 1; m < MIN (n + NUM_CALLERS + 1, A->n_frames); m++) {
if (A->frames[m]->function_srcloc != last) {
g_string_append_c (string, '\n');
g_string_append_c (string, '\t');
@@ -736,7 +736,7 @@ block_map_query_tooltip (GtkWidget *widget,
break;
}
last = NULL;
- for (m = n + 1; m < MIN (n + 9, A->n_frames); m++) {
+ for (m = n + 1; m < MIN (n + NUM_CALLERS + 1, A->n_frames); m++) {
if (A->frames[m]->function_srcloc != last) {
g_string_append_c (string, '\n');
g_string_append_c (string, '\t');
diff --git a/src/callgraph-treemap.c b/src/callgraph-treemap.c
index a74f44b..13cba3b 100644
--- a/src/callgraph-treemap.c
+++ b/src/callgraph-treemap.c
@@ -616,7 +616,7 @@ call_graph_tree_map_draw_label (CallGraphTreeMap *self,
ctx = gtk_widget_create_pango_context (&self->widget);
merge = pango_context_get_font_description (ctx);
desc = pango_font_description_new ();
- pango_font_description_set_family (desc, "sans");
+ pango_font_description_set_family_static (desc, "sans");
pango_font_description_set_size (desc, PANGO_SCALE * 8);
pango_font_description_set_weight (desc, PANGO_WEIGHT_NORMAL);
pango_font_description_merge (desc, merge, FALSE);
diff --git a/src/callgraph.c b/src/callgraph.c
index ac8eac5..97d1970 100644
--- a/src/callgraph.c
+++ b/src/callgraph.c
@@ -327,7 +327,7 @@ call_graph_query_tooltip (GtkWidget *widget,
do {
if (child->frame != child->parent->frame) {
- if (++n == 8)
+ if (++n == NUM_CALLERS)
break;
if (frame->frame->function == main_fn)
break;
@@ -352,7 +352,7 @@ call_graph_query_tooltip (GtkWidget *widget,
g_string_append (string, frame->frame->function_srcloc);
if (frame->frame->function == main_fn)
break;
- if (++n == 8)
+ if (++n == NUM_CALLERS)
break;
}
if (frame->allocator != NULL)
@@ -363,7 +363,7 @@ call_graph_query_tooltip (GtkWidget *widget,
} else
string = g_string_new ("Called from:");
- if (frame->frame->function != main_fn && n < 8) {
+ if (frame->frame->function != main_fn && n < NUM_CALLERS) {
const gchar *last_frame = frame->frame->function_srcloc;
const Allocator *A = frame->allocator;
guint m = frame->depth + 1;
@@ -376,7 +376,7 @@ call_graph_query_tooltip (GtkWidget *widget,
g_string_append (string, str);
if (A->frames[m]->function == main_fn)
break;
- if (++n == 8)
+ if (++n == NUM_CALLERS)
break;
last_frame = str;
}
diff --git a/src/frames.c b/src/frames.c
index dd281a1..2532617 100644
--- a/src/frames.c
+++ b/src/frames.c
@@ -242,7 +242,9 @@ _frames_init_alloc_fns (Frames *frames)
"([sS]trn?|[mM]em)dup",
"ft_.*alloc", "FT_New_Memory", /* FreeType */
"_hb_.*alloc", /* HarfBuzz */
- "X.*alloc" /* xorg */
+ "X.*alloc", /* xorg */
+
+ "^alloc"
};
guint n;
diff --git a/src/lwp.c b/src/lwp.c
index 5a28595..0416c9e 100644
--- a/src/lwp.c
+++ b/src/lwp.c
@@ -836,6 +836,10 @@ _lwp_record_event (LWP_EventType type, const LWP_Event *ev)
events[n_events].type = type;
events[n_events].time = _lwp_read_time ();
events[n_events].event = *ev;
+ if (n_events) { /* flush the pending events every 10 seconds */
+ if (events[n_events].time - events[0].time > 10000)
+ force_send = TRUE;
+ }
if (G_UNLIKELY (++n_events == G_N_ELEMENTS (events) || force_send)) {
_write_failed = ! _lwp_write_events (events, n_events);
n_events = 0;
diff --git a/src/minibfd/binfile.c b/src/minibfd/binfile.c
index f8e38a4..38cc569 100644
--- a/src/minibfd/binfile.c
+++ b/src/minibfd/binfile.c
@@ -64,7 +64,7 @@ read_inode (const char *filename)
}
static ElfParser *
-separate_debug_file_exists (const char *name, guint32 crc)
+separate_debug_file_exists (const char *name, guint32 crc, gboolean force)
{
ElfParser *parser;
@@ -73,8 +73,12 @@ separate_debug_file_exists (const char *name, guint32 crc)
return NULL;
if (elf_parser_get_crc32 (parser) != crc) {
- elf_parser_free (parser);
- return NULL;
+ if (force) {
+ g_warning ("debug crc mismatch for '%s' (forced load)", name);
+ } else {
+ elf_parser_free (parser);
+ return NULL;
+ }
}
return parser;
@@ -108,7 +112,16 @@ get_debug_file (ElfParser *elf, const char *filename, char **new_name)
tries[3] = g_build_filename (debug_file_directory, dir, basename, NULL);
for (i = 0; i < N_TRIES; ++i) {
- result = separate_debug_file_exists (tries[i], crc32);
+ result = separate_debug_file_exists (tries[i], crc32, FALSE);
+ if (result) {
+ if (new_name)
+ *new_name = g_strdup (tries[i]);
+ break;
+ }
+ }
+
+ for (i = 1; i < N_TRIES; ++i) {
+ result = separate_debug_file_exists (tries[i], crc32, TRUE);
if (result) {
if (new_name)
*new_name = g_strdup (tries[i]);
diff --git a/src/odin.h b/src/odin.h
index ef17348..dac8e55 100644
--- a/src/odin.h
+++ b/src/odin.h
@@ -26,6 +26,8 @@
G_BEGIN_DECLS
+#define NUM_CALLERS 12
+
typedef struct _app App;
typedef struct _client Client;
typedef struct _allocator Allocator;
diff --git a/src/spacetime.c b/src/spacetime.c
index 94a9d0e..830a906 100644
--- a/src/spacetime.c
+++ b/src/spacetime.c
@@ -442,7 +442,7 @@ spacetime_expose (GtkWidget *widget, GdkEventExpose *ev)
ctx = gtk_widget_create_pango_context (&self->widget);
merge = pango_context_get_font_description (ctx);
desc = pango_font_description_new ();
- pango_font_description_set_family (desc, "sans");
+ pango_font_description_set_family_static (desc, "sans");
pango_font_description_set_size (desc, PANGO_SCALE * 8);
pango_font_description_set_weight (desc, PANGO_WEIGHT_NORMAL);
pango_font_description_merge (desc, merge, FALSE);
diff --git a/src/summary-chart.c b/src/summary-chart.c
index 53751bc..e9a5dc1 100644
--- a/src/summary-chart.c
+++ b/src/summary-chart.c
@@ -33,7 +33,8 @@
typedef struct _summary_chart {
GtkWidget widget;
- cairo_surface_t *image;
+ cairo_pattern_t *image;
+ int image_width, image_height;
AllocatorsStore *store;
struct _sum_allocator others;
@@ -140,6 +141,45 @@ summary_chart_realize (GtkWidget *widget)
gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
}
+static void
+summary_chart_load_background (SummaryChart *self, cairo_surface_t *target)
+{
+ static cairo_surface_t *background;
+
+ if (background == NULL)
+ background = cairo_image_surface_create_from_png (DATADIR G_DIR_SEPARATOR_S "odin.png");
+
+ if (cairo_surface_status (background) == CAIRO_STATUS_SUCCESS) {
+ cairo_surface_t *surface;
+ cairo_t *cr;
+ cairo_status_t status;
+
+ self->image_width = cairo_image_surface_get_width (background);
+ self->image_height = cairo_image_surface_get_height (background);
+ surface = cairo_surface_create_similar (target,
+ cairo_surface_get_content (background),
+ self->image_width, self->image_height);
+
+ cr = cairo_create (surface);
+ cairo_set_source_surface (cr, background, 0, 0);
+ cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+ cairo_paint (cr);
+ status = cairo_status (cr);
+ cairo_destroy (cr);
+
+ if (status == CAIRO_STATUS_SUCCESS &&
+ cairo_surface_status (surface) == CAIRO_STATUS_SUCCESS)
+ {
+ self->image = cairo_pattern_create_for_surface (surface);
+ if (cairo_pattern_status (self->image)) {
+ cairo_pattern_destroy (self->image);
+ self->image = NULL;
+ }
+ }
+ cairo_surface_destroy (surface);
+ }
+}
+
static gboolean
summary_chart_expose (GtkWidget *widget, GdkEventExpose *ev)
{
@@ -148,9 +188,9 @@ summary_chart_expose (GtkWidget *widget, GdkEventExpose *ev)
GPtrArray *allocators;
guint64 total;
guint min;
- guint n, ww, hh;
+ guint n;
gint r;
- gdouble theta, theta_offset;
+ gdouble theta, theta_offset, ww, hh;
AllocatorsStoreSort sort;
PangoContext *ctx;
@@ -161,7 +201,7 @@ summary_chart_expose (GtkWidget *widget, GdkEventExpose *ev)
ctx = gtk_widget_create_pango_context (&self->widget);
merge = pango_context_get_font_description (ctx);
desc = pango_font_description_new ();
- pango_font_description_set_family (desc, "sans");
+ pango_font_description_set_family_static (desc, "sans");
pango_font_description_set_size (desc, PANGO_SCALE * 8);
pango_font_description_set_weight (desc, PANGO_WEIGHT_NORMAL);
pango_font_description_merge (desc, merge, FALSE);
@@ -199,20 +239,26 @@ summary_chart_expose (GtkWidget *widget, GdkEventExpose *ev)
}
theta_offset = -G_PI / 2 + (2 * G_PI - theta) / 2.;
- ww = widget->allocation.width / 2;
- hh = widget->allocation.height / 2;
+ ww = .5 * widget->allocation.width;
+ hh = .5 * widget->allocation.height;
/* background */
cairo_arc (cr, ww, hh, r, 0, 2 * G_PI);
cairo_set_source_rgb (cr, .7, .7, .7);
+ if (self->image == NULL)
+ summary_chart_load_background (self, cairo_get_target (cr));
if (self->image != NULL) {
+ cairo_matrix_t matrix;
+
cairo_fill_preserve (cr);
cairo_clip (cr);
- cairo_set_source_surface (cr, self->image,
- ww - cairo_image_surface_get_width (self->image) / 2,
- hh - cairo_image_surface_get_width (self->image) / 2);
+ cairo_matrix_init_translate (&matrix,
+ .5 * self->image_width - ww,
+ .5 * self->image_height - hh);
+ cairo_pattern_set_matrix (self->image, &matrix);
+ cairo_set_source (cr, self->image);
cairo_paint (cr);
cairo_reset_clip (cr);
} else
@@ -280,7 +326,7 @@ summary_chart_expose (GtkWidget *widget, GdkEventExpose *ev)
max_r = mid_r + logical.width / 2.;
arc_height = dtheta * min_r - 4;
if (min_r < r/4 + 2 || max_r > r - 2 || logical.height > arc_height) {
- pango_layout_set_width (text, r*3./4 - 2*BORDER);
+ pango_layout_set_width (text, PANGO_SCALE * (r*3./4 - 2*BORDER));
pango_layout_set_ellipsize (text, PANGO_ELLIPSIZE_END);
pango_layout_get_pixel_extents (text, NULL, &logical);
min_r = mid_r - logical.width / 2.;
@@ -303,7 +349,6 @@ summary_chart_expose (GtkWidget *widget, GdkEventExpose *ev)
}
cairo_set_source_rgb (cr, 0., 0., 0.);
pango_cairo_show_layout (cr, text);
- cairo_stroke (cr);
cairo_restore (cr);
}
g_object_unref (text);
@@ -324,6 +369,19 @@ summary_chart_expose (GtkWidget *widget, GdkEventExpose *ev)
return FALSE;
}
+static void
+summary_chart_unrealize (GtkWidget *widget)
+{
+ SummaryChart *self = (SummaryChart *) widget;
+
+ if (self->image != NULL) {
+ cairo_pattern_destroy (self->image);
+ self->image = NULL;
+ }
+
+ GTK_WIDGET_CLASS (summary_chart_parent_class)->unrealize (widget);
+}
+
static struct _sum_allocator *
_summary_chart_get_sum_for_cursor (SummaryChart *self, gint x, gint y)
{
@@ -461,7 +519,7 @@ summary_chart_query_tooltip (GtkWidget *widget,
main_fn = app_get_main_function (app_get (widget));
last = NULL;
- for (m = n; m < MIN (n + 8, A->n_frames); m++) {
+ for (m = n; m < MIN (n + NUM_CALLERS, A->n_frames); m++) {
if (A->frames[m]->function_srcloc != last) {
g_string_append_c (string, '\n');
g_string_append_c (string, '\t');
@@ -492,8 +550,6 @@ summary_chart_query_tooltip (GtkWidget *widget,
return TRUE;
}
-static cairo_surface_t *background;
-
static void
summary_chart_class_init (SummaryChartClass *klass)
{
@@ -504,6 +560,7 @@ summary_chart_class_init (SummaryChartClass *klass)
object_class->get_property = summary_chart_get_property;
widget_class->realize = summary_chart_realize;
+ widget_class->unrealize = summary_chart_unrealize;
widget_class->expose_event = summary_chart_expose;
widget_class->query_tooltip = summary_chart_query_tooltip;
@@ -518,10 +575,6 @@ summary_chart_class_init (SummaryChartClass *klass)
G_PARAM_STATIC_BLURB |
G_PARAM_STATIC_NAME |
G_PARAM_READWRITE));
-
- background = cairo_image_surface_create_from_png (DATADIR G_DIR_SEPARATOR_S "odin.png");
- if (cairo_surface_status (background))
- background = NULL;
}
@@ -529,7 +582,6 @@ static void
summary_chart_init (SummaryChart *self)
{
self->others.frame = (gchar *) "Others";
- self->image = cairo_surface_reference (background);
gtk_widget_set_has_tooltip (&self->widget, TRUE);
}
diff --git a/src/summary-view.c b/src/summary-view.c
index 8c68120..5e962b8 100644
--- a/src/summary-view.c
+++ b/src/summary-view.c
@@ -165,7 +165,7 @@ summary_view_query_tooltip (GtkWidget *widget,
main_fn = app_get_main_function (app_get (widget));
last = NULL;
- for (m = n; m < MIN (n + 8, A->n_frames); m++) {
+ for (m = n; m < MIN (n + NUM_CALLERS, A->n_frames); m++) {
if (A->frames[m]->function_srcloc != last) {
g_string_append_c (string, '\n');
g_string_append_c (string, '\t');
@@ -220,6 +220,20 @@ summary_view_set_sort_by_count (SummaryView *self)
ALLOCATORS_STORE_SORT_BY_COUNT);
}
+static gboolean
+summary_view_search_equal_func (GtkTreeModel *model,
+ gint column,
+ const gchar *key,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ struct _sum_allocator *sum = iter->user_data;
+ if (sum->filtered)
+ return FALSE;
+ return strncmp (sum->frame, key, strlen (key)) != 0;
+}
+
+
static void
summary_view_init (SummaryView *self)
{
@@ -262,6 +276,12 @@ summary_view_init (SummaryView *self)
self);
gtk_tree_view_append_column (&self->tv, column);
+ gtk_tree_view_set_search_column (&self->tv, ALLOCATORS_FRAME);
+ gtk_tree_view_set_enable_search (&self->tv, TRUE);
+ gtk_tree_view_set_search_equal_func (&self->tv,
+ summary_view_search_equal_func,
+ NULL, NULL);
+
gtk_widget_set_has_tooltip (GTK_WIDGET (self), TRUE);
}
diff --git a/src/summary.c b/src/summary.c
index 4f19614..91a7a8b 100644
--- a/src/summary.c
+++ b/src/summary.c
@@ -101,9 +101,60 @@ summary_class_init (SummaryClass *klass)
}
static void
+do_filter_changed (GtkEntry *entry, Summary *self)
+{
+ const char *filter;
+
+ allocators_store_reset_filters (self->store);
+
+ filter = gtk_entry_get_text (entry);
+ if (filter != NULL && *filter != '\0')
+ allocators_store_add_filter (self->store, filter, NULL);
+}
+
+static void
+do_save_allocators (GtkWidget *widget, Summary *self)
+{
+ GtkWidget *dialog;
+
+ dialog = gtk_file_chooser_dialog_new ("Choose file",
+ GTK_WINDOW (gtk_widget_get_toplevel (widget)),
+ GTK_FILE_CHOOSER_ACTION_SAVE,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
+ NULL);
+ gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER(dialog), TRUE);
+
+ if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
+ char *filename;
+ FILE *file;
+
+ filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
+ file = fopen (filename, "w");
+ g_free (filename);
+
+ if (file != NULL) {
+ GPtrArray *allocators;
+ guint n;
+
+ allocators = allocators_store_get_array (self->store);
+ for (n = 0; n < allocators->len; n++) {
+ struct _sum_allocator *sum = g_ptr_array_index (allocators, n);
+ fprintf (file, "%s\t%d\t%"G_GUINT64_FORMAT"\n",
+ sum->frame, sum->count, sum->size);
+ }
+
+ fclose (file);
+ }
+ }
+
+ gtk_widget_destroy (dialog);
+}
+
+static void
summary_init (Summary *self)
{
- GtkWidget *hbox, *w, *sw;
+ GtkWidget *hbox, *vbox, *lbl, *w, *sw;
self->store = allocators_store_new ();
self->total = TRUE;
@@ -112,18 +163,42 @@ summary_init (Summary *self)
gtk_container_add (GTK_CONTAINER (self), hbox);
gtk_widget_show (hbox);
+ vbox = gtk_vbox_new (FALSE, 2);
+ gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 2);
+ gtk_widget_show (vbox);
+
+ w = summary_chart_new (self->store);
+ gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 2);
+ gtk_widget_show (w);
+
sw = gtk_scrolled_window_new (NULL, NULL);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
- gtk_box_pack_start (GTK_BOX (hbox), sw, FALSE, FALSE, 2);
+ gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 2);
gtk_widget_show (sw);
w = summary_view_new (self->store);
gtk_container_add (GTK_CONTAINER (sw), w);
gtk_widget_show (w);
- w = summary_chart_new (self->store);
- gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 2);
+
+ hbox = gtk_hbox_new (FALSE, 2);
+ gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 2);
+ gtk_widget_show (hbox);
+
+ lbl = gtk_label_new_with_mnemonic ("_Filter");
+ gtk_box_pack_start (GTK_BOX (hbox), lbl, FALSE, FALSE, 2);
+ gtk_widget_show (lbl);
+
+ w = gtk_entry_new ();
+ g_signal_connect (w, "activate", G_CALLBACK (do_filter_changed), self);
+ gtk_box_pack_start (GTK_BOX (hbox), w, FALSE, FALSE, 2);
+ gtk_widget_show (w);
+ gtk_label_set_mnemonic_widget (GTK_LABEL (lbl), w);
+
+ w = gtk_button_new_from_stock (GTK_STOCK_SAVE);
+ g_signal_connect (w, "clicked", G_CALLBACK (do_save_allocators), self);
+ gtk_box_pack_end (GTK_BOX (hbox), w, FALSE, FALSE, 2);
gtk_widget_show (w);
}
diff --git a/src/timeline.c b/src/timeline.c
index 912be76..b6e6832 100644
--- a/src/timeline.c
+++ b/src/timeline.c
@@ -47,6 +47,10 @@ struct _timeline {
guint64 max_bytes;
guint64 max_active;
gint max_blocks;
+
+ cairo_pattern_t *red_yellow_green_pattern;
+ cairo_pattern_t *red_black_green_pattern;
+ cairo_pattern_t *transparent_white_pattern;
};
static GType
@@ -114,6 +118,112 @@ timeline_realize (GtkWidget *widget)
}
#define BORDER 4
+
+static cairo_pattern_t *
+_red_yellow_green_pattern (Timeline *self, cairo_t *cr)
+{
+ cairo_pattern_t *gradient;
+ cairo_surface_t *surface;
+ cairo_t *cr2;
+
+ if (self->red_yellow_green_pattern != NULL)
+ return self->red_yellow_green_pattern;
+
+ surface = cairo_surface_create_similar (cairo_get_target (cr),
+ CAIRO_CONTENT_COLOR,
+ 8, self->widget.allocation.height);
+ cr2 = cairo_create (surface);
+
+ gradient = cairo_pattern_create_linear (
+ 0, BORDER,
+ 0, self->widget.allocation.height - BORDER);
+ cairo_pattern_add_color_stop_rgb (gradient, 0., 0.76, 0.1, 0);
+ cairo_pattern_add_color_stop_rgb (gradient, .40, 0.76, 0.1, 0);
+ cairo_pattern_add_color_stop_rgb (gradient, .45, 0.76, 0.76, 0);
+ cairo_pattern_add_color_stop_rgb (gradient, .55, 0.76, 0.76, 0.);
+ cairo_pattern_add_color_stop_rgb (gradient, .60, 0, 0.76, 0.1);
+ cairo_pattern_add_color_stop_rgb (gradient, 1., 0, 0.76, 0.1);
+ cairo_set_source (cr2, gradient);
+ cairo_pattern_destroy (gradient);
+ cairo_paint (cr2);
+ cairo_destroy (cr2);
+
+ self->red_yellow_green_pattern = cairo_pattern_create_for_surface (surface);
+ cairo_surface_destroy (surface);
+ cairo_pattern_set_extend (self->red_yellow_green_pattern,
+ CAIRO_EXTEND_REPEAT);
+
+ return self->red_yellow_green_pattern;
+}
+
+static cairo_pattern_t *
+_transparent_white_pattern (Timeline *self, cairo_t *cr)
+{
+ cairo_pattern_t *gradient;
+ cairo_surface_t *surface;
+ cairo_t *cr2;
+
+ if (self->transparent_white_pattern != NULL)
+ return self->transparent_white_pattern;
+
+ surface = cairo_surface_create_similar (cairo_get_target (cr),
+ CAIRO_CONTENT_COLOR_ALPHA,
+ 8, self->widget.allocation.height);
+ cr2 = cairo_create (surface);
+
+ gradient = cairo_pattern_create_linear (
+ 0, 0,
+ 0, self->widget.allocation.height);
+ cairo_pattern_add_color_stop_rgba (gradient, 0.0, 1, 1, 1, 0);
+ cairo_pattern_add_color_stop_rgba (gradient, 0.5, 1, 1, 1, 1);
+ cairo_pattern_add_color_stop_rgba (gradient, 1.0, 1, 1, 1, 0);
+ cairo_set_source (cr2, gradient);
+ cairo_pattern_destroy (gradient);
+ cairo_paint (cr2);
+ cairo_destroy (cr2);
+
+ self->transparent_white_pattern = cairo_pattern_create_for_surface (surface);
+ cairo_surface_destroy (surface);
+ cairo_pattern_set_extend (self->transparent_white_pattern,
+ CAIRO_EXTEND_REPEAT);
+
+ return self->transparent_white_pattern;
+}
+
+static cairo_pattern_t *
+_red_black_green_pattern (Timeline *self, cairo_t *cr)
+{
+ cairo_pattern_t *gradient;
+ cairo_surface_t *surface;
+ cairo_t *cr2;
+
+ if (self->red_black_green_pattern != NULL)
+ return self->red_black_green_pattern;
+
+ surface = cairo_surface_create_similar (cairo_get_target (cr),
+ CAIRO_CONTENT_COLOR,
+ 8, self->widget.allocation.height);
+ cr2 = cairo_create (surface);
+
+ gradient = cairo_pattern_create_linear (
+ 0, 0,
+ 0, self->widget.allocation.height);
+ cairo_pattern_add_color_stop_rgb (gradient, 0.0, 1, 0, 0);
+ cairo_pattern_add_color_stop_rgb (gradient, 0.5, 0, 0, 0);
+ cairo_pattern_add_color_stop_rgb (gradient, 1.0, 0, 1, 0);
+ cairo_set_source (cr2, gradient);
+ cairo_pattern_destroy (gradient);
+ cairo_paint (cr2);
+ cairo_destroy (cr2);
+
+ self->red_black_green_pattern = cairo_pattern_create_for_surface (surface);
+ cairo_surface_destroy (surface);
+ cairo_pattern_set_extend (self->red_black_green_pattern,
+ CAIRO_EXTEND_REPEAT);
+
+ return self->red_black_green_pattern;
+}
+
static gboolean
timeline_expose (GtkWidget *widget, GdkEventExpose *ev)
{
@@ -121,7 +231,6 @@ timeline_expose (GtkWidget *widget, GdkEventExpose *ev)
TimelineData *data, *first;
cairo_t *cr;
double dashes[1] = {4.};
- cairo_pattern_t *pattern;
guint last_time;
guint64 last_value;
gdouble last_x;
@@ -134,205 +243,173 @@ timeline_expose (GtkWidget *widget, GdkEventExpose *ev)
if (self->data != NULL)
first = self->data->next;
if (first != NULL) {
- cairo_save (cr);
- cairo_translate (cr, BORDER, widget->allocation.height - BORDER);
- cairo_scale (cr,
- (widget->allocation.width - 2*BORDER) / (gdouble) self->max_time,
- -(widget->allocation.height - 2*BORDER) / (gdouble) (2 * self->max_bytes));
- cairo_translate (cr, 0, self->max_bytes);
-
- /* bytes allocated */
- cairo_move_to (cr, 0, 0);
- cairo_line_to (cr, 0, first->bytes_allocated);
- last_time = last_value = 0;
- for (data = first; data != NULL; data = data->next) {
- guint64 bytes = data->prev->bytes_allocated;
- guint64 value = data->bytes_allocated - bytes;
- cairo_curve_to (cr,
- .5 * (data->time - last_time) + last_time, last_value,
- .5 * (data->time - last_time) + last_time, value,
- data->time, value);
- last_time = data->time;
- last_value = value;
- }
- cairo_line_to (cr, self->max_time, 0);
- cairo_close_path (cr);
-
- cairo_save (cr);
- cairo_identity_matrix (cr);
- pattern = cairo_pattern_create_linear (
- 0, .5 * self->widget.allocation.height,
- 0, 0);
- cairo_pattern_add_color_stop_rgba (pattern, 0, 0, 0, 0, 1);
- cairo_pattern_add_color_stop_rgba (pattern, 1, 1, 0, 0, 1);
- cairo_set_source (cr, pattern);
- cairo_pattern_destroy (pattern);
- cairo_fill (cr);
- cairo_restore (cr);
-
- cairo_scale (cr, 1, -1);
-
- /* bytes freed */
- cairo_move_to (cr, 0, 0);
- cairo_line_to (cr, 0, first->bytes_freed);
- last_time = last_value = 0;
- for (data = first; data != NULL; data = data->next) {
- guint64 bytes = data->prev->bytes_freed;
- guint64 value = data->bytes_freed - bytes;
- cairo_curve_to (cr,
- .5 * (data->time - last_time) + last_time, last_value,
- .5 * (data->time - last_time) + last_time, value,
- data->time, value);
- last_time = data->time;
- last_value = value;
- }
- cairo_line_to (cr, self->max_time, 0);
- cairo_close_path (cr);
-
- cairo_save (cr);
- cairo_identity_matrix (cr);
- pattern = cairo_pattern_create_linear (
- 0, .5 * widget->allocation.height,
- 0, widget->allocation.height);
- cairo_pattern_add_color_stop_rgb (pattern, 0., 0, 0, 0);
- cairo_pattern_add_color_stop_rgb (pattern, 1., 0, 1, 0);
- cairo_set_source (cr, pattern);
- cairo_pattern_destroy (pattern);
- cairo_fill (cr);
- cairo_restore (cr);
-
-
- /* bytes delta */
- cairo_move_to (cr, 0, 0);
- cairo_line_to (cr, 0, first->bytes_allocated - first->bytes_freed);
- last_time = last_value = 0;
- for (data = first; data != NULL; data = data->next) {
- gint bytes = data->prev->bytes_allocated - data->prev->bytes_freed;
- gint value = data->bytes_allocated - data->bytes_freed - bytes;
- if (value < 0)
- value = 0;
- cairo_curve_to (cr,
- .5 * (data->time - last_time) + last_time, last_value,
- .5 * (data->time - last_time) + last_time, value,
- data->time, value);
- last_time = data->time;
- last_value = value;
- }
- cairo_line_to (cr, last_time, 0);
-
- cairo_scale (cr, 1, -1);
-
- cairo_move_to (cr, 0, 0);
- cairo_line_to (cr, 0, first->bytes_allocated - first->bytes_freed);
- last_time = last_value = 0;
- for (data = first; data != NULL; data = data->next) {
- gint bytes = data->prev->bytes_allocated - data->prev->bytes_freed;
- gint value = data->bytes_allocated - data->bytes_freed - bytes;
- if (value < 0)
- value = 0;
- cairo_curve_to (cr,
- .5 * (data->time - last_time) + last_time, last_value,
- .5 * (data->time - last_time) + last_time, value,
- data->time, value);
- last_time = data->time;
- last_value = value;
- }
- cairo_line_to (cr, last_time, 0);
- cairo_close_path (cr);
-
- cairo_save (cr);
- cairo_identity_matrix (cr);
- //cairo_set_source_rgb (cr, 1, 1, 1);
- pattern = cairo_pattern_create_linear (
- 0, 0,
- 0, self->widget.allocation.height);
- cairo_pattern_add_color_stop_rgba (pattern, 0, 1, 1, 1, 0);
- cairo_pattern_add_color_stop_rgba (pattern, 0.5, 1, 1, 1, 1);
- cairo_pattern_add_color_stop_rgba (pattern, 1, 1, 1, 1, 0);
- cairo_set_source (cr, pattern);
- cairo_pattern_destroy (pattern);
- cairo_fill (cr);
- cairo_restore (cr);
-
- cairo_restore (cr);
-
-
- pattern = cairo_pattern_create_linear (
- 0, BORDER,
- 0, self->widget.allocation.height - BORDER);
- cairo_pattern_add_color_stop_rgb (pattern, 0., 0.76, 0.1, 0);
- cairo_pattern_add_color_stop_rgb (pattern, .40, 0.76, 0.1, 0);
- cairo_pattern_add_color_stop_rgb (pattern, .45, 0.76, 0.76, 0);
- cairo_pattern_add_color_stop_rgb (pattern, .55, 0.76, 0.76, 0.);
- cairo_pattern_add_color_stop_rgb (pattern, .60, 0, 0.76, 0.1);
- cairo_pattern_add_color_stop_rgb (pattern, 1., 0, 0.76, 0.1);
- cairo_set_source (cr, pattern);
- cairo_pattern_destroy (pattern);
+ cairo_save (cr); {
+ cairo_translate (cr, BORDER, widget->allocation.height - BORDER);
+ cairo_scale (cr,
+ (widget->allocation.width - 2*BORDER) / (gdouble) self->max_time,
+ -(widget->allocation.height - 2*BORDER) / (gdouble) (2 * self->max_bytes));
+ cairo_translate (cr, 0, self->max_bytes);
+
+
+ /* bytes allocated */
+ cairo_move_to (cr, 0, 0);
+ cairo_line_to (cr, 0, first->bytes_allocated);
+ last_time = last_value = 0;
+ for (data = first; data != NULL; data = data->next) {
+ guint64 bytes = data->prev->bytes_allocated;
+ guint64 value = data->bytes_allocated - bytes;
+ cairo_curve_to (cr,
+ .5 * (data->time - last_time) + last_time, last_value,
+ .5 * (data->time - last_time) + last_time, value,
+ data->time, value);
+ last_time = data->time;
+ last_value = value;
+ }
+ cairo_line_to (cr, self->max_time, 0);
+ cairo_close_path (cr);
+ cairo_save (cr); {
+ cairo_identity_matrix (cr);
+ cairo_set_source (cr, _red_black_green_pattern (self, cr));
+ cairo_fill (cr);
+ } cairo_restore (cr);
+
+ cairo_scale (cr, 1, -1);
+
+ /* bytes freed */
+ cairo_move_to (cr, 0, 0);
+ cairo_line_to (cr, 0, first->bytes_freed);
+ last_time = last_value = 0;
+ for (data = first; data != NULL; data = data->next) {
+ guint64 bytes = data->prev->bytes_freed;
+ guint64 value = data->bytes_freed - bytes;
+ cairo_curve_to (cr,
+ .5 * (data->time - last_time) + last_time, last_value,
+ .5 * (data->time - last_time) + last_time, value,
+ data->time, value);
+ last_time = data->time;
+ last_value = value;
+ }
+ cairo_line_to (cr, self->max_time, 0);
+ cairo_close_path (cr);
+ cairo_save (cr); {
+ cairo_identity_matrix (cr);
+ cairo_set_source (cr, _red_black_green_pattern (self, cr));
+ cairo_fill (cr);
+ } cairo_restore (cr);
+
+ /* bytes delta */
+ cairo_move_to (cr, 0, 0);
+ cairo_line_to (cr, 0, first->bytes_allocated - first->bytes_freed);
+ last_time = last_value = 0;
+ for (data = first; data != NULL; data = data->next) {
+ gint bytes = data->prev->bytes_allocated - data->prev->bytes_freed;
+ gint value = data->bytes_allocated - data->bytes_freed - bytes;
+ if (value < 0)
+ value = 0;
+ cairo_curve_to (cr,
+ .5 * (data->time - last_time) + last_time, last_value,
+ .5 * (data->time - last_time) + last_time, value,
+ data->time, value);
+ last_time = data->time;
+ last_value = value;
+ }
+ cairo_line_to (cr, last_time, 0);
+
+ cairo_scale (cr, 1, -1);
+
+ cairo_move_to (cr, 0, 0);
+ cairo_line_to (cr, 0, first->bytes_allocated - first->bytes_freed);
+ last_time = last_value = 0;
+ for (data = first; data != NULL; data = data->next) {
+ gint bytes = data->prev->bytes_allocated - data->prev->bytes_freed;
+ gint value = data->bytes_allocated - data->bytes_freed - bytes;
+ if (value < 0)
+ value = 0;
+ cairo_curve_to (cr,
+ .5 * (data->time - last_time) + last_time, last_value,
+ .5 * (data->time - last_time) + last_time, value,
+ data->time, value);
+ last_time = data->time;
+ last_value = value;
+ }
+ cairo_line_to (cr, last_time, 0);
+ cairo_close_path (cr);
+
+ cairo_save (cr); {
+ cairo_identity_matrix (cr);
+ cairo_set_source (cr, _transparent_white_pattern (self, cr));
+ cairo_fill (cr);
+ } cairo_restore (cr);
+
+ } cairo_restore (cr);
+
+
+ cairo_set_source (cr, _red_yellow_green_pattern (self, cr));
cairo_set_line_width (cr, 2.0);
- cairo_save (cr);
- cairo_translate (cr, BORDER, widget->allocation.height - BORDER);
- cairo_scale (cr,
- (widget->allocation.width - 2*BORDER) / (gdouble) self->max_time,
- -(widget->allocation.height - 2*BORDER) / (gdouble) (2 * self->max_blocks));
- cairo_translate (cr, 0, self->max_blocks);
-
-
- /* allocation bias */
- cairo_move_to (cr, 0, first->prev->alloc_bias);
- for (data = first; data != NULL; data = data->next) {
- gint last_bias = data->prev->alloc_bias;
- cairo_line_to (cr, data->time, data->alloc_bias - last_bias);
- }
- cairo_save (cr);
- cairo_identity_matrix (cr);
- cairo_stroke (cr);
- cairo_restore (cr);
- cairo_restore (cr);
+ cairo_save (cr); {
+ cairo_translate (cr, BORDER, widget->allocation.height - BORDER);
+ cairo_scale (cr,
+ (widget->allocation.width - 2*BORDER) / (gdouble) self->max_time,
+ -(widget->allocation.height - 2*BORDER) / (gdouble) (2 * self->max_blocks));
+ cairo_translate (cr, 0, self->max_blocks);
+
+
+ /* allocation bias */
+ cairo_move_to (cr, 0, first->prev->alloc_bias);
+ for (data = first; data != NULL; data = data->next) {
+ gint last_bias = data->prev->alloc_bias;
+ cairo_line_to (cr, data->time, data->alloc_bias - last_bias);
+ }
+ cairo_save (cr); {
+ cairo_identity_matrix (cr);
+ cairo_stroke (cr);
+ } cairo_restore (cr);
+ } cairo_restore (cr);
/* active bytes */
- cairo_save (cr);
- cairo_translate (cr, BORDER, widget->allocation.height - BORDER);
- cairo_scale (cr,
- (widget->allocation.width - 2*BORDER) / (gdouble) self->max_time,
- -(widget->allocation.height - 2*BORDER) / (gdouble) (2 * self->max_active));
- cairo_translate (cr, 0, self->max_active);
-
- cairo_set_source_rgb (cr, 1, 1, 1);
- /* struts */
- last_x = 0;
- for (data = first; data->next != NULL; data = data->next) {
- gdouble x;
-
- x = floor ((widget->allocation.width - 2*BORDER) / (gdouble) self->max_time * data->time) - .5;
- /* maintain a minimum of 10 pixels between struts */
- if (x - last_x < 10.)
- continue;
-
- last_x = x;
- x *= self->max_time / (gdouble) (widget->allocation.width - 2*BORDER);
-
- cairo_move_to (cr, x, 0);
- cairo_line_to (cr, x, data->bytes_allocated - data->bytes_freed);
-
- cairo_save (cr);
+ cairo_save (cr); {
+ cairo_translate (cr, BORDER, widget->allocation.height - BORDER);
+ cairo_scale (cr,
+ (widget->allocation.width - 2*BORDER) / (gdouble) self->max_time,
+ -(widget->allocation.height - 2*BORDER) / (gdouble) (2 * self->max_active));
+ cairo_translate (cr, 0, self->max_active);
+
+ cairo_set_source_rgb (cr, 1, 1, 1);
+ /* struts */
+ last_x = 0;
+ for (data = first; data->next != NULL; data = data->next) {
+ gdouble x;
+
+ x = floor ((widget->allocation.width - 2*BORDER) / (gdouble) self->max_time * data->time) - .5;
+ /* maintain a minimum of 10 pixels between struts */
+ if (x - last_x < 10.)
+ continue;
+
+ last_x = x;
+ x *= self->max_time / (gdouble) (widget->allocation.width - 2*BORDER);
+
+ cairo_move_to (cr, x, 0);
+ cairo_line_to (cr, x, data->bytes_allocated - data->bytes_freed);
+
+ cairo_save (cr); {
+ cairo_identity_matrix (cr);
+ cairo_set_dash (cr, dashes, 1, 0.);
+ cairo_set_line_width (cr, 1.);
+ cairo_stroke (cr);
+ } cairo_restore (cr);
+ }
+
+ /* bytes allocated */
+ cairo_move_to (cr, 0, 0);
+ for (data = first; data != NULL; data = data->next) {
+ cairo_line_to (cr,
+ data->time,
+ data->bytes_allocated - data->bytes_freed);
+ }
cairo_identity_matrix (cr);
- cairo_set_dash (cr, dashes, 1, 0.);
- cairo_set_line_width (cr, 1.);
cairo_stroke (cr);
- cairo_restore (cr);
- }
-
- /* bytes allocated */
- cairo_move_to (cr, 0, 0);
- for (data = first; data != NULL; data = data->next) {
- cairo_line_to (cr,
- data->time,
- data->bytes_allocated - data->bytes_freed);
- }
- cairo_identity_matrix (cr);
- cairo_stroke (cr);
- cairo_restore (cr);
+ } cairo_restore (cr);
/* draw a fine-line to show zero */
cairo_move_to (cr,
@@ -358,6 +435,52 @@ timeline_expose (GtkWidget *widget, GdkEventExpose *ev)
}
static void
+timeline_unrealize (GtkWidget *widget)
+{
+ Timeline *self = (Timeline *) widget;
+
+ if (self->red_yellow_green_pattern != NULL) {
+ cairo_pattern_destroy (self->red_yellow_green_pattern);
+ self->red_yellow_green_pattern = NULL;
+ }
+
+ if (self->transparent_white_pattern != NULL) {
+ cairo_pattern_destroy (self->transparent_white_pattern);
+ self->transparent_white_pattern = NULL;
+ }
+
+ if (self->red_black_green_pattern != NULL) {
+ cairo_pattern_destroy (self->red_black_green_pattern);
+ self->red_black_green_pattern = NULL;
+ }
+
+ GTK_WIDGET_CLASS (timeline_parent_class)->unrealize (widget);
+}
+
+static void
+timeline_size_allocate (GtkWidget *widget, GdkRectangle *allocation)
+{
+ Timeline *self = (Timeline *) widget;
+
+ if (self->red_yellow_green_pattern != NULL) {
+ cairo_pattern_destroy (self->red_yellow_green_pattern);
+ self->red_yellow_green_pattern = NULL;
+ }
+
+ if (self->transparent_white_pattern != NULL) {
+ cairo_pattern_destroy (self->transparent_white_pattern);
+ self->transparent_white_pattern = NULL;
+ }
+
+ if (self->red_black_green_pattern != NULL) {
+ cairo_pattern_destroy (self->red_black_green_pattern);
+ self->red_black_green_pattern = NULL;
+ }
+
+ GTK_WIDGET_CLASS (timeline_parent_class)->size_allocate (widget, allocation);
+}
+
+static void
timeline_class_init (TimelineClass *klass)
{
GObjectClass *object_class = (GObjectClass *) klass;
@@ -367,7 +490,9 @@ timeline_class_init (TimelineClass *klass)
object_class->get_property = timeline_get_property;
widget_class->realize = timeline_realize;
+ widget_class->unrealize = timeline_unrealize;
widget_class->expose_event = timeline_expose;
+ widget_class->size_allocate = timeline_size_allocate;
}
static void
diff --git a/src/utils.c b/src/utils.c
index ac641f3..3656864 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -59,7 +59,10 @@ cell_layout_pretty_print_uint (GtkCellLayout *layout,
len = g_snprintf (buf + 40, 40, "%u", v);
pretty_print_number (buf + 40, len, buf);
- g_object_set (G_OBJECT (cell), "text", buf, NULL);
+ g_object_set (G_OBJECT (cell),
+ "text", buf,
+ "xalign", (gfloat) 1.0,
+ NULL);
}
void
@@ -78,7 +81,10 @@ cell_layout_pretty_print_uint64 (GtkCellLayout *layout,
len = g_snprintf (buf + 80, 80, "%" G_GUINT64_FORMAT, v);
pretty_print_number (buf + 80, len, buf);
- g_object_set (G_OBJECT (cell), "text", buf, NULL);
+ g_object_set (G_OBJECT (cell),
+ "text", buf,
+ "xalign", (gfloat) 1.0,
+ NULL);
}
void