1 /* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2010 Yannick Brosseau
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License Version 2 as
6 * published by the Free Software Foundation;
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
20 #include "timeentry.h"
22 #include <gtk/gtkeventbox.h>
23 #include <gtk/gtkvseparator.h>
27 SIGNAL_START_TIME_CHANGED
,
28 SIGNAL_END_TIME_CHANGED
,
29 SIGNAL_CURRENT_TIME_CHANGED
,
33 static void timebar_class_init(TimebarClass
*klass
);
34 static void timebar_init(Timebar
*ttt
);
36 static guint timebar_signals
[LAST_SIGNAL
] = { 0 };
38 static void on_start_time_value_changed(Timeentry
*spinbutton
,
40 static void on_end_time_value_changed(Timeentry
*spinbutton
,
42 static void on_interval_time_value_changed(Timeentry
*spinbutton
,
44 static void on_current_time_value_changed(Timeentry
*spinbutton
,
47 static void update_interval(Timebar
*timebar
);
49 static inline LttTime
timeentry_get_ltt_time(Timeentry
*timeentry
)
53 timeentry_get_time(timeentry
,
59 GType
timebar_get_type(void)
61 static GType tb_type
= 0;
64 const GTypeInfo tb_info
=
66 sizeof (TimebarClass
),
68 NULL
, /* base_finalize */
69 (GClassInitFunc
) timebar_class_init
,
70 NULL
, /* class_finalize */
71 NULL
, /* class_data */
74 (GInstanceInitFunc
) timebar_init
,
77 tb_type
= g_type_register_static(GTK_TYPE_HBOX
,
87 static void timebar_class_init(TimebarClass
*klass
)
89 timebar_signals
[SIGNAL_START_TIME_CHANGED
] = g_signal_new("start-time-changed",
90 G_TYPE_FROM_CLASS(klass
),
91 G_SIGNAL_RUN_FIRST
| G_SIGNAL_ACTION
,
92 G_STRUCT_OFFSET(TimebarClass
, timebar
),
95 g_cclosure_marshal_VOID__VOID
,
98 timebar_signals
[SIGNAL_END_TIME_CHANGED
] = g_signal_new("end-time-changed",
99 G_TYPE_FROM_CLASS(klass
),
100 G_SIGNAL_RUN_FIRST
| G_SIGNAL_ACTION
,
101 G_STRUCT_OFFSET(TimebarClass
, timebar
),
104 g_cclosure_marshal_VOID__VOID
,
106 timebar_signals
[SIGNAL_CURRENT_TIME_CHANGED
] = g_signal_new("current-time-changed",
107 G_TYPE_FROM_CLASS(klass
),
108 G_SIGNAL_RUN_FIRST
| G_SIGNAL_ACTION
,
109 G_STRUCT_OFFSET(TimebarClass
, timebar
),
112 g_cclosure_marshal_VOID__VOID
,
117 static void timebar_init(Timebar
*timebar
)
120 timebar
->title_eventbox
= gtk_event_box_new();
121 gtk_widget_show(timebar
->title_eventbox
);
123 timebar
->title_label
= gtk_label_new("Time Frame ");
124 gtk_widget_show(timebar
->title_label
);
125 gtk_container_add(GTK_CONTAINER(timebar
->title_eventbox
), timebar
->title_label
);
127 /* Start time entry */
128 timebar
->start_timeentry
= timeentry_new("Start: ");
129 gtk_widget_show(timebar
->start_timeentry
);
132 timebar
->end_timeentry
= timeentry_new("End: ");
133 gtk_widget_show(timebar
->end_timeentry
);
135 /* Interval time entry */
136 timebar
->interval_timeentry
= timeentry_new("Time Interval: ");
137 gtk_widget_show(timebar
->interval_timeentry
);
139 /* Current time entry */
140 timebar
->current_timeentry
= timeentry_new("Current Time: ");
141 gtk_widget_show(timebar
->current_timeentry
);
143 /* Pack all the widget in the timebar box */
144 GtkWidget
*temp_widget
;
146 gtk_box_pack_start (GTK_BOX(timebar
), timebar
->title_eventbox
, FALSE
, FALSE
, 2);
148 gtk_box_pack_start (GTK_BOX(timebar
), timebar
->start_timeentry
, FALSE
, FALSE
, 0);
150 temp_widget
= gtk_vseparator_new();
151 gtk_widget_show(temp_widget
);
152 gtk_box_pack_start (GTK_BOX(timebar
), temp_widget
, FALSE
, FALSE
, 2);
154 gtk_box_pack_start (GTK_BOX(timebar
), timebar
->end_timeentry
, FALSE
, FALSE
, 0);
156 temp_widget
= gtk_vseparator_new();
157 gtk_widget_show(temp_widget
);
158 gtk_box_pack_start (GTK_BOX(timebar
), temp_widget
, FALSE
, FALSE
, 2);
160 gtk_box_pack_start (GTK_BOX(timebar
), timebar
->interval_timeentry
, FALSE
, FALSE
, 0);
162 gtk_box_pack_end (GTK_BOX(timebar
), timebar
->current_timeentry
, FALSE
, FALSE
, 0);
163 temp_widget
= gtk_vseparator_new();
164 gtk_widget_show(temp_widget
);
165 gtk_box_pack_end (GTK_BOX(timebar
), temp_widget
, FALSE
, FALSE
, 2);
167 /* Set an initial time */
168 timebar_set_minmax_time(timebar
, <t_time_zero
, <t_time_one
);
170 /* Connect signals */
171 g_signal_connect ((gpointer
) timebar
->start_timeentry
, "time-changed",
172 G_CALLBACK(on_start_time_value_changed
),
174 g_signal_connect ((gpointer
) timebar
->end_timeentry
, "time-changed",
175 G_CALLBACK(on_end_time_value_changed
),
177 timebar
->interval_handler_id
=
178 g_signal_connect ((gpointer
) timebar
->interval_timeentry
, "time-changed",
179 G_CALLBACK (on_interval_time_value_changed
),
181 g_signal_connect ((gpointer
) timebar
->current_timeentry
, "time-changed",
182 G_CALLBACK(on_current_time_value_changed
),
186 GtkWidget
*timebar_new(void)
188 return GTK_WIDGET(g_object_new (TIMEBAR_TYPE
, NULL
));
191 void timebar_set_current_time(Timebar
*timebar
, const LttTime
* time
)
197 timeentry_set_time(TIMEENTRY(timebar
->current_timeentry
),
202 void timebar_set_start_time(Timebar
*timebar
, const LttTime
* time
)
208 timeentry_set_time(TIMEENTRY(timebar
->start_timeentry
),
212 update_interval(timebar
);
215 void timebar_set_end_time(Timebar
*timebar
, const LttTime
* time
)
221 timeentry_set_time(TIMEENTRY(timebar
->end_timeentry
),
224 update_interval(timebar
);
227 void timebar_set_minmax_time(Timebar
*timebar
,
228 const LttTime
*min_time
,
229 const LttTime
*max_time
)
231 LttTime new_interval_length
;
232 LttTime start_max_time
;
233 LttTime end_min_time
;
235 /* Need to set both min_time and max_time */
236 if (min_time
== NULL
|| max_time
== NULL
) {
239 /* Do nothing if there is no change */
240 if (ltt_time_compare(timebar
->min_time
, *min_time
) == 0 &&
241 ltt_time_compare(timebar
->max_time
, *max_time
) == 0
246 if (min_time
!= NULL
) {
247 timebar
->min_time
= *min_time
;
250 if (max_time
!= NULL
) {
251 timebar
->max_time
= *max_time
;
255 if (ltt_time_compare(timebar
->min_time
, timebar
->max_time
) == 0) {
257 /* If the min and max are equal set the same values, which will
258 disable all the widgets of the timebar */
259 new_interval_length
.tv_sec
= 0;
260 new_interval_length
.tv_nsec
= 1;
262 start_max_time
.tv_sec
= timebar
->max_time
.tv_sec
;
263 start_max_time
.tv_nsec
= timebar
->max_time
.tv_nsec
;
265 end_min_time
.tv_sec
= timebar
->min_time
.tv_sec
;
266 end_min_time
.tv_nsec
= timebar
->min_time
.tv_nsec
;
269 /* Special minmax (to keep a minimum interval of 1 nsec */
270 /* start max time is max minus 1 nsec */
271 if (timebar
->max_time
.tv_nsec
== 0) {
272 start_max_time
.tv_sec
= timebar
->max_time
.tv_sec
- 1;
273 start_max_time
.tv_nsec
= NANOSECONDS_PER_SECOND
- 1;
275 start_max_time
.tv_sec
= timebar
->max_time
.tv_sec
;
276 start_max_time
.tv_nsec
= timebar
->max_time
.tv_nsec
- 1;
279 /* end min time is min plus 1 nsec */
280 if (timebar
->min_time
.tv_nsec
+ 1 == NANOSECONDS_PER_SECOND
) {
281 end_min_time
.tv_sec
= timebar
->min_time
.tv_sec
+ 1;
282 end_min_time
.tv_nsec
= 0;
284 end_min_time
.tv_sec
= timebar
->min_time
.tv_sec
;
285 end_min_time
.tv_nsec
= timebar
->min_time
.tv_nsec
+ 1;
288 /* Compute max interval */
289 new_interval_length
= ltt_time_sub(timebar
->max_time
,
295 timeentry_set_minmax_time(TIMEENTRY(timebar
->start_timeentry
),
296 timebar
->min_time
.tv_sec
,
297 timebar
->min_time
.tv_nsec
,
298 start_max_time
.tv_sec
,
299 start_max_time
.tv_nsec
);
300 timeentry_set_minmax_time(TIMEENTRY(timebar
->end_timeentry
),
302 end_min_time
.tv_nsec
,
303 timebar
->max_time
.tv_sec
,
304 timebar
->max_time
.tv_nsec
);
305 timeentry_set_minmax_time(TIMEENTRY(timebar
->current_timeentry
),
306 timebar
->min_time
.tv_sec
,
307 timebar
->min_time
.tv_nsec
,
308 timebar
->max_time
.tv_sec
,
309 timebar
->max_time
.tv_nsec
);
312 timeentry_set_minmax_time(TIMEENTRY(timebar
->interval_timeentry
),
315 new_interval_length
.tv_sec
,
316 new_interval_length
.tv_nsec
);
319 LttTime
timebar_get_start_time(Timebar
*timebar
)
321 return timeentry_get_ltt_time(TIMEENTRY(timebar
->start_timeentry
));
324 LttTime
timebar_get_end_time(Timebar
*timebar
)
326 return timeentry_get_ltt_time(TIMEENTRY(timebar
->end_timeentry
));
329 LttTime
timebar_get_current_time(Timebar
*timebar
)
331 return timeentry_get_ltt_time(TIMEENTRY(timebar
->current_timeentry
));
334 static void update_interval(Timebar
*timebar
)
336 LttTime start_time
= timeentry_get_ltt_time(TIMEENTRY(timebar
->start_timeentry
));
337 LttTime end_time
= timeentry_get_ltt_time(TIMEENTRY(timebar
->end_timeentry
));
338 LttTime new_interval
;
340 /* Compute max interval */
341 new_interval
= ltt_time_sub(end_time
,
344 /* Don't trigger the signal when we update the interval */
345 g_signal_handler_block(timebar
->interval_timeentry
,
346 timebar
->interval_handler_id
);
348 timeentry_set_time(TIMEENTRY(timebar
->interval_timeentry
),
350 new_interval
.tv_nsec
);
352 g_signal_handler_unblock(timebar
->interval_timeentry
,
353 timebar
->interval_handler_id
);
356 static void on_start_time_value_changed(Timeentry
*timeentry
,
359 Timebar
*timebar
= (Timebar
*)user_data
;
361 update_interval(timebar
);
363 g_signal_emit(timebar
,
364 timebar_signals
[SIGNAL_START_TIME_CHANGED
], 0);
367 static void on_end_time_value_changed(Timeentry
*timeentry
,
370 Timebar
*timebar
= (Timebar
*)user_data
;
372 update_interval(timebar
);
374 g_signal_emit(timebar
,
375 timebar_signals
[SIGNAL_END_TIME_CHANGED
], 0);
378 static void on_interval_time_value_changed (Timeentry
*timeentry
,
381 Timebar
*timebar
= (Timebar
*)user_data
;
383 LttTime new_interval
= timeentry_get_ltt_time(TIMEENTRY(timebar
->interval_timeentry
));
385 LttTime start_time
= timebar_get_start_time(timebar
);
387 LttTime new_end_time
;
389 gboolean need_interval_update
= FALSE
;
391 /* Lock the start and change the end */
392 new_end_time
= ltt_time_add(start_time
, new_interval
);
394 /* We cannot push further the max end */
395 if (ltt_time_compare(new_end_time
, timebar
->max_time
) > 0) {
396 /* Set the end to the max and pull on the start */
397 new_end_time
= timebar
->max_time
;
398 LttTime new_start_time
= ltt_time_sub(new_end_time
, new_interval
);
400 /* We cannot pull before the min start */
401 if (ltt_time_compare(new_start_time
, timebar
->min_time
) < 0) {
402 /* Set the interval to the max */
403 new_start_time
= timebar
->min_time
;
404 need_interval_update
= TRUE
;
406 timebar_set_start_time(timebar
, &new_start_time
);
408 timebar_set_end_time(timebar
, &new_end_time
);
410 if (need_interval_update
) {
411 update_interval(timebar
);
415 static void on_current_time_value_changed(Timeentry
*timeentry
,
418 Timebar
*timebar
= (Timebar
*)user_data
;
420 g_signal_emit(timebar
,
421 timebar_signals
[SIGNAL_CURRENT_TIME_CHANGED
], 0);