Commit | Line | Data |
---|---|---|
4172f013 YB |
1 | /* This file is part of the Linux Trace Toolkit viewer |
2 | * Copyright (C) 2010 Yannick Brosseau | |
3 | * | |
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; | |
7 | * | |
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. | |
12 | * | |
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, | |
16 | * MA 02111-1307, USA. | |
17 | */ | |
18 | #include "timebar.h" | |
19 | ||
20 | #include "timeentry.h" | |
21 | ||
22 | #include <gtk/gtkeventbox.h> | |
23 | #include <gtk/gtkvseparator.h> | |
24 | #include <ltt/time.h> | |
25 | ||
26 | enum { | |
27 | SIGNAL_START_TIME_CHANGED, | |
28 | SIGNAL_END_TIME_CHANGED, | |
29 | SIGNAL_CURRENT_TIME_CHANGED, | |
30 | LAST_SIGNAL | |
31 | }; | |
32 | ||
33 | static void timebar_class_init(TimebarClass *klass); | |
34 | static void timebar_init(Timebar *ttt); | |
35 | ||
36 | static guint timebar_signals[LAST_SIGNAL] = { 0 }; | |
37 | ||
38 | static void on_start_time_value_changed(Timeentry *spinbutton, | |
39 | gpointer user_data); | |
40 | static void on_end_time_value_changed(Timeentry *spinbutton, | |
41 | gpointer user_data); | |
42 | static void on_interval_time_value_changed(Timeentry *spinbutton, | |
43 | gpointer user_data); | |
44 | static void on_current_time_value_changed(Timeentry *spinbutton, | |
45 | gpointer user_data); | |
46 | ||
47 | static void update_interval(Timebar *timebar); | |
48 | ||
49 | static inline LttTime timeentry_get_ltt_time(Timeentry *timeentry) | |
50 | { | |
51 | LttTime time; | |
52 | ||
53 | timeentry_get_time(timeentry, | |
54 | &time.tv_sec, | |
55 | &time.tv_nsec); | |
56 | return time; | |
57 | } | |
58 | ||
59 | GType timebar_get_type(void) | |
60 | { | |
61 | static GType tb_type = 0; | |
62 | ||
63 | if (!tb_type) { | |
64 | const GTypeInfo tb_info = | |
65 | { | |
66 | sizeof (TimebarClass), | |
67 | NULL, /* base_init */ | |
68 | NULL, /* base_finalize */ | |
69 | (GClassInitFunc) timebar_class_init, | |
70 | NULL, /* class_finalize */ | |
71 | NULL, /* class_data */ | |
72 | sizeof (Timebar), | |
73 | 0, /* n_preallocs */ | |
74 | (GInstanceInitFunc) timebar_init, | |
75 | }; | |
76 | ||
77 | tb_type = g_type_register_static(GTK_TYPE_HBOX, | |
78 | "Timebar", | |
79 | &tb_info, | |
80 | 0); | |
81 | } | |
82 | ||
83 | return tb_type; | |
84 | } | |
85 | ||
86 | ||
87 | static void timebar_class_init(TimebarClass *klass) | |
88 | { | |
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), | |
93 | NULL, | |
94 | NULL, | |
95 | g_cclosure_marshal_VOID__VOID, | |
96 | G_TYPE_NONE, 0); | |
97 | ||
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), | |
102 | NULL, | |
103 | NULL, | |
104 | g_cclosure_marshal_VOID__VOID, | |
105 | G_TYPE_NONE, 0); | |
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), | |
110 | NULL, | |
111 | NULL, | |
112 | g_cclosure_marshal_VOID__VOID, | |
113 | G_TYPE_NONE, 0); | |
114 | } | |
115 | ||
116 | ||
117 | static void timebar_init(Timebar *timebar) | |
118 | { | |
119 | /* Title label */ | |
120 | timebar->title_eventbox = gtk_event_box_new(); | |
121 | gtk_widget_show(timebar->title_eventbox); | |
122 | ||
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); | |
126 | ||
127 | /* Start time entry */ | |
128 | timebar->start_timeentry = timeentry_new("Start: "); | |
129 | gtk_widget_show(timebar->start_timeentry); | |
130 | ||
131 | /* End time entry */ | |
132 | timebar->end_timeentry = timeentry_new("End: "); | |
133 | gtk_widget_show(timebar->end_timeentry); | |
134 | ||
135 | /* Interval time entry */ | |
136 | timebar->interval_timeentry = timeentry_new("Time Interval: "); | |
137 | gtk_widget_show(timebar->interval_timeentry); | |
138 | ||
139 | /* Current time entry */ | |
140 | timebar->current_timeentry = timeentry_new("Current Time: "); | |
141 | gtk_widget_show(timebar->current_timeentry); | |
142 | ||
143 | /* Pack all the widget in the timebar box */ | |
144 | GtkWidget *temp_widget; | |
145 | ||
146 | gtk_box_pack_start (GTK_BOX(timebar), timebar->title_eventbox, FALSE, FALSE, 2); | |
147 | ||
148 | gtk_box_pack_start (GTK_BOX(timebar), timebar->start_timeentry, FALSE, FALSE, 0); | |
149 | ||
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); | |
153 | ||
154 | gtk_box_pack_start (GTK_BOX(timebar), timebar->end_timeentry, FALSE, FALSE, 0); | |
155 | ||
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); | |
159 | ||
160 | gtk_box_pack_start (GTK_BOX(timebar), timebar->interval_timeentry, FALSE, FALSE, 0); | |
161 | ||
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); | |
166 | ||
167 | /* Set an initial time */ | |
168 | timebar_set_minmax_time(timebar, <t_time_zero, <t_time_one); | |
169 | ||
170 | /* Connect signals */ | |
171 | g_signal_connect ((gpointer) timebar->start_timeentry, "time-changed", | |
172 | G_CALLBACK(on_start_time_value_changed), | |
173 | timebar); | |
174 | g_signal_connect ((gpointer) timebar->end_timeentry, "time-changed", | |
175 | G_CALLBACK(on_end_time_value_changed), | |
176 | timebar); | |
177 | timebar->interval_handler_id = | |
178 | g_signal_connect ((gpointer) timebar->interval_timeentry, "time-changed", | |
179 | G_CALLBACK (on_interval_time_value_changed), | |
180 | timebar); | |
181 | g_signal_connect ((gpointer) timebar->current_timeentry, "time-changed", | |
182 | G_CALLBACK(on_current_time_value_changed), | |
183 | timebar); | |
184 | } | |
185 | ||
186 | GtkWidget *timebar_new(void) | |
187 | { | |
188 | return GTK_WIDGET(g_object_new (TIMEBAR_TYPE, NULL)); | |
189 | } | |
190 | ||
191 | void timebar_set_current_time(Timebar *timebar, const LttTime* time) | |
192 | { | |
193 | if (time == NULL) { | |
194 | return; | |
195 | } | |
196 | ||
197 | timeentry_set_time(TIMEENTRY(timebar->current_timeentry), | |
198 | time->tv_sec, | |
199 | time->tv_nsec); | |
200 | } | |
201 | ||
202 | void timebar_set_start_time(Timebar *timebar, const LttTime* time) | |
203 | { | |
204 | if (time == NULL) { | |
205 | return; | |
206 | } | |
207 | ||
208 | timeentry_set_time(TIMEENTRY(timebar->start_timeentry), | |
209 | time->tv_sec, | |
210 | time->tv_nsec); | |
211 | ||
212 | update_interval(timebar); | |
213 | } | |
214 | ||
215 | void timebar_set_end_time(Timebar *timebar, const LttTime* time) | |
216 | { | |
217 | if (time == NULL) { | |
218 | return; | |
219 | } | |
220 | ||
221 | timeentry_set_time(TIMEENTRY(timebar->end_timeentry), | |
222 | time->tv_sec, | |
223 | time->tv_nsec); | |
224 | update_interval(timebar); | |
225 | } | |
226 | ||
227 | void timebar_set_minmax_time(Timebar *timebar, | |
228 | const LttTime *min_time, | |
229 | const LttTime *max_time) | |
230 | { | |
231 | LttTime new_interval_length; | |
232 | LttTime start_max_time; | |
233 | LttTime end_min_time; | |
234 | ||
235 | /* Need to set both min_time and max_time */ | |
236 | if (min_time == NULL || max_time == NULL) { | |
237 | return; | |
238 | } | |
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 | |
242 | ) { | |
243 | return; | |
244 | } | |
245 | ||
246 | if (min_time != NULL) { | |
247 | timebar->min_time = *min_time; | |
248 | } | |
249 | ||
250 | if (max_time != NULL) { | |
251 | timebar->max_time = *max_time; | |
252 | } | |
253 | ||
254 | ||
255 | if (ltt_time_compare(timebar->min_time, timebar->max_time) == 0) { | |
256 | ||
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; | |
261 | ||
262 | start_max_time.tv_sec = timebar->max_time.tv_sec; | |
263 | start_max_time.tv_nsec = timebar->max_time.tv_nsec; | |
264 | ||
265 | end_min_time.tv_sec = timebar->min_time.tv_sec; | |
266 | end_min_time.tv_nsec = timebar->min_time.tv_nsec; | |
267 | ||
268 | } else { | |
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; | |
274 | } else { | |
275 | start_max_time.tv_sec = timebar->max_time.tv_sec; | |
276 | start_max_time.tv_nsec = timebar->max_time.tv_nsec - 1; | |
277 | } | |
278 | ||
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; | |
283 | } else { | |
284 | end_min_time.tv_sec = timebar->min_time.tv_sec; | |
285 | end_min_time.tv_nsec = timebar->min_time.tv_nsec + 1; | |
286 | } | |
287 | ||
288 | /* Compute max interval */ | |
289 | new_interval_length = ltt_time_sub(timebar->max_time, | |
290 | timebar->min_time); | |
291 | } | |
292 | ||
293 | ||
294 | /* Update widgets */ | |
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), | |
301 | end_min_time.tv_sec, | |
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); | |
310 | ||
311 | ||
312 | timeentry_set_minmax_time(TIMEENTRY(timebar->interval_timeentry), | |
313 | 0, | |
314 | 1, | |
315 | new_interval_length.tv_sec, | |
316 | new_interval_length.tv_nsec); | |
317 | } | |
318 | ||
319 | LttTime timebar_get_start_time(Timebar *timebar) | |
320 | { | |
321 | return timeentry_get_ltt_time(TIMEENTRY(timebar->start_timeentry)); | |
322 | } | |
323 | ||
324 | LttTime timebar_get_end_time(Timebar *timebar) | |
325 | { | |
326 | return timeentry_get_ltt_time(TIMEENTRY(timebar->end_timeentry)); | |
327 | } | |
328 | ||
329 | LttTime timebar_get_current_time(Timebar *timebar) | |
330 | { | |
331 | return timeentry_get_ltt_time(TIMEENTRY(timebar->current_timeentry)); | |
332 | } | |
333 | ||
334 | static void update_interval(Timebar *timebar) | |
335 | { | |
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; | |
339 | ||
340 | /* Compute max interval */ | |
341 | new_interval = ltt_time_sub(end_time, | |
342 | start_time); | |
343 | ||
344 | /* Don't trigger the signal when we update the interval */ | |
345 | g_signal_handler_block(timebar->interval_timeentry, | |
346 | timebar->interval_handler_id); | |
347 | ||
348 | timeentry_set_time(TIMEENTRY(timebar->interval_timeentry), | |
349 | new_interval.tv_sec, | |
350 | new_interval.tv_nsec); | |
351 | ||
352 | g_signal_handler_unblock(timebar->interval_timeentry, | |
353 | timebar->interval_handler_id); | |
354 | } | |
355 | ||
356 | static void on_start_time_value_changed(Timeentry *timeentry, | |
357 | gpointer user_data) | |
358 | { | |
359 | Timebar *timebar = (Timebar *)user_data; | |
360 | ||
361 | update_interval(timebar); | |
362 | ||
363 | g_signal_emit(timebar, | |
364 | timebar_signals[SIGNAL_START_TIME_CHANGED], 0); | |
365 | } | |
366 | ||
367 | static void on_end_time_value_changed(Timeentry *timeentry, | |
368 | gpointer user_data) | |
369 | { | |
370 | Timebar *timebar = (Timebar *)user_data; | |
371 | ||
372 | update_interval(timebar); | |
373 | ||
374 | g_signal_emit(timebar, | |
375 | timebar_signals[SIGNAL_END_TIME_CHANGED], 0); | |
376 | } | |
377 | ||
378 | static void on_interval_time_value_changed (Timeentry *timeentry, | |
379 | gpointer user_data) | |
380 | { | |
381 | Timebar *timebar = (Timebar *)user_data; | |
382 | ||
383 | LttTime new_interval = timeentry_get_ltt_time(TIMEENTRY(timebar->interval_timeentry)); | |
384 | ||
385 | LttTime start_time = timebar_get_start_time(timebar); | |
386 | ||
387 | LttTime new_end_time; | |
388 | ||
389 | gboolean need_interval_update = FALSE; | |
390 | ||
391 | /* Lock the start and change the end */ | |
392 | new_end_time = ltt_time_add(start_time, new_interval); | |
393 | ||
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); | |
399 | ||
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; | |
405 | } | |
406 | timebar_set_start_time(timebar, &new_start_time); | |
407 | } | |
408 | timebar_set_end_time(timebar, &new_end_time); | |
409 | ||
410 | if (need_interval_update) { | |
411 | update_interval(timebar); | |
412 | } | |
413 | } | |
414 | ||
415 | static void on_current_time_value_changed(Timeentry *timeentry, | |
416 | gpointer user_data) | |
417 | { | |
418 | Timebar *timebar = (Timebar *)user_data; | |
419 | ||
420 | g_signal_emit(timebar, | |
421 | timebar_signals[SIGNAL_CURRENT_TIME_CHANGED], 0); | |
422 | } | |
423 | ||
424 |