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
245 /* null-checked already */
246 timebar
->min_time
= *min_time
;
247 timebar
->max_time
= *max_time
;
249 if (ltt_time_compare(timebar
->min_time
, timebar
->max_time
) == 0) {
251 /* If the min and max are equal set the same values, which will
252 disable all the widgets of the timebar */
253 new_interval_length
.tv_sec
= 0;
254 new_interval_length
.tv_nsec
= 1;
256 start_max_time
.tv_sec
= timebar
->max_time
.tv_sec
;
257 start_max_time
.tv_nsec
= timebar
->max_time
.tv_nsec
;
259 end_min_time
.tv_sec
= timebar
->min_time
.tv_sec
;
260 end_min_time
.tv_nsec
= timebar
->min_time
.tv_nsec
;
263 /* Special minmax (to keep a minimum interval of 1 nsec */
264 /* start max time is max minus 1 nsec */
265 if (timebar
->max_time
.tv_nsec
== 0) {
266 start_max_time
.tv_sec
= timebar
->max_time
.tv_sec
- 1;
267 start_max_time
.tv_nsec
= NANOSECONDS_PER_SECOND
- 1;
269 start_max_time
.tv_sec
= timebar
->max_time
.tv_sec
;
270 start_max_time
.tv_nsec
= timebar
->max_time
.tv_nsec
- 1;
273 /* end min time is min plus 1 nsec */
274 if (timebar
->min_time
.tv_nsec
+ 1 == NANOSECONDS_PER_SECOND
) {
275 end_min_time
.tv_sec
= timebar
->min_time
.tv_sec
+ 1;
276 end_min_time
.tv_nsec
= 0;
278 end_min_time
.tv_sec
= timebar
->min_time
.tv_sec
;
279 end_min_time
.tv_nsec
= timebar
->min_time
.tv_nsec
+ 1;
282 /* Compute max interval */
283 new_interval_length
= ltt_time_sub(timebar
->max_time
,
289 timeentry_set_minmax_time(TIMEENTRY(timebar
->start_timeentry
),
290 timebar
->min_time
.tv_sec
,
291 timebar
->min_time
.tv_nsec
,
292 start_max_time
.tv_sec
,
293 start_max_time
.tv_nsec
);
294 timeentry_set_minmax_time(TIMEENTRY(timebar
->end_timeentry
),
296 end_min_time
.tv_nsec
,
297 timebar
->max_time
.tv_sec
,
298 timebar
->max_time
.tv_nsec
);
299 timeentry_set_minmax_time(TIMEENTRY(timebar
->current_timeentry
),
300 timebar
->min_time
.tv_sec
,
301 timebar
->min_time
.tv_nsec
,
302 timebar
->max_time
.tv_sec
,
303 timebar
->max_time
.tv_nsec
);
306 timeentry_set_minmax_time(TIMEENTRY(timebar
->interval_timeentry
),
309 new_interval_length
.tv_sec
,
310 new_interval_length
.tv_nsec
);
313 LttTime
timebar_get_start_time(Timebar
*timebar
)
315 return timeentry_get_ltt_time(TIMEENTRY(timebar
->start_timeentry
));
318 LttTime
timebar_get_end_time(Timebar
*timebar
)
320 return timeentry_get_ltt_time(TIMEENTRY(timebar
->end_timeentry
));
323 LttTime
timebar_get_current_time(Timebar
*timebar
)
325 return timeentry_get_ltt_time(TIMEENTRY(timebar
->current_timeentry
));
328 static void update_interval(Timebar
*timebar
)
330 LttTime start_time
= timeentry_get_ltt_time(TIMEENTRY(timebar
->start_timeentry
));
331 LttTime end_time
= timeentry_get_ltt_time(TIMEENTRY(timebar
->end_timeentry
));
332 LttTime new_interval
;
334 /* Compute max interval */
335 new_interval
= ltt_time_sub(end_time
,
338 /* Don't trigger the signal when we update the interval */
339 g_signal_handler_block(timebar
->interval_timeentry
,
340 timebar
->interval_handler_id
);
342 timeentry_set_time(TIMEENTRY(timebar
->interval_timeentry
),
344 new_interval
.tv_nsec
);
346 g_signal_handler_unblock(timebar
->interval_timeentry
,
347 timebar
->interval_handler_id
);
350 static void on_start_time_value_changed(Timeentry
*timeentry
,
353 Timebar
*timebar
= (Timebar
*)user_data
;
355 update_interval(timebar
);
357 g_signal_emit(timebar
,
358 timebar_signals
[SIGNAL_START_TIME_CHANGED
], 0);
361 static void on_end_time_value_changed(Timeentry
*timeentry
,
364 Timebar
*timebar
= (Timebar
*)user_data
;
366 update_interval(timebar
);
368 g_signal_emit(timebar
,
369 timebar_signals
[SIGNAL_END_TIME_CHANGED
], 0);
372 static void on_interval_time_value_changed (Timeentry
*timeentry
,
375 Timebar
*timebar
= (Timebar
*)user_data
;
377 LttTime new_interval
= timeentry_get_ltt_time(TIMEENTRY(timebar
->interval_timeentry
));
379 LttTime start_time
= timebar_get_start_time(timebar
);
381 LttTime new_end_time
;
383 gboolean need_interval_update
= FALSE
;
385 /* Lock the start and change the end */
386 new_end_time
= ltt_time_add(start_time
, new_interval
);
388 /* We cannot push further the max end */
389 if (ltt_time_compare(new_end_time
, timebar
->max_time
) > 0) {
390 /* Set the end to the max and pull on the start */
391 new_end_time
= timebar
->max_time
;
392 LttTime new_start_time
= ltt_time_sub(new_end_time
, new_interval
);
394 /* We cannot pull before the min start */
395 if (ltt_time_compare(new_start_time
, timebar
->min_time
) < 0) {
396 /* Set the interval to the max */
397 new_start_time
= timebar
->min_time
;
398 need_interval_update
= TRUE
;
400 timebar_set_start_time(timebar
, &new_start_time
);
402 timebar_set_end_time(timebar
, &new_end_time
);
404 if (need_interval_update
) {
405 update_interval(timebar
);
409 static void on_current_time_value_changed(Timeentry
*timeentry
,
412 Timebar
*timebar
= (Timebar
*)user_data
;
414 g_signal_emit(timebar
,
415 timebar_signals
[SIGNAL_CURRENT_TIME_CHANGED
], 0);