X-Git-Url: http://git.lttng.org./?a=blobdiff_plain;f=lttv%2Fmodules%2Fgui%2Flttvwindow%2Flttvwindow%2Ftimebar.c;fp=lttv%2Fmodules%2Fgui%2Flttvwindow%2Flttvwindow%2Ftimebar.c;h=9673ec669a97c551f9054f2cd2eaeebfe48f8bd3;hb=4172f013ca271667f6be4735216e9f69578a88fd;hp=0000000000000000000000000000000000000000;hpb=0fe54b017fd76e78304066575103681ea7a36457;p=lttv.git diff --git a/lttv/modules/gui/lttvwindow/lttvwindow/timebar.c b/lttv/modules/gui/lttvwindow/lttvwindow/timebar.c new file mode 100644 index 00000000..9673ec66 --- /dev/null +++ b/lttv/modules/gui/lttvwindow/lttvwindow/timebar.c @@ -0,0 +1,424 @@ +/* This file is part of the Linux Trace Toolkit viewer + * Copyright (C) 2010 Yannick Brosseau + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License Version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA. + */ +#include "timebar.h" + +#include "timeentry.h" + +#include +#include +#include + +enum { + SIGNAL_START_TIME_CHANGED, + SIGNAL_END_TIME_CHANGED, + SIGNAL_CURRENT_TIME_CHANGED, + LAST_SIGNAL +}; + +static void timebar_class_init(TimebarClass *klass); +static void timebar_init(Timebar *ttt); + +static guint timebar_signals[LAST_SIGNAL] = { 0 }; + +static void on_start_time_value_changed(Timeentry *spinbutton, + gpointer user_data); +static void on_end_time_value_changed(Timeentry *spinbutton, + gpointer user_data); +static void on_interval_time_value_changed(Timeentry *spinbutton, + gpointer user_data); +static void on_current_time_value_changed(Timeentry *spinbutton, + gpointer user_data); + +static void update_interval(Timebar *timebar); + +static inline LttTime timeentry_get_ltt_time(Timeentry *timeentry) +{ + LttTime time; + + timeentry_get_time(timeentry, + &time.tv_sec, + &time.tv_nsec); + return time; +} + +GType timebar_get_type(void) +{ + static GType tb_type = 0; + + if (!tb_type) { + const GTypeInfo tb_info = + { + sizeof (TimebarClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) timebar_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (Timebar), + 0, /* n_preallocs */ + (GInstanceInitFunc) timebar_init, + }; + + tb_type = g_type_register_static(GTK_TYPE_HBOX, + "Timebar", + &tb_info, + 0); + } + + return tb_type; +} + + +static void timebar_class_init(TimebarClass *klass) +{ + timebar_signals[SIGNAL_START_TIME_CHANGED] = g_signal_new("start-time-changed", + G_TYPE_FROM_CLASS(klass), + G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET(TimebarClass, timebar), + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + timebar_signals[SIGNAL_END_TIME_CHANGED] = g_signal_new("end-time-changed", + G_TYPE_FROM_CLASS(klass), + G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET(TimebarClass, timebar), + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + timebar_signals[SIGNAL_CURRENT_TIME_CHANGED] = g_signal_new("current-time-changed", + G_TYPE_FROM_CLASS(klass), + G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET(TimebarClass, timebar), + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); +} + + +static void timebar_init(Timebar *timebar) +{ + /* Title label */ + timebar->title_eventbox = gtk_event_box_new(); + gtk_widget_show(timebar->title_eventbox); + + timebar->title_label = gtk_label_new("Time Frame "); + gtk_widget_show(timebar->title_label); + gtk_container_add(GTK_CONTAINER(timebar->title_eventbox), timebar->title_label); + + /* Start time entry */ + timebar->start_timeentry = timeentry_new("Start: "); + gtk_widget_show(timebar->start_timeentry); + + /* End time entry */ + timebar->end_timeentry = timeentry_new("End: "); + gtk_widget_show(timebar->end_timeentry); + + /* Interval time entry */ + timebar->interval_timeentry = timeentry_new("Time Interval: "); + gtk_widget_show(timebar->interval_timeentry); + + /* Current time entry */ + timebar->current_timeentry = timeentry_new("Current Time: "); + gtk_widget_show(timebar->current_timeentry); + + /* Pack all the widget in the timebar box */ + GtkWidget *temp_widget; + + gtk_box_pack_start (GTK_BOX(timebar), timebar->title_eventbox, FALSE, FALSE, 2); + + gtk_box_pack_start (GTK_BOX(timebar), timebar->start_timeentry, FALSE, FALSE, 0); + + temp_widget = gtk_vseparator_new(); + gtk_widget_show(temp_widget); + gtk_box_pack_start (GTK_BOX(timebar), temp_widget, FALSE, FALSE, 2); + + gtk_box_pack_start (GTK_BOX(timebar), timebar->end_timeentry, FALSE, FALSE, 0); + + temp_widget = gtk_vseparator_new(); + gtk_widget_show(temp_widget); + gtk_box_pack_start (GTK_BOX(timebar), temp_widget, FALSE, FALSE, 2); + + gtk_box_pack_start (GTK_BOX(timebar), timebar->interval_timeentry, FALSE, FALSE, 0); + + gtk_box_pack_end (GTK_BOX(timebar), timebar->current_timeentry, FALSE, FALSE, 0); + temp_widget = gtk_vseparator_new(); + gtk_widget_show(temp_widget); + gtk_box_pack_end (GTK_BOX(timebar), temp_widget, FALSE, FALSE, 2); + + /* Set an initial time */ + timebar_set_minmax_time(timebar, <t_time_zero, <t_time_one); + + /* Connect signals */ + g_signal_connect ((gpointer) timebar->start_timeentry, "time-changed", + G_CALLBACK(on_start_time_value_changed), + timebar); + g_signal_connect ((gpointer) timebar->end_timeentry, "time-changed", + G_CALLBACK(on_end_time_value_changed), + timebar); + timebar->interval_handler_id = + g_signal_connect ((gpointer) timebar->interval_timeentry, "time-changed", + G_CALLBACK (on_interval_time_value_changed), + timebar); + g_signal_connect ((gpointer) timebar->current_timeentry, "time-changed", + G_CALLBACK(on_current_time_value_changed), + timebar); +} + +GtkWidget *timebar_new(void) +{ + return GTK_WIDGET(g_object_new (TIMEBAR_TYPE, NULL)); +} + +void timebar_set_current_time(Timebar *timebar, const LttTime* time) +{ + if (time == NULL) { + return; + } + + timeentry_set_time(TIMEENTRY(timebar->current_timeentry), + time->tv_sec, + time->tv_nsec); +} + +void timebar_set_start_time(Timebar *timebar, const LttTime* time) +{ + if (time == NULL) { + return; + } + + timeentry_set_time(TIMEENTRY(timebar->start_timeentry), + time->tv_sec, + time->tv_nsec); + + update_interval(timebar); +} + +void timebar_set_end_time(Timebar *timebar, const LttTime* time) +{ + if (time == NULL) { + return; + } + + timeentry_set_time(TIMEENTRY(timebar->end_timeentry), + time->tv_sec, + time->tv_nsec); + update_interval(timebar); +} + +void timebar_set_minmax_time(Timebar *timebar, + const LttTime *min_time, + const LttTime *max_time) +{ + LttTime new_interval_length; + LttTime start_max_time; + LttTime end_min_time; + + /* Need to set both min_time and max_time */ + if (min_time == NULL || max_time == NULL) { + return; + } + /* Do nothing if there is no change */ + if (ltt_time_compare(timebar->min_time, *min_time) == 0 && + ltt_time_compare(timebar->max_time, *max_time) == 0 + ) { + return; + } + + if (min_time != NULL) { + timebar->min_time = *min_time; + } + + if (max_time != NULL) { + timebar->max_time = *max_time; + } + + + if (ltt_time_compare(timebar->min_time, timebar->max_time) == 0) { + + /* If the min and max are equal set the same values, which will + disable all the widgets of the timebar */ + new_interval_length.tv_sec = 0; + new_interval_length.tv_nsec = 1; + + start_max_time.tv_sec = timebar->max_time.tv_sec; + start_max_time.tv_nsec = timebar->max_time.tv_nsec; + + end_min_time.tv_sec = timebar->min_time.tv_sec; + end_min_time.tv_nsec = timebar->min_time.tv_nsec; + + } else { + /* Special minmax (to keep a minimum interval of 1 nsec */ + /* start max time is max minus 1 nsec */ + if (timebar->max_time.tv_nsec == 0) { + start_max_time.tv_sec = timebar->max_time.tv_sec - 1; + start_max_time.tv_nsec = NANOSECONDS_PER_SECOND - 1; + } else { + start_max_time.tv_sec = timebar->max_time.tv_sec; + start_max_time.tv_nsec = timebar->max_time.tv_nsec - 1; + } + + /* end min time is min plus 1 nsec */ + if (timebar->min_time.tv_nsec + 1 == NANOSECONDS_PER_SECOND) { + end_min_time.tv_sec = timebar->min_time.tv_sec + 1; + end_min_time.tv_nsec = 0; + } else { + end_min_time.tv_sec = timebar->min_time.tv_sec; + end_min_time.tv_nsec = timebar->min_time.tv_nsec + 1; + } + + /* Compute max interval */ + new_interval_length = ltt_time_sub(timebar->max_time, + timebar->min_time); + } + + + /* Update widgets */ + timeentry_set_minmax_time(TIMEENTRY(timebar->start_timeentry), + timebar->min_time.tv_sec, + timebar->min_time.tv_nsec, + start_max_time.tv_sec, + start_max_time.tv_nsec); + timeentry_set_minmax_time(TIMEENTRY(timebar->end_timeentry), + end_min_time.tv_sec, + end_min_time.tv_nsec, + timebar->max_time.tv_sec, + timebar->max_time.tv_nsec); + timeentry_set_minmax_time(TIMEENTRY(timebar->current_timeentry), + timebar->min_time.tv_sec, + timebar->min_time.tv_nsec, + timebar->max_time.tv_sec, + timebar->max_time.tv_nsec); + + + timeentry_set_minmax_time(TIMEENTRY(timebar->interval_timeentry), + 0, + 1, + new_interval_length.tv_sec, + new_interval_length.tv_nsec); +} + +LttTime timebar_get_start_time(Timebar *timebar) +{ + return timeentry_get_ltt_time(TIMEENTRY(timebar->start_timeentry)); +} + +LttTime timebar_get_end_time(Timebar *timebar) +{ + return timeentry_get_ltt_time(TIMEENTRY(timebar->end_timeentry)); +} + +LttTime timebar_get_current_time(Timebar *timebar) +{ + return timeentry_get_ltt_time(TIMEENTRY(timebar->current_timeentry)); +} + +static void update_interval(Timebar *timebar) +{ + LttTime start_time = timeentry_get_ltt_time(TIMEENTRY(timebar->start_timeentry)); + LttTime end_time = timeentry_get_ltt_time(TIMEENTRY(timebar->end_timeentry)); + LttTime new_interval; + + /* Compute max interval */ + new_interval = ltt_time_sub(end_time, + start_time); + + /* Don't trigger the signal when we update the interval */ + g_signal_handler_block(timebar->interval_timeentry, + timebar->interval_handler_id); + + timeentry_set_time(TIMEENTRY(timebar->interval_timeentry), + new_interval.tv_sec, + new_interval.tv_nsec); + + g_signal_handler_unblock(timebar->interval_timeentry, + timebar->interval_handler_id); +} + +static void on_start_time_value_changed(Timeentry *timeentry, + gpointer user_data) +{ + Timebar *timebar = (Timebar *)user_data; + + update_interval(timebar); + + g_signal_emit(timebar, + timebar_signals[SIGNAL_START_TIME_CHANGED], 0); +} + +static void on_end_time_value_changed(Timeentry *timeentry, + gpointer user_data) +{ + Timebar *timebar = (Timebar *)user_data; + + update_interval(timebar); + + g_signal_emit(timebar, + timebar_signals[SIGNAL_END_TIME_CHANGED], 0); +} + +static void on_interval_time_value_changed (Timeentry *timeentry, + gpointer user_data) +{ + Timebar *timebar = (Timebar *)user_data; + + LttTime new_interval = timeentry_get_ltt_time(TIMEENTRY(timebar->interval_timeentry)); + + LttTime start_time = timebar_get_start_time(timebar); + + LttTime new_end_time; + + gboolean need_interval_update = FALSE; + + /* Lock the start and change the end */ + new_end_time = ltt_time_add(start_time, new_interval); + + /* We cannot push further the max end */ + if (ltt_time_compare(new_end_time, timebar->max_time) > 0) { + /* Set the end to the max and pull on the start */ + new_end_time = timebar->max_time; + LttTime new_start_time = ltt_time_sub(new_end_time, new_interval); + + /* We cannot pull before the min start */ + if (ltt_time_compare(new_start_time, timebar->min_time) < 0) { + /* Set the interval to the max */ + new_start_time = timebar->min_time; + need_interval_update = TRUE; + } + timebar_set_start_time(timebar, &new_start_time); + } + timebar_set_end_time(timebar, &new_end_time); + + if (need_interval_update) { + update_interval(timebar); + } +} + +static void on_current_time_value_changed(Timeentry *timeentry, + gpointer user_data) +{ + Timebar *timebar = (Timebar *)user_data; + + g_signal_emit(timebar, + timebar_signals[SIGNAL_CURRENT_TIME_CHANGED], 0); +} + +