continue work on resourceview
[lttv.git] / ltt / branches / poly / lttv / modules / gui / resourceview / eventhooks.c
CommitLineData
9e01e6d4 1/* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2003-2004 Mathieu Desnoyers
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
19
20/*****************************************************************************
21 * Hooks to be called by the main window *
22 *****************************************************************************/
23
24
25/* Event hooks are the drawing hooks called during traceset read. They draw the
26 * icons, text, lines and background color corresponding to the events read.
27 *
28 * Two hooks are used for drawing : before_schedchange and after_schedchange hooks. The
29 * before_schedchange is called before the state update that occurs with an event and
30 * the after_schedchange hook is called after this state update.
31 *
32 * The before_schedchange hooks fulfill the task of drawing the visible objects that
33 * corresponds to the data accumulated by the after_schedchange hook.
34 *
35 * The after_schedchange hook accumulates the data that need to be shown on the screen
36 * (items) into a queue. Then, the next before_schedchange hook will draw what that
37 * queue contains. That's the Right Way (TM) of drawing items on the screen,
38 * because we need to draw the background first (and then add icons, text, ...
39 * over it), but we only know the length of a background region once the state
40 * corresponding to it is over, which happens to be at the next before_schedchange
41 * hook.
42 *
43 * We also have a hook called at the end of a chunk to draw the information left
44 * undrawn in each process queue. We use the current time as end of
45 * line/background.
46 */
47
48#ifdef HAVE_CONFIG_H
49#include <config.h>
50#endif
51
52//#define PANGO_ENABLE_BACKEND
53#include <gtk/gtk.h>
54#include <gdk/gdk.h>
55#include <glib.h>
56#include <assert.h>
57#include <string.h>
58#include <stdio.h>
59
60//#include <pango/pango.h>
61
62#include <ltt/event.h>
63#include <ltt/time.h>
64#include <ltt/type.h>
65#include <ltt/trace.h>
66
67#include <lttv/lttv.h>
68#include <lttv/hook.h>
69#include <lttv/state.h>
70#include <lttvwindow/lttvwindow.h>
71#include <lttvwindow/lttvwindowtraces.h>
72#include <lttvwindow/support.h>
73
74
75#include "eventhooks.h"
76#include "cfv.h"
77#include "processlist.h"
78#include "drawing.h"
79
80
81#define MAX_PATH_LEN 256
82#define STATE_LINE_WIDTH 4
83#define COLLISION_POSITION(height) (((height - STATE_LINE_WIDTH)/2) -3)
84
85extern GSList *g_legend_list;
86
87
88/* Action to do when background computation completed.
89 *
90 * Wait for all the awaited computations to be over.
91 */
92
93static gint background_ready(void *hook_data, void *call_data)
94{
95 ControlFlowData *control_flow_data = (ControlFlowData *)hook_data;
96 LttvTrace *trace = (LttvTrace*)call_data;
97
98 control_flow_data->background_info_waiting--;
99
100 if(control_flow_data->background_info_waiting == 0) {
101 g_message("control flow viewer : background computation data ready.");
102
103 drawing_clear(control_flow_data->drawing);
104 processlist_clear(control_flow_data->process_list);
105 gtk_widget_set_size_request(
106 control_flow_data->drawing->drawing_area,
107 -1, processlist_get_height(control_flow_data->process_list));
108 redraw_notify(control_flow_data, NULL);
109 }
110
111 return 0;
112}
113
114
115/* Request background computation. Verify if it is in progress or ready first.
116 * Only for each trace in the tab's traceset.
117 */
118static void request_background_data(ControlFlowData *control_flow_data)
119{
120 LttvTracesetContext * tsc =
121 lttvwindow_get_traceset_context(control_flow_data->tab);
122 gint num_traces = lttv_traceset_number(tsc->ts);
123 gint i;
124 LttvTrace *trace;
125 LttvTraceState *tstate;
126
127 LttvHooks *background_ready_hook =
128 lttv_hooks_new();
129 lttv_hooks_add(background_ready_hook, background_ready, control_flow_data,
130 LTTV_PRIO_DEFAULT);
131 control_flow_data->background_info_waiting = 0;
132
133 for(i=0;i<num_traces;i++) {
134 trace = lttv_traceset_get(tsc->ts, i);
135 tstate = LTTV_TRACE_STATE(tsc->traces[i]);
136
137 if(lttvwindowtraces_get_ready(g_quark_from_string("state"),trace)==FALSE
138 && !tstate->has_precomputed_states) {
139
140 if(lttvwindowtraces_get_in_progress(g_quark_from_string("state"),
141 trace) == FALSE) {
142 /* We first remove requests that could have been done for the same
143 * information. Happens when two viewers ask for it before servicing
144 * starts.
145 */
146 if(!lttvwindowtraces_background_request_find(trace, "state"))
147 lttvwindowtraces_background_request_queue(
148 main_window_get_widget(control_flow_data->tab), trace, "state");
149 lttvwindowtraces_background_notify_queue(control_flow_data,
150 trace,
151 ltt_time_infinite,
152 NULL,
153 background_ready_hook);
154 control_flow_data->background_info_waiting++;
155 } else { /* in progress */
156
157 lttvwindowtraces_background_notify_current(control_flow_data,
158 trace,
159 ltt_time_infinite,
160 NULL,
161 background_ready_hook);
162 control_flow_data->background_info_waiting++;
163 }
164 } else {
165 /* Data ready. By its nature, this viewer doesn't need to have
166 * its data ready hook called there, because a background
167 * request is always linked with a redraw.
168 */
169 }
170
171 }
172
173 lttv_hooks_destroy(background_ready_hook);
174}
175
176
177
178
179/**
180 * Event Viewer's constructor hook
181 *
182 * This constructor is given as a parameter to the menuitem and toolbar button
183 * registration. It creates the list.
184 * @param tab A pointer to the parent tab.
185 * @return The widget created.
186 */
187GtkWidget *
188h_guicontrolflow(LttvPlugin *plugin)
189{
190 LttvPluginTab *ptab = LTTV_PLUGIN_TAB(plugin);
191 Tab *tab = ptab->tab;
192 g_info("h_guicontrolflow, %p", tab);
193 ControlFlowData *control_flow_data = guicontrolflow(ptab);
194
195 control_flow_data->tab = tab;
196
197 // Unreg done in the GuiControlFlow_Destructor
198 lttvwindow_register_traceset_notify(tab,
199 traceset_notify,
200 control_flow_data);
201
202 lttvwindow_register_time_window_notify(tab,
203 update_time_window_hook,
204 control_flow_data);
205 lttvwindow_register_current_time_notify(tab,
206 update_current_time_hook,
207 control_flow_data);
208 lttvwindow_register_redraw_notify(tab,
209 redraw_notify,
210 control_flow_data);
211 lttvwindow_register_continue_notify(tab,
212 continue_notify,
213 control_flow_data);
214 request_background_data(control_flow_data);
215
216
217 return guicontrolflow_get_widget(control_flow_data) ;
218
219}
220
221void legend_destructor(GtkWindow *legend)
222{
223 g_legend_list = g_slist_remove(g_legend_list, legend);
224}
225
226/* Create a popup legend */
227GtkWidget *
228h_legend(LttvPlugin *plugin)
229{
230 LttvPluginTab *ptab = LTTV_PLUGIN_TAB(plugin);
231 Tab *tab = ptab->tab;
232 g_info("h_legend, %p", tab);
233
234 GtkWindow *legend = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL));
235
236 g_legend_list = g_slist_append(
237 g_legend_list,
238 legend);
239
240 g_object_set_data_full(
241 G_OBJECT(legend),
242 "legend",
243 legend,
244 (GDestroyNotify)legend_destructor);
245
246 gtk_window_set_title(legend, "Control Flow View Legend");
247
248 GtkWidget *pixmap = create_pixmap(GTK_WIDGET(legend), "lttv-color-list.png");
249
250 // GtkImage *image = GTK_IMAGE(gtk_image_new_from_pixmap(
251 // GDK_PIXMAP(pixmap), NULL));
252
253 gtk_container_add(GTK_CONTAINER(legend), GTK_WIDGET(pixmap));
254
255 gtk_widget_show(GTK_WIDGET(pixmap));
256 gtk_widget_show(GTK_WIDGET(legend));
257
258
259 return NULL; /* This is a popup window */
260}
261
262
263int event_selected_hook(void *hook_data, void *call_data)
264{
265 ControlFlowData *control_flow_data = (ControlFlowData*) hook_data;
266 guint *event_number = (guint*) call_data;
267
268 g_debug("DEBUG : event selected by main window : %u", *event_number);
269
270 return 0;
271}
272
273/* Function that selects the color of status&exemode line */
274static inline PropertiesLine prepare_s_e_line(LttvProcessState *process)
275{
276 PropertiesLine prop_line;
277 prop_line.line_width = STATE_LINE_WIDTH;
278 prop_line.style = GDK_LINE_SOLID;
279 prop_line.y = MIDDLE;
280 //GdkColormap *colormap = gdk_colormap_get_system();
281
282 if(process->state->s == LTTV_STATE_RUN) {
283 if(process->state->t == LTTV_STATE_USER_MODE)
284 prop_line.color = drawing_colors[COL_RUN_USER_MODE];
285 else if(process->state->t == LTTV_STATE_SYSCALL)
286 prop_line.color = drawing_colors[COL_RUN_SYSCALL];
287 else if(process->state->t == LTTV_STATE_TRAP)
288 prop_line.color = drawing_colors[COL_RUN_TRAP];
289 else if(process->state->t == LTTV_STATE_IRQ)
290 prop_line.color = drawing_colors[COL_RUN_IRQ];
291 else if(process->state->t == LTTV_STATE_SOFT_IRQ)
292 prop_line.color = drawing_colors[COL_RUN_SOFT_IRQ];
293 else if(process->state->t == LTTV_STATE_MODE_UNKNOWN)
294 prop_line.color = drawing_colors[COL_MODE_UNKNOWN];
295 else
296 g_assert(FALSE); /* RUNNING MODE UNKNOWN */
297 } else if(process->state->s == LTTV_STATE_WAIT) {
298 /* We don't show if we wait while in user mode, trap, irq or syscall */
299 prop_line.color = drawing_colors[COL_WAIT];
300 } else if(process->state->s == LTTV_STATE_WAIT_CPU) {
301 /* We don't show if we wait for CPU while in user mode, trap, irq
302 * or syscall */
303 prop_line.color = drawing_colors[COL_WAIT_CPU];
304 } else if(process->state->s == LTTV_STATE_ZOMBIE) {
305 prop_line.color = drawing_colors[COL_ZOMBIE];
306 } else if(process->state->s == LTTV_STATE_WAIT_FORK) {
307 prop_line.color = drawing_colors[COL_WAIT_FORK];
308 } else if(process->state->s == LTTV_STATE_EXIT) {
309 prop_line.color = drawing_colors[COL_EXIT];
310 } else if(process->state->s == LTTV_STATE_UNNAMED) {
311 prop_line.color = drawing_colors[COL_UNNAMED];
312 } else {
313 g_critical("unknown state : %s", g_quark_to_string(process->state->s));
314 g_assert(FALSE); /* UNKNOWN STATE */
315 }
316
317 return prop_line;
318
319}
320
321
322/* before_schedchange_hook
323 *
324 * This function basically draw lines and icons. Two types of lines are drawn :
325 * one small (3 pixels?) representing the state of the process and the second
326 * type is thicker (10 pixels?) representing on which CPU a process is running
327 * (and this only in running state).
328 *
329 * Extremums of the lines :
330 * x_min : time of the last event context for this process kept in memory.
331 * x_max : time of the current event.
332 * y : middle of the process in the process list. The process is found in the
333 * list, therefore is it's position in pixels.
334 *
335 * The choice of lines'color is defined by the context of the last event for this
336 * process.
337 */
338
339
340int before_schedchange_hook(void *hook_data, void *call_data)
341{
342 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility*)hook_data;
343 EventsRequest *events_request = (EventsRequest*)thf->hook_data;
344 ControlFlowData *control_flow_data = events_request->viewer_data;
345
346 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
347
348 LttvTracefileState *tfs = (LttvTracefileState *)call_data;
349 LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
350
351 LttEvent *e;
352 e = ltt_tracefile_get_event(tfc->tf);
353 gint target_pid_saved = tfc->target_pid;
354
355 LttTime evtime = ltt_event_time(e);
356 LttvFilter *filter = control_flow_data->filter;
357
358 /* we are in a schedchange, before the state update. We must draw the
359 * items corresponding to the state before it changes : now is the right
360 * time to do it.
361 */
362
363 guint pid_out;
364 guint pid_in;
365 {
366 pid_out = ltt_event_get_long_unsigned(e, thf->f1);
367 pid_in = ltt_event_get_long_unsigned(e, thf->f2);
368 }
c4e6f4dc 369
370 g_debug("a");
9e01e6d4 371
372 tfc->target_pid = pid_out;
373 if(!filter || !filter->head ||
374 lttv_filter_tree_parse(filter->head,e,tfc->tf,
375 tfc->t_context->t,tfc,NULL,NULL)) {
376 /* For the pid_out */
377 /* First, check if the current process is in the state computation
378 * process list. If it is there, that means we must add it right now and
379 * draw items from the beginning of the read for it. If it is not
380 * present, it's a new process and it was not present : it will
381 * be added after the state update. */
382 guint cpu = tfs->cpu;
383 guint trace_num = ts->parent.index;
384 LttvProcessState *process = ts->running_process[cpu];
385 /* unknown state, bad current pid */
386 if(process->pid != pid_out)
387 process = lttv_state_find_process(ts,
388 tfs->cpu, pid_out);
389
390 if(process != NULL) {
391 /* Well, the process_out existed : we must get it in the process hash
392 * or add it, and draw its items.
393 */
394 /* Add process to process list (if not present) */
395 guint pl_height = 0;
396 HashedProcessData *hashed_process_data = NULL;
397 ProcessList *process_list = control_flow_data->process_list;
398 LttTime birth = process->creation_time;
399
400 hashed_process_data = processlist_get_process_data(process_list,
401 pid_out,
402 process->cpu,
403 &birth,
404 trace_num);
405 if(hashed_process_data == NULL)
406 {
407 g_assert(pid_out == 0 || pid_out != process->ppid);
408 /* Process not present */
409 ProcessInfo *process_info;
410 Drawing_t *drawing = control_flow_data->drawing;
c4e6f4dc 411 resourcelist_add(process_list,
9e01e6d4 412 drawing,
c4e6f4dc 413// pid_out,
414// process->tgid,
415// process->cpu,
416// process->ppid,
417// &birth,
418// trace_num,
9e01e6d4 419 process->name,
c4e6f4dc 420// process->brand,
9e01e6d4 421 &pl_height,
422 &process_info,
423 &hashed_process_data);
424 gtk_widget_set_size_request(drawing->drawing_area,
425 -1,
426 pl_height);
427 gtk_widget_queue_draw(drawing->drawing_area);
428
429 }
430
431 /* Now, the process is in the state hash and our own process hash.
432 * We definitely can draw the items related to the ending state.
433 */
434
435 if(ltt_time_compare(hashed_process_data->next_good_time,
436 evtime) > 0)
437 {
438 if(hashed_process_data->x.middle_marked == FALSE) {
439
440 TimeWindow time_window =
441 lttvwindow_get_time_window(control_flow_data->tab);
442#ifdef EXTRA_CHECK
443 if(ltt_time_compare(evtime, time_window.start_time) == -1
444 || ltt_time_compare(evtime, time_window.end_time) == 1)
445 return;
446#endif //EXTRA_CHECK
447 Drawing_t *drawing = control_flow_data->drawing;
448 guint width = drawing->width;
449 guint x;
450 convert_time_to_pixels(
451 time_window,
452 evtime,
453 width,
454 &x);
455
456 /* Draw collision indicator */
457 gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
458 gdk_draw_point(hashed_process_data->pixmap,
459 drawing->gc,
460 x,
461 COLLISION_POSITION(hashed_process_data->height));
462 hashed_process_data->x.middle_marked = TRUE;
463 }
464 } else {
465 TimeWindow time_window =
466 lttvwindow_get_time_window(control_flow_data->tab);
467#ifdef EXTRA_CHECK
468 if(ltt_time_compare(evtime, time_window.start_time) == -1
469 || ltt_time_compare(evtime, time_window.end_time) == 1)
470 return;
471#endif //EXTRA_CHECK
472 Drawing_t *drawing = control_flow_data->drawing;
473 guint width = drawing->width;
474 guint x;
475 convert_time_to_pixels(
476 time_window,
477 evtime,
478 width,
479 &x);
480
481
482 /* Jump over draw if we are at the same x position */
483 if(x == hashed_process_data->x.middle &&
484 hashed_process_data->x.middle_used)
485 {
486 if(hashed_process_data->x.middle_marked == FALSE) {
487 /* Draw collision indicator */
488 gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
489 gdk_draw_point(hashed_process_data->pixmap,
490 drawing->gc,
491 x,
492 COLLISION_POSITION(hashed_process_data->height));
493 hashed_process_data->x.middle_marked = TRUE;
494 }
495 /* jump */
496 } else {
497 DrawContext draw_context;
498
499 /* Now create the drawing context that will be used to draw
500 * items related to the last state. */
501 draw_context.drawable = hashed_process_data->pixmap;
502 draw_context.gc = drawing->gc;
503 draw_context.pango_layout = drawing->pango_layout;
504 draw_context.drawinfo.start.x = hashed_process_data->x.middle;
505 draw_context.drawinfo.end.x = x;
506
507 draw_context.drawinfo.y.over = 1;
508 draw_context.drawinfo.y.middle = (hashed_process_data->height/2);
509 draw_context.drawinfo.y.under = hashed_process_data->height;
510
511 draw_context.drawinfo.start.offset.over = 0;
512 draw_context.drawinfo.start.offset.middle = 0;
513 draw_context.drawinfo.start.offset.under = 0;
514 draw_context.drawinfo.end.offset.over = 0;
515 draw_context.drawinfo.end.offset.middle = 0;
516 draw_context.drawinfo.end.offset.under = 0;
517
518 {
519 /* Draw the line */
520 PropertiesLine prop_line = prepare_s_e_line(process);
521 draw_line((void*)&prop_line, (void*)&draw_context);
522
523 }
524 /* become the last x position */
525 hashed_process_data->x.middle = x;
526 hashed_process_data->x.middle_used = TRUE;
527 hashed_process_data->x.middle_marked = FALSE;
528
529 /* Calculate the next good time */
530 convert_pixels_to_time(width, x+1, time_window,
531 &hashed_process_data->next_good_time);
532 }
533 }
534 }
535 }
536
537 tfc->target_pid = pid_in;
538 if(!filter || !filter->head ||
539 lttv_filter_tree_parse(filter->head,e,tfc->tf,
540 tfc->t_context->t,tfc,NULL,NULL)) {
541 /* For the pid_in */
542 /* First, check if the current process is in the state computation
543 * process list. If it is there, that means we must add it right now and
544 * draw items from the beginning of the read for it. If it is not
545 * present, it's a new process and it was not present : it will
546 * be added after the state update. */
547 LttvProcessState *process;
548 process = lttv_state_find_process(ts,
549 tfs->cpu, pid_in);
550 guint trace_num = ts->parent.index;
551
552 if(process != NULL) {
553 /* Well, the process existed : we must get it in the process hash
554 * or add it, and draw its items.
555 */
556 /* Add process to process list (if not present) */
557 guint pl_height = 0;
558 HashedProcessData *hashed_process_data = NULL;
559 ProcessList *process_list = control_flow_data->process_list;
560 LttTime birth = process->creation_time;
561
562 hashed_process_data = processlist_get_process_data(process_list,
563 pid_in,
564 tfs->cpu,
565 &birth,
566 trace_num);
567 if(hashed_process_data == NULL)
568 {
569 g_assert(pid_in == 0 || pid_in != process->ppid);
570 /* Process not present */
571 ProcessInfo *process_info;
572 Drawing_t *drawing = control_flow_data->drawing;
573 processlist_add(process_list,
574 drawing,
575 pid_in,
576 process->tgid,
577 tfs->cpu,
578 process->ppid,
579 &birth,
580 trace_num,
581 process->name,
582 process->brand,
583 &pl_height,
584 &process_info,
585 &hashed_process_data);
586 gtk_widget_set_size_request(drawing->drawing_area,
587 -1,
588 pl_height);
589 gtk_widget_queue_draw(drawing->drawing_area);
590
591 }
592 //We could set the current process and hash here, but will be done
593 //by after schedchange hook
594
595 /* Now, the process is in the state hash and our own process hash.
596 * We definitely can draw the items related to the ending state.
597 */
598
599 if(ltt_time_compare(hashed_process_data->next_good_time,
600 evtime) > 0)
601 {
602 if(hashed_process_data->x.middle_marked == FALSE) {
603
604 TimeWindow time_window =
605 lttvwindow_get_time_window(control_flow_data->tab);
606#ifdef EXTRA_CHECK
607 if(ltt_time_compare(evtime, time_window.start_time) == -1
608 || ltt_time_compare(evtime, time_window.end_time) == 1)
609 return;
610#endif //EXTRA_CHECK
611 Drawing_t *drawing = control_flow_data->drawing;
612 guint width = drawing->width;
613 guint x;
614 convert_time_to_pixels(
615 time_window,
616 evtime,
617 width,
618 &x);
619
620 /* Draw collision indicator */
621 gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
622 gdk_draw_point(hashed_process_data->pixmap,
623 drawing->gc,
624 x,
625 COLLISION_POSITION(hashed_process_data->height));
626 hashed_process_data->x.middle_marked = TRUE;
627 }
628 } else {
629 TimeWindow time_window =
630 lttvwindow_get_time_window(control_flow_data->tab);
631#ifdef EXTRA_CHECK
632 if(ltt_time_compare(evtime, time_window.start_time) == -1
633 || ltt_time_compare(evtime, time_window.end_time) == 1)
634 return;
635#endif //EXTRA_CHECK
636 Drawing_t *drawing = control_flow_data->drawing;
637 guint width = drawing->width;
638 guint x;
639
640 convert_time_to_pixels(
641 time_window,
642 evtime,
643 width,
644 &x);
645
646
647 /* Jump over draw if we are at the same x position */
648 if(x == hashed_process_data->x.middle &&
649 hashed_process_data->x.middle_used)
650 {
651 if(hashed_process_data->x.middle_marked == FALSE) {
652 /* Draw collision indicator */
653 gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
654 gdk_draw_point(hashed_process_data->pixmap,
655 drawing->gc,
656 x,
657 COLLISION_POSITION(hashed_process_data->height));
658 hashed_process_data->x.middle_marked = TRUE;
659 }
660 /* jump */
661 } else {
662 DrawContext draw_context;
663
664 /* Now create the drawing context that will be used to draw
665 * items related to the last state. */
666 draw_context.drawable = hashed_process_data->pixmap;
667 draw_context.gc = drawing->gc;
668 draw_context.pango_layout = drawing->pango_layout;
669 draw_context.drawinfo.start.x = hashed_process_data->x.middle;
670 draw_context.drawinfo.end.x = x;
671
672 draw_context.drawinfo.y.over = 1;
673 draw_context.drawinfo.y.middle = (hashed_process_data->height/2);
674 draw_context.drawinfo.y.under = hashed_process_data->height;
675
676 draw_context.drawinfo.start.offset.over = 0;
677 draw_context.drawinfo.start.offset.middle = 0;
678 draw_context.drawinfo.start.offset.under = 0;
679 draw_context.drawinfo.end.offset.over = 0;
680 draw_context.drawinfo.end.offset.middle = 0;
681 draw_context.drawinfo.end.offset.under = 0;
682
683 {
684 /* Draw the line */
685 PropertiesLine prop_line = prepare_s_e_line(process);
686 draw_line((void*)&prop_line, (void*)&draw_context);
687 }
688
689
690 /* become the last x position */
691 hashed_process_data->x.middle = x;
692 hashed_process_data->x.middle_used = TRUE;
693 hashed_process_data->x.middle_marked = FALSE;
694
695 /* Calculate the next good time */
696 convert_pixels_to_time(width, x+1, time_window,
697 &hashed_process_data->next_good_time);
698 }
699 }
700 } else
701 g_warning("Cannot find pin_in in schedchange %u", pid_in);
702 }
703 tfc->target_pid = target_pid_saved;
704 return 0;
705
706
707
708
709 /* Text dump */
710#ifdef DONTSHOW
711 GString *string = g_string_new("");;
712 gboolean field_names = TRUE, state = TRUE;
713
714 lttv_event_to_string(e, tfc->tf, string, TRUE, field_names, tfs);
715 g_string_append_printf(string,"\n");
716
717 if(state) {
718 g_string_append_printf(string, " %s",
719 g_quark_to_string(tfs->process->state->s));
720 }
721
722 g_info("%s",string->str);
723
724 g_string_free(string, TRUE);
725
726 /* End of text dump */
727#endif //DONTSHOW
728
729}
730
731/* after_schedchange_hook
732 *
733 * The draw after hook is called by the reading API to have a
734 * particular event drawn on the screen.
735 * @param hook_data ControlFlowData structure of the viewer.
736 * @param call_data Event context.
737 *
738 * This function adds items to be drawn in a queue for each process.
739 *
740 */
741int after_schedchange_hook(void *hook_data, void *call_data)
742{
743 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility*)hook_data;
744 EventsRequest *events_request = (EventsRequest*)thf->hook_data;
745 ControlFlowData *control_flow_data = events_request->viewer_data;
746
747 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
748
749 LttvTracefileState *tfs = (LttvTracefileState *)call_data;
750
751 LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
752
753 LttEvent *e;
754 e = ltt_tracefile_get_event(tfc->tf);
755
756 LttvFilter *filter = control_flow_data->filter;
757 if(filter != NULL && filter->head != NULL)
758 if(!lttv_filter_tree_parse(filter->head,e,tfc->tf,
759 tfc->t_context->t,tfc,NULL,NULL))
760 return FALSE;
761
762 LttTime evtime = ltt_event_time(e);
763
764 /* Add process to process list (if not present) */
765 LttvProcessState *process_in;
766 LttTime birth;
767 guint pl_height = 0;
768 HashedProcessData *hashed_process_data_in = NULL;
769
770 ProcessList *process_list = control_flow_data->process_list;
771
772 guint pid_in;
773 {
774 guint pid_out;
775 pid_out = ltt_event_get_long_unsigned(e, thf->f1);
776 pid_in = ltt_event_get_long_unsigned(e, thf->f2);
777 }
778
779
780 /* Find process pid_in in the list... */
781 //process_in = lttv_state_find_process(ts, ANY_CPU, pid_in);
782 //process_in = tfs->process;
783 guint cpu = tfs->cpu;
784 guint trace_num = ts->parent.index;
785 process_in = ts->running_process[cpu];
786 /* It should exist, because we are after the state update. */
787#ifdef EXTRA_CHECK
788 g_assert(process_in != NULL);
789#endif //EXTRA_CHECK
790 birth = process_in->creation_time;
791
792 hashed_process_data_in = processlist_get_process_data(process_list,
793 pid_in,
794 process_in->cpu,
795 &birth,
796 trace_num);
797 if(hashed_process_data_in == NULL)
798 {
799 g_assert(pid_in == 0 || pid_in != process_in->ppid);
800 ProcessInfo *process_info;
801 Drawing_t *drawing = control_flow_data->drawing;
802 /* Process not present */
803 processlist_add(process_list,
804 drawing,
805 pid_in,
806 process_in->tgid,
807 process_in->cpu,
808 process_in->ppid,
809 &birth,
810 trace_num,
811 process_in->name,
812 process_in->brand,
813 &pl_height,
814 &process_info,
815 &hashed_process_data_in);
816 gtk_widget_set_size_request(drawing->drawing_area,
817 -1,
818 pl_height);
819 gtk_widget_queue_draw(drawing->drawing_area);
820 }
821 /* Set the current process */
822 process_list->current_hash_data[trace_num][process_in->cpu] =
823 hashed_process_data_in;
824
825 if(ltt_time_compare(hashed_process_data_in->next_good_time,
826 evtime) <= 0)
827 {
828 TimeWindow time_window =
829 lttvwindow_get_time_window(control_flow_data->tab);
830
831#ifdef EXTRA_CHECK
832 if(ltt_time_compare(evtime, time_window.start_time) == -1
833 || ltt_time_compare(evtime, time_window.end_time) == 1)
834 return;
835#endif //EXTRA_CHECK
836 Drawing_t *drawing = control_flow_data->drawing;
837 guint width = drawing->width;
838 guint new_x;
839
840 convert_time_to_pixels(
841 time_window,
842 evtime,
843 width,
844 &new_x);
845
846 if(hashed_process_data_in->x.middle != new_x) {
847 hashed_process_data_in->x.middle = new_x;
848 hashed_process_data_in->x.middle_used = FALSE;
849 hashed_process_data_in->x.middle_marked = FALSE;
850 }
851 }
852 return 0;
853}
854
855
856
857
858/* before_execmode_hook
859 *
860 * This function basically draw lines and icons. Two types of lines are drawn :
861 * one small (3 pixels?) representing the state of the process and the second
862 * type is thicker (10 pixels?) representing on which CPU a process is running
863 * (and this only in running state).
864 *
865 * Extremums of the lines :
866 * x_min : time of the last event context for this process kept in memory.
867 * x_max : time of the current event.
868 * y : middle of the process in the process list. The process is found in the
869 * list, therefore is it's position in pixels.
870 *
871 * The choice of lines'color is defined by the context of the last event for this
872 * process.
873 */
874
875
876int before_execmode_hook(void *hook_data, void *call_data)
877{
878 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility*)hook_data;
879 EventsRequest *events_request = (EventsRequest*)thf->hook_data;
880 ControlFlowData *control_flow_data = events_request->viewer_data;
881
882 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
883
884 LttvTracefileState *tfs = (LttvTracefileState *)call_data;
885
886 LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
887
888 LttEvent *e;
889 e = ltt_tracefile_get_event(tfc->tf);
890
891 LttvFilter *filter = control_flow_data->filter;
892 if(filter != NULL && filter->head != NULL)
893 if(!lttv_filter_tree_parse(filter->head,e,tfc->tf,
894 tfc->t_context->t,tfc,NULL,NULL))
895 return FALSE;
896
897 LttTime evtime = ltt_event_time(e);
898
899 /* we are in a execmode, before the state update. We must draw the
900 * items corresponding to the state before it changes : now is the right
901 * time to do it.
902 */
903 /* For the pid */
904 //LttvProcessState *process = tfs->process;
905 guint cpu = tfs->cpu;
906 guint trace_num = ts->parent.index;
907 LttvProcessState *process = ts->running_process[cpu];
908 g_assert(process != NULL);
909
910 guint pid = process->pid;
911
912 /* Well, the process_out existed : we must get it in the process hash
913 * or add it, and draw its items.
914 */
915 /* Add process to process list (if not present) */
916 guint pl_height = 0;
917 HashedProcessData *hashed_process_data = NULL;
918 ProcessList *process_list = control_flow_data->process_list;
919 LttTime birth = process->creation_time;
920
921 if(likely(process_list->current_hash_data[trace_num][cpu] != NULL)) {
922 hashed_process_data = process_list->current_hash_data[trace_num][cpu];
923 } else {
924 hashed_process_data = processlist_get_process_data(process_list,
925 pid,
926 process->cpu,
927 &birth,
928 trace_num);
929 if(unlikely(hashed_process_data == NULL))
930 {
931 g_assert(pid == 0 || pid != process->ppid);
932 ProcessInfo *process_info;
933 /* Process not present */
934 Drawing_t *drawing = control_flow_data->drawing;
935 processlist_add(process_list,
936 drawing,
937 pid,
938 process->tgid,
939 process->cpu,
940 process->ppid,
941 &birth,
942 trace_num,
943 process->name,
944 process->brand,
945 &pl_height,
946 &process_info,
947 &hashed_process_data);
948 gtk_widget_set_size_request(drawing->drawing_area,
949 -1,
950 pl_height);
951 gtk_widget_queue_draw(drawing->drawing_area);
952 }
953 /* Set the current process */
954 process_list->current_hash_data[trace_num][process->cpu] =
955 hashed_process_data;
956 }
957
958 /* Now, the process is in the state hash and our own process hash.
959 * We definitely can draw the items related to the ending state.
960 */
961
962 if(likely(ltt_time_compare(hashed_process_data->next_good_time,
963 evtime) > 0))
964 {
965 if(unlikely(hashed_process_data->x.middle_marked == FALSE)) {
966 TimeWindow time_window =
967 lttvwindow_get_time_window(control_flow_data->tab);
968
969#ifdef EXTRA_CHECK
970 if(ltt_time_compare(evtime, time_window.start_time) == -1
971 || ltt_time_compare(evtime, time_window.end_time) == 1)
972 return;
973#endif //EXTRA_CHECK
974 Drawing_t *drawing = control_flow_data->drawing;
975 guint width = drawing->width;
976 guint x;
977 convert_time_to_pixels(
978 time_window,
979 evtime,
980 width,
981 &x);
982
983 /* Draw collision indicator */
984 gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
985 gdk_draw_point(hashed_process_data->pixmap,
986 drawing->gc,
987 x,
988 COLLISION_POSITION(hashed_process_data->height));
989 hashed_process_data->x.middle_marked = TRUE;
990 }
991 } else {
992 TimeWindow time_window =
993 lttvwindow_get_time_window(control_flow_data->tab);
994
995#ifdef EXTRA_CHECK
996 if(ltt_time_compare(evtime, time_window.start_time) == -1
997 || ltt_time_compare(evtime, time_window.end_time) == 1)
998 return;
999#endif //EXTRA_CHECK
1000 Drawing_t *drawing = control_flow_data->drawing;
1001 guint width = drawing->width;
1002 guint x;
1003
1004 convert_time_to_pixels(
1005 time_window,
1006 evtime,
1007 width,
1008 &x);
1009
1010
1011 /* Jump over draw if we are at the same x position */
1012 if(unlikely(x == hashed_process_data->x.middle &&
1013 hashed_process_data->x.middle_used))
1014 {
1015 if(unlikely(hashed_process_data->x.middle_marked == FALSE)) {
1016 /* Draw collision indicator */
1017 gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
1018 gdk_draw_point(hashed_process_data->pixmap,
1019 drawing->gc,
1020 x,
1021 COLLISION_POSITION(hashed_process_data->height));
1022 hashed_process_data->x.middle_marked = TRUE;
1023 }
1024 /* jump */
1025 } else {
1026
1027 DrawContext draw_context;
1028 /* Now create the drawing context that will be used to draw
1029 * items related to the last state. */
1030 draw_context.drawable = hashed_process_data->pixmap;
1031 draw_context.gc = drawing->gc;
1032 draw_context.pango_layout = drawing->pango_layout;
1033 draw_context.drawinfo.start.x = hashed_process_data->x.middle;
1034 draw_context.drawinfo.end.x = x;
1035
1036 draw_context.drawinfo.y.over = 1;
1037 draw_context.drawinfo.y.middle = (hashed_process_data->height/2);
1038 draw_context.drawinfo.y.under = hashed_process_data->height;
1039
1040 draw_context.drawinfo.start.offset.over = 0;
1041 draw_context.drawinfo.start.offset.middle = 0;
1042 draw_context.drawinfo.start.offset.under = 0;
1043 draw_context.drawinfo.end.offset.over = 0;
1044 draw_context.drawinfo.end.offset.middle = 0;
1045 draw_context.drawinfo.end.offset.under = 0;
1046
1047 {
1048 /* Draw the line */
1049 PropertiesLine prop_line = prepare_s_e_line(process);
1050 draw_line((void*)&prop_line, (void*)&draw_context);
1051
1052 }
1053 /* become the last x position */
1054 hashed_process_data->x.middle = x;
1055 hashed_process_data->x.middle_used = TRUE;
1056 hashed_process_data->x.middle_marked = FALSE;
1057
1058 /* Calculate the next good time */
1059 convert_pixels_to_time(width, x+1, time_window,
1060 &hashed_process_data->next_good_time);
1061 }
1062 }
1063
1064 return 0;
1065}
1066
1067/* before_process_exit_hook
1068 *
1069 * Draw lines for process event.
1070 *
1071 * @param hook_data ControlFlowData structure of the viewer.
1072 * @param call_data Event context.
1073 *
1074 * This function adds items to be drawn in a queue for each process.
1075 *
1076 */
1077
1078
1079int before_process_exit_hook(void *hook_data, void *call_data)
1080{
1081 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility*)hook_data;
1082 EventsRequest *events_request = (EventsRequest*)thf->hook_data;
1083
1084 ControlFlowData *control_flow_data = events_request->viewer_data;
1085
1086 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
1087
1088 LttvTracefileState *tfs = (LttvTracefileState *)call_data;
1089
1090 LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
1091
1092 LttEvent *e;
1093 e = ltt_tracefile_get_event(tfc->tf);
1094
1095 LttvFilter *filter = control_flow_data->filter;
1096 if(filter != NULL && filter->head != NULL)
1097 if(!lttv_filter_tree_parse(filter->head,e,tfc->tf,
1098 tfc->t_context->t,tfc,NULL,NULL))
1099 return FALSE;
1100
1101 LttTime evtime = ltt_event_time(e);
1102
1103 /* Add process to process list (if not present) */
1104 //LttvProcessState *process = tfs->process;
1105 guint cpu = tfs->cpu;
1106 guint trace_num = ts->parent.index;
1107 LttvProcessState *process = ts->running_process[cpu];
1108 guint pid = process->pid;
1109 LttTime birth;
1110 guint pl_height = 0;
1111 HashedProcessData *hashed_process_data = NULL;
1112
1113 ProcessList *process_list = control_flow_data->process_list;
1114
1115 g_assert(process != NULL);
1116
1117 birth = process->creation_time;
1118
1119 if(likely(process_list->current_hash_data[trace_num][cpu] != NULL)) {
1120 hashed_process_data = process_list->current_hash_data[trace_num][cpu];
1121 } else {
1122 hashed_process_data = processlist_get_process_data(process_list,
1123 pid,
1124 process->cpu,
1125 &birth,
1126 trace_num);
1127 if(unlikely(hashed_process_data == NULL))
1128 {
1129 g_assert(pid == 0 || pid != process->ppid);
1130 /* Process not present */
1131 Drawing_t *drawing = control_flow_data->drawing;
1132 ProcessInfo *process_info;
1133 processlist_add(process_list,
1134 drawing,
1135 pid,
1136 process->tgid,
1137 process->cpu,
1138 process->ppid,
1139 &birth,
1140 trace_num,
1141 process->name,
1142 process->brand,
1143 &pl_height,
1144 &process_info,
1145 &hashed_process_data);
1146 gtk_widget_set_size_request(drawing->drawing_area,
1147 -1,
1148 pl_height);
1149 gtk_widget_queue_draw(drawing->drawing_area);
1150 }
1151 }
1152
1153 /* Now, the process is in the state hash and our own process hash.
1154 * We definitely can draw the items related to the ending state.
1155 */
1156
1157 if(likely(ltt_time_compare(hashed_process_data->next_good_time,
1158 evtime) > 0))
1159 {
1160 if(unlikely(hashed_process_data->x.middle_marked == FALSE)) {
1161 TimeWindow time_window =
1162 lttvwindow_get_time_window(control_flow_data->tab);
1163
1164#ifdef EXTRA_CHECK
1165 if(ltt_time_compare(evtime, time_window.start_time) == -1
1166 || ltt_time_compare(evtime, time_window.end_time) == 1)
1167 return;
1168#endif //EXTRA_CHECK
1169 Drawing_t *drawing = control_flow_data->drawing;
1170 guint width = drawing->width;
1171 guint x;
1172 convert_time_to_pixels(
1173 time_window,
1174 evtime,
1175 width,
1176 &x);
1177
1178 /* Draw collision indicator */
1179 gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
1180 gdk_draw_point(hashed_process_data->pixmap,
1181 drawing->gc,
1182 x,
1183 COLLISION_POSITION(hashed_process_data->height));
1184 hashed_process_data->x.middle_marked = TRUE;
1185 }
1186 } else {
1187 TimeWindow time_window =
1188 lttvwindow_get_time_window(control_flow_data->tab);
1189
1190#ifdef EXTRA_CHECK
1191 if(ltt_time_compare(evtime, time_window.start_time) == -1
1192 || ltt_time_compare(evtime, time_window.end_time) == 1)
1193 return;
1194#endif //EXTRA_CHECK
1195 Drawing_t *drawing = control_flow_data->drawing;
1196 guint width = drawing->width;
1197 guint x;
1198
1199 convert_time_to_pixels(
1200 time_window,
1201 evtime,
1202 width,
1203 &x);
1204
1205
1206 /* Jump over draw if we are at the same x position */
1207 if(unlikely(x == hashed_process_data->x.middle &&
1208 hashed_process_data->x.middle_used))
1209 {
1210 if(unlikely(hashed_process_data->x.middle_marked == FALSE)) {
1211 /* Draw collision indicator */
1212 gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
1213 gdk_draw_point(hashed_process_data->pixmap,
1214 drawing->gc,
1215 x,
1216 COLLISION_POSITION(hashed_process_data->height));
1217 hashed_process_data->x.middle_marked = TRUE;
1218 }
1219 /* jump */
1220 } else {
1221 DrawContext draw_context;
1222
1223 /* Now create the drawing context that will be used to draw
1224 * items related to the last state. */
1225 draw_context.drawable = hashed_process_data->pixmap;
1226 draw_context.gc = drawing->gc;
1227 draw_context.pango_layout = drawing->pango_layout;
1228 draw_context.drawinfo.start.x = hashed_process_data->x.middle;
1229 draw_context.drawinfo.end.x = x;
1230
1231 draw_context.drawinfo.y.over = 1;
1232 draw_context.drawinfo.y.middle = (hashed_process_data->height/2);
1233 draw_context.drawinfo.y.under = hashed_process_data->height;
1234
1235 draw_context.drawinfo.start.offset.over = 0;
1236 draw_context.drawinfo.start.offset.middle = 0;
1237 draw_context.drawinfo.start.offset.under = 0;
1238 draw_context.drawinfo.end.offset.over = 0;
1239 draw_context.drawinfo.end.offset.middle = 0;
1240 draw_context.drawinfo.end.offset.under = 0;
1241
1242 {
1243 /* Draw the line */
1244 PropertiesLine prop_line = prepare_s_e_line(process);
1245 draw_line((void*)&prop_line, (void*)&draw_context);
1246
1247 }
1248 /* become the last x position */
1249 hashed_process_data->x.middle = x;
1250 hashed_process_data->x.middle_used = TRUE;
1251 hashed_process_data->x.middle_marked = FALSE;
1252
1253 /* Calculate the next good time */
1254 convert_pixels_to_time(width, x+1, time_window,
1255 &hashed_process_data->next_good_time);
1256 }
1257 }
1258
1259 return 0;
1260
1261}
1262
1263
1264
1265/* before_process_release_hook
1266 *
1267 * Draw lines for process event.
1268 *
1269 * @param hook_data ControlFlowData structure of the viewer.
1270 * @param call_data Event context.
1271 *
1272 * This function adds items to be drawn in a queue for each process.
1273 *
1274 */
1275
1276
1277int before_process_release_hook(void *hook_data, void *call_data)
1278{
1279 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility*)hook_data;
1280 EventsRequest *events_request = (EventsRequest*)thf->hook_data;
1281
1282 ControlFlowData *control_flow_data = events_request->viewer_data;
1283
1284 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
1285
1286 LttvTracefileState *tfs = (LttvTracefileState *)call_data;
1287
1288 LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
1289
1290 LttEvent *e;
1291 e = ltt_tracefile_get_event(tfc->tf);
1292
1293 LttvFilter *filter = control_flow_data->filter;
1294 if(filter != NULL && filter->head != NULL)
1295 if(!lttv_filter_tree_parse(filter->head,e,tfc->tf,
1296 tfc->t_context->t,tfc,NULL,NULL))
1297 return FALSE;
1298
1299 LttTime evtime = ltt_event_time(e);
1300
1301 guint trace_num = ts->parent.index;
1302
1303 guint pid;
1304 {
1305 pid = ltt_event_get_long_unsigned(e, thf->f1);
1306 }
1307
1308 /* Add process to process list (if not present) */
1309 /* Don't care about the process if it's not in the state hash already :
1310 * that means a process that has never done anything in the trace and
1311 * unknown suddently gets destroyed : no state meaningful to show. */
1312 LttvProcessState *process = lttv_state_find_process(ts, ANY_CPU, pid);
1313
1314 if(process != NULL) {
1315 LttTime birth;
1316 guint pl_height = 0;
1317 HashedProcessData *hashed_process_data = NULL;
1318
1319 ProcessList *process_list = control_flow_data->process_list;
1320
1321 birth = process->creation_time;
1322
1323 /* Cannot use current process : this event happens on another process,
1324 * action done by the parent. */
1325 hashed_process_data = processlist_get_process_data(process_list,
1326 pid,
1327 process->cpu,
1328 &birth,
1329 trace_num);
1330 if(unlikely(hashed_process_data == NULL))
1331 {
1332 g_assert(pid == 0 || pid != process->ppid);
1333 /* Process not present */
1334 Drawing_t *drawing = control_flow_data->drawing;
1335 ProcessInfo *process_info;
1336 processlist_add(process_list,
1337 drawing,
1338 pid,
1339 process->tgid,
1340 process->cpu,
1341 process->ppid,
1342 &birth,
1343 trace_num,
1344 process->name,
1345 process->brand,
1346 &pl_height,
1347 &process_info,
1348 &hashed_process_data);
1349 gtk_widget_set_size_request(drawing->drawing_area,
1350 -1,
1351 pl_height);
1352 gtk_widget_queue_draw(drawing->drawing_area);
1353 }
1354
1355 /* Now, the process is in the state hash and our own process hash.
1356 * We definitely can draw the items related to the ending state.
1357 */
1358
1359 if(likely(ltt_time_compare(hashed_process_data->next_good_time,
1360 evtime) > 0))
1361 {
1362 if(unlikely(hashed_process_data->x.middle_marked == FALSE)) {
1363 TimeWindow time_window =
1364 lttvwindow_get_time_window(control_flow_data->tab);
1365
1366#ifdef EXTRA_CHECK
1367 if(ltt_time_compare(evtime, time_window.start_time) == -1
1368 || ltt_time_compare(evtime, time_window.end_time) == 1)
1369 return;
1370#endif //EXTRA_CHECK
1371 Drawing_t *drawing = control_flow_data->drawing;
1372 guint width = drawing->width;
1373 guint x;
1374 convert_time_to_pixels(
1375 time_window,
1376 evtime,
1377 width,
1378 &x);
1379
1380 /* Draw collision indicator */
1381 gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
1382 gdk_draw_point(hashed_process_data->pixmap,
1383 drawing->gc,
1384 x,
1385 COLLISION_POSITION(hashed_process_data->height));
1386 hashed_process_data->x.middle_marked = TRUE;
1387 }
1388 } else {
1389 TimeWindow time_window =
1390 lttvwindow_get_time_window(control_flow_data->tab);
1391
1392#ifdef EXTRA_CHECK
1393 if(ltt_time_compare(evtime, time_window.start_time) == -1
1394 || ltt_time_compare(evtime, time_window.end_time) == 1)
1395 return;
1396#endif //EXTRA_CHECK
1397 Drawing_t *drawing = control_flow_data->drawing;
1398 guint width = drawing->width;
1399 guint x;
1400
1401 convert_time_to_pixels(
1402 time_window,
1403 evtime,
1404 width,
1405 &x);
1406
1407
1408 /* Jump over draw if we are at the same x position */
1409 if(unlikely(x == hashed_process_data->x.middle &&
1410 hashed_process_data->x.middle_used))
1411 {
1412 if(unlikely(hashed_process_data->x.middle_marked == FALSE)) {
1413 /* Draw collision indicator */
1414 gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
1415 gdk_draw_point(hashed_process_data->pixmap,
1416 drawing->gc,
1417 x,
1418 COLLISION_POSITION(hashed_process_data->height));
1419 hashed_process_data->x.middle_marked = TRUE;
1420 }
1421 /* jump */
1422 } else {
1423 DrawContext draw_context;
1424
1425 /* Now create the drawing context that will be used to draw
1426 * items related to the last state. */
1427 draw_context.drawable = hashed_process_data->pixmap;
1428 draw_context.gc = drawing->gc;
1429 draw_context.pango_layout = drawing->pango_layout;
1430 draw_context.drawinfo.start.x = hashed_process_data->x.middle;
1431 draw_context.drawinfo.end.x = x;
1432
1433 draw_context.drawinfo.y.over = 1;
1434 draw_context.drawinfo.y.middle = (hashed_process_data->height/2);
1435 draw_context.drawinfo.y.under = hashed_process_data->height;
1436
1437 draw_context.drawinfo.start.offset.over = 0;
1438 draw_context.drawinfo.start.offset.middle = 0;
1439 draw_context.drawinfo.start.offset.under = 0;
1440 draw_context.drawinfo.end.offset.over = 0;
1441 draw_context.drawinfo.end.offset.middle = 0;
1442 draw_context.drawinfo.end.offset.under = 0;
1443
1444 {
1445 /* Draw the line */
1446 PropertiesLine prop_line = prepare_s_e_line(process);
1447 draw_line((void*)&prop_line, (void*)&draw_context);
1448
1449 }
1450 /* become the last x position */
1451 hashed_process_data->x.middle = x;
1452 hashed_process_data->x.middle_used = TRUE;
1453 hashed_process_data->x.middle_marked = FALSE;
1454
1455 /* Calculate the next good time */
1456 convert_pixels_to_time(width, x+1, time_window,
1457 &hashed_process_data->next_good_time);
1458 }
1459 }
1460 }
1461
1462 return 0;
1463}
1464
1465
1466
1467
1468
1469/* after_process_fork_hook
1470 *
1471 * Create the processlist entry for the child process. Put the last
1472 * position in x at the current time value.
1473 *
1474 * @param hook_data ControlFlowData structure of the viewer.
1475 * @param call_data Event context.
1476 *
1477 * This function adds items to be drawn in a queue for each process.
1478 *
1479 */
1480int after_process_fork_hook(void *hook_data, void *call_data)
1481{
1482 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility*)hook_data;
1483 EventsRequest *events_request = (EventsRequest*)thf->hook_data;
1484 ControlFlowData *control_flow_data = events_request->viewer_data;
1485
1486 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
1487
1488 LttvTracefileState *tfs = (LttvTracefileState *)call_data;
1489
1490 LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
1491
1492 LttEvent *e;
1493 e = ltt_tracefile_get_event(tfc->tf);
1494
1495 LttvFilter *filter = control_flow_data->filter;
1496 if(filter != NULL && filter->head != NULL)
1497 if(!lttv_filter_tree_parse(filter->head,e,tfc->tf,
1498 tfc->t_context->t,tfc,NULL,NULL))
1499 return FALSE;
1500
1501 LttTime evtime = ltt_event_time(e);
1502
1503 guint child_pid;
1504 {
1505 child_pid = ltt_event_get_long_unsigned(e, thf->f2);
1506 }
1507
1508 /* Add process to process list (if not present) */
1509 LttvProcessState *process_child;
1510 LttTime birth;
1511 guint pl_height = 0;
1512 HashedProcessData *hashed_process_data_child = NULL;
1513
1514 ProcessList *process_list = control_flow_data->process_list;
1515
1516 /* Find child in the list... */
1517 process_child = lttv_state_find_process(ts, ANY_CPU, child_pid);
1518 /* It should exist, because we are after the state update. */
1519 g_assert(process_child != NULL);
1520
1521 birth = process_child->creation_time;
1522 guint trace_num = ts->parent.index;
1523
1524 /* Cannot use current process, because this action is done by the parent
1525 * on its child. */
1526 hashed_process_data_child = processlist_get_process_data(process_list,
1527 child_pid,
1528 process_child->cpu,
1529 &birth,
1530 trace_num);
1531 if(likely(hashed_process_data_child == NULL))
1532 {
1533 g_assert(child_pid == 0 || child_pid != process_child->ppid);
1534 /* Process not present */
1535 Drawing_t *drawing = control_flow_data->drawing;
1536 ProcessInfo *process_info;
1537 processlist_add(process_list,
1538 drawing,
1539 child_pid,
1540 process_child->tgid,
1541 process_child->cpu,
1542 process_child->ppid,
1543 &birth,
1544 trace_num,
1545 process_child->name,
1546 process_child->brand,
1547 &pl_height,
1548 &process_info,
1549 &hashed_process_data_child);
1550 gtk_widget_set_size_request(drawing->drawing_area,
1551 -1,
1552 pl_height);
1553 gtk_widget_queue_draw(drawing->drawing_area);
1554 } else {
1555 processlist_set_ppid(process_list, process_child->ppid,
1556 hashed_process_data_child);
1557 processlist_set_tgid(process_list, process_child->tgid,
1558 hashed_process_data_child);
1559 }
1560
1561
1562 if(likely(ltt_time_compare(hashed_process_data_child->next_good_time,
1563 evtime) <= 0))
1564 {
1565 TimeWindow time_window =
1566 lttvwindow_get_time_window(control_flow_data->tab);
1567
1568#ifdef EXTRA_CHECK
1569 if(ltt_time_compare(evtime, time_window.start_time) == -1
1570 || ltt_time_compare(evtime, time_window.end_time) == 1)
1571 return;
1572#endif //EXTRA_CHECK
1573 Drawing_t *drawing = control_flow_data->drawing;
1574 guint width = drawing->width;
1575 guint new_x;
1576 convert_time_to_pixels(
1577 time_window,
1578 evtime,
1579 width,
1580 &new_x);
1581
1582 if(likely(hashed_process_data_child->x.over != new_x)) {
1583 hashed_process_data_child->x.over = new_x;
1584 hashed_process_data_child->x.over_used = FALSE;
1585 hashed_process_data_child->x.over_marked = FALSE;
1586 }
1587 if(likely(hashed_process_data_child->x.middle != new_x)) {
1588 hashed_process_data_child->x.middle = new_x;
1589 hashed_process_data_child->x.middle_used = FALSE;
1590 hashed_process_data_child->x.middle_marked = FALSE;
1591 }
1592 if(likely(hashed_process_data_child->x.under != new_x)) {
1593 hashed_process_data_child->x.under = new_x;
1594 hashed_process_data_child->x.under_used = FALSE;
1595 hashed_process_data_child->x.under_marked = FALSE;
1596 }
1597 }
1598 return 0;
1599}
1600
1601
1602
1603/* after_process_exit_hook
1604 *
1605 * Create the processlist entry for the child process. Put the last
1606 * position in x at the current time value.
1607 *
1608 * @param hook_data ControlFlowData structure of the viewer.
1609 * @param call_data Event context.
1610 *
1611 * This function adds items to be drawn in a queue for each process.
1612 *
1613 */
1614int after_process_exit_hook(void *hook_data, void *call_data)
1615{
1616 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility*)hook_data;
1617 EventsRequest *events_request = (EventsRequest*)thf->hook_data;
1618 ControlFlowData *control_flow_data = events_request->viewer_data;
1619
1620 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
1621
1622 LttvTracefileState *tfs = (LttvTracefileState *)call_data;
1623
1624 LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
1625
1626 LttEvent *e;
1627 e = ltt_tracefile_get_event(tfc->tf);
1628
1629 LttvFilter *filter = control_flow_data->filter;
1630 if(filter != NULL && filter->head != NULL)
1631 if(!lttv_filter_tree_parse(filter->head,e,tfc->tf,
1632 tfc->t_context->t,tfc,NULL,NULL))
1633 return FALSE;
1634
1635 LttTime evtime = ltt_event_time(e);
1636
1637 /* Add process to process list (if not present) */
1638 //LttvProcessState *process = tfs->process;
1639 guint cpu = tfs->cpu;
1640 guint trace_num = ts->parent.index;
1641 LttvProcessState *process = ts->running_process[cpu];
1642
1643 /* It should exist, because we are after the state update. */
1644 g_assert(process != NULL);
1645
1646 guint pid = process->pid;
1647 LttTime birth;
1648 guint pl_height = 0;
1649 HashedProcessData *hashed_process_data = NULL;
1650
1651 ProcessList *process_list = control_flow_data->process_list;
1652
1653 birth = process->creation_time;
1654
1655 if(likely(process_list->current_hash_data[trace_num][cpu] != NULL) ){
1656 hashed_process_data = process_list->current_hash_data[trace_num][cpu];
1657 } else {
1658 hashed_process_data = processlist_get_process_data(process_list,
1659 pid,
1660 process->cpu,
1661 &birth,
1662 trace_num);
1663 if(unlikely(hashed_process_data == NULL))
1664 {
1665 g_assert(pid == 0 || pid != process->ppid);
1666 /* Process not present */
1667 Drawing_t *drawing = control_flow_data->drawing;
1668 ProcessInfo *process_info;
1669 processlist_add(process_list,
1670 drawing,
1671 pid,
1672 process->tgid,
1673 process->cpu,
1674 process->ppid,
1675 &birth,
1676 trace_num,
1677 process->name,
1678 process->brand,
1679 &pl_height,
1680 &process_info,
1681 &hashed_process_data);
1682 gtk_widget_set_size_request(drawing->drawing_area,
1683 -1,
1684 pl_height);
1685 gtk_widget_queue_draw(drawing->drawing_area);
1686 }
1687
1688 /* Set the current process */
1689 process_list->current_hash_data[trace_num][process->cpu] =
1690 hashed_process_data;
1691 }
1692
1693 if(unlikely(ltt_time_compare(hashed_process_data->next_good_time,
1694 evtime) <= 0))
1695 {
1696 TimeWindow time_window =
1697 lttvwindow_get_time_window(control_flow_data->tab);
1698
1699#ifdef EXTRA_CHECK
1700 if(ltt_time_compare(evtime, time_window.start_time) == -1
1701 || ltt_time_compare(evtime, time_window.end_time) == 1)
1702 return;
1703#endif //EXTRA_CHECK
1704 Drawing_t *drawing = control_flow_data->drawing;
1705 guint width = drawing->width;
1706 guint new_x;
1707 convert_time_to_pixels(
1708 time_window,
1709 evtime,
1710 width,
1711 &new_x);
1712 if(unlikely(hashed_process_data->x.middle != new_x)) {
1713 hashed_process_data->x.middle = new_x;
1714 hashed_process_data->x.middle_used = FALSE;
1715 hashed_process_data->x.middle_marked = FALSE;
1716 }
1717 }
1718
1719 return 0;
1720}
1721
1722
1723/* Get the filename of the process to print */
1724int after_fs_exec_hook(void *hook_data, void *call_data)
1725{
1726 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility*)hook_data;
1727 EventsRequest *events_request = (EventsRequest*)thf->hook_data;
1728 ControlFlowData *control_flow_data = events_request->viewer_data;
1729
1730 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
1731
1732 LttvTracefileState *tfs = (LttvTracefileState *)call_data;
1733
1734 LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
1735
1736 LttEvent *e;
1737 e = ltt_tracefile_get_event(tfc->tf);
1738
1739 LttvFilter *filter = control_flow_data->filter;
1740 if(filter != NULL && filter->head != NULL)
1741 if(!lttv_filter_tree_parse(filter->head,e,tfc->tf,
1742 tfc->t_context->t,tfc,NULL,NULL))
1743 return FALSE;
1744
1745 guint cpu = tfs->cpu;
1746 guint trace_num = ts->parent.index;
1747 LttvProcessState *process = ts->running_process[cpu];
1748 g_assert(process != NULL);
1749
1750 guint pid = process->pid;
1751
1752 /* Well, the process_out existed : we must get it in the process hash
1753 * or add it, and draw its items.
1754 */
1755 /* Add process to process list (if not present) */
1756 guint pl_height = 0;
1757 HashedProcessData *hashed_process_data = NULL;
1758 ProcessList *process_list = control_flow_data->process_list;
1759 LttTime birth = process->creation_time;
1760
1761 if(likely(process_list->current_hash_data[trace_num][cpu] != NULL)) {
1762 hashed_process_data = process_list->current_hash_data[trace_num][cpu];
1763 } else {
1764 hashed_process_data = processlist_get_process_data(process_list,
1765 pid,
1766 process->cpu,
1767 &birth,
1768 trace_num);
1769 if(unlikely(hashed_process_data == NULL))
1770 {
1771 g_assert(pid == 0 || pid != process->ppid);
1772 ProcessInfo *process_info;
1773 /* Process not present */
1774 Drawing_t *drawing = control_flow_data->drawing;
1775 processlist_add(process_list,
1776 drawing,
1777 pid,
1778 process->tgid,
1779 process->cpu,
1780 process->ppid,
1781 &birth,
1782 trace_num,
1783 process->name,
1784 process->brand,
1785 &pl_height,
1786 &process_info,
1787 &hashed_process_data);
1788 gtk_widget_set_size_request(drawing->drawing_area,
1789 -1,
1790 pl_height);
1791 gtk_widget_queue_draw(drawing->drawing_area);
1792 }
1793 /* Set the current process */
1794 process_list->current_hash_data[trace_num][process->cpu] =
1795 hashed_process_data;
1796 }
1797
1798 processlist_set_name(process_list, process->name, hashed_process_data);
1799
1800 return 0;
1801
1802}
1803
1804/* Get the filename of the process to print */
1805int after_user_generic_thread_brand_hook(void *hook_data, void *call_data)
1806{
1807 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility*)hook_data;
1808 EventsRequest *events_request = (EventsRequest*)thf->hook_data;
1809 ControlFlowData *control_flow_data = events_request->viewer_data;
1810
1811 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
1812
1813 LttvTracefileState *tfs = (LttvTracefileState *)call_data;
1814
1815 LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
1816
1817 LttEvent *e;
1818 e = ltt_tracefile_get_event(tfc->tf);
1819
1820 LttvFilter *filter = control_flow_data->filter;
1821 if(filter != NULL && filter->head != NULL)
1822 if(!lttv_filter_tree_parse(filter->head,e,tfc->tf,
1823 tfc->t_context->t,tfc,NULL,NULL))
1824 return FALSE;
1825
1826 guint cpu = tfs->cpu;
1827 guint trace_num = ts->parent.index;
1828 LttvProcessState *process = ts->running_process[cpu];
1829 g_assert(process != NULL);
1830
1831 guint pid = process->pid;
1832
1833 /* Well, the process_out existed : we must get it in the process hash
1834 * or add it, and draw its items.
1835 */
1836 /* Add process to process list (if not present) */
1837 guint pl_height = 0;
1838 HashedProcessData *hashed_process_data = NULL;
1839 ProcessList *process_list = control_flow_data->process_list;
1840 LttTime birth = process->creation_time;
1841
1842 if(likely(process_list->current_hash_data[trace_num][cpu] != NULL)) {
1843 hashed_process_data = process_list->current_hash_data[trace_num][cpu];
1844 } else {
1845 hashed_process_data = processlist_get_process_data(process_list,
1846 pid,
1847 process->cpu,
1848 &birth,
1849 trace_num);
1850 if(unlikely(hashed_process_data == NULL))
1851 {
1852 g_assert(pid == 0 || pid != process->ppid);
1853 ProcessInfo *process_info;
1854 /* Process not present */
1855 Drawing_t *drawing = control_flow_data->drawing;
1856 processlist_add(process_list,
1857 drawing,
1858 pid,
1859 process->tgid,
1860 process->cpu,
1861 process->ppid,
1862 &birth,
1863 trace_num,
1864 process->name,
1865 process->brand,
1866 &pl_height,
1867 &process_info,
1868 &hashed_process_data);
1869 gtk_widget_set_size_request(drawing->drawing_area,
1870 -1,
1871 pl_height);
1872 gtk_widget_queue_draw(drawing->drawing_area);
1873 }
1874 /* Set the current process */
1875 process_list->current_hash_data[trace_num][process->cpu] =
1876 hashed_process_data;
1877 }
1878
1879 processlist_set_brand(process_list, process->brand, hashed_process_data);
1880
1881 return 0;
1882
1883}
1884
1885
1886/* after_event_enum_process_hook
1887 *
1888 * Create the processlist entry for the child process. Put the last
1889 * position in x at the current time value.
1890 *
1891 * @param hook_data ControlFlowData structure of the viewer.
1892 * @param call_data Event context.
1893 *
1894 * This function adds items to be drawn in a queue for each process.
1895 *
1896 */
1897int after_event_enum_process_hook(void *hook_data, void *call_data)
1898{
1899 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility*)hook_data;
1900 EventsRequest *events_request = (EventsRequest*)thf->hook_data;
1901 ControlFlowData *control_flow_data = events_request->viewer_data;
1902
1903 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
1904
1905 LttvTracefileState *tfs = (LttvTracefileState *)call_data;
1906
1907 LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
1908
1909 guint first_cpu, nb_cpus, cpu;
1910
1911 LttEvent *e;
1912 e = ltt_tracefile_get_event(tfc->tf);
1913
1914 LttvFilter *filter = control_flow_data->filter;
1915 if(filter != NULL && filter->head != NULL)
1916 if(!lttv_filter_tree_parse(filter->head,e,tfc->tf,
1917 tfc->t_context->t,tfc,NULL,NULL))
1918 return FALSE;
1919
1920 LttTime evtime = ltt_event_time(e);
1921
1922 /* Add process to process list (if not present) */
1923 LttvProcessState *process_in;
1924 LttTime birth;
1925 guint pl_height = 0;
1926 HashedProcessData *hashed_process_data_in = NULL;
1927
1928 ProcessList *process_list = control_flow_data->process_list;
1929 guint trace_num = ts->parent.index;
1930
1931 guint pid_in;
1932 {
1933 pid_in = ltt_event_get_long_unsigned(e, thf->f1);
1934 }
1935
1936 if(pid_in == 0) {
1937 first_cpu = 0;
1938 nb_cpus = ltt_trace_get_num_cpu(ts->parent.t);
1939 } else {
1940 first_cpu = ANY_CPU;
1941 nb_cpus = ANY_CPU+1;
1942 }
1943
1944 for(cpu = first_cpu; cpu < nb_cpus; cpu++) {
1945 /* Find process pid_in in the list... */
1946 process_in = lttv_state_find_process(ts, cpu, pid_in);
1947 //process_in = tfs->process;
1948 //guint cpu = tfs->cpu;
1949 //guint trace_num = ts->parent.index;
1950 //process_in = ts->running_process[cpu];
1951 /* It should exist, because we are after the state update. */
1952 #ifdef EXTRA_CHECK
1953 //g_assert(process_in != NULL);
1954 #endif //EXTRA_CHECK
1955 birth = process_in->creation_time;
1956
1957 hashed_process_data_in = processlist_get_process_data(process_list,
1958 pid_in,
1959 process_in->cpu,
1960 &birth,
1961 trace_num);
1962 if(hashed_process_data_in == NULL)
1963 {
1964 if(pid_in != 0 && pid_in == process_in->ppid)
1965 g_critical("TEST %u , %u", pid_in, process_in->ppid);
1966 g_assert(pid_in == 0 || pid_in != process_in->ppid);
1967 ProcessInfo *process_info;
1968 Drawing_t *drawing = control_flow_data->drawing;
1969 /* Process not present */
1970 processlist_add(process_list,
1971 drawing,
1972 pid_in,
1973 process_in->tgid,
1974 process_in->cpu,
1975 process_in->ppid,
1976 &birth,
1977 trace_num,
1978 process_in->name,
1979 process_in->brand,
1980 &pl_height,
1981 &process_info,
1982 &hashed_process_data_in);
1983 gtk_widget_set_size_request(drawing->drawing_area,
1984 -1,
1985 pl_height);
1986 gtk_widget_queue_draw(drawing->drawing_area);
1987 } else {
1988 processlist_set_name(process_list, process_in->name,
1989 hashed_process_data_in);
1990 processlist_set_ppid(process_list, process_in->ppid,
1991 hashed_process_data_in);
1992 processlist_set_tgid(process_list, process_in->tgid,
1993 hashed_process_data_in);
1994 }
1995 }
1996 return 0;
1997}
1998
1999
2000gint update_time_window_hook(void *hook_data, void *call_data)
2001{
2002 ControlFlowData *control_flow_data = (ControlFlowData*) hook_data;
2003 Drawing_t *drawing = control_flow_data->drawing;
2004 ProcessList *process_list = control_flow_data->process_list;
2005
2006 const TimeWindowNotifyData *time_window_nofify_data =
2007 ((const TimeWindowNotifyData *)call_data);
2008
2009 TimeWindow *old_time_window =
2010 time_window_nofify_data->old_time_window;
2011 TimeWindow *new_time_window =
2012 time_window_nofify_data->new_time_window;
2013
2014 /* Update the ruler */
2015 drawing_update_ruler(control_flow_data->drawing,
2016 new_time_window);
2017
2018
2019 /* Two cases : zoom in/out or scrolling */
2020
2021 /* In order to make sure we can reuse the old drawing, the scale must
2022 * be the same and the new time interval being partly located in the
2023 * currently shown time interval. (reuse is only for scrolling)
2024 */
2025
2026 g_info("Old time window HOOK : %lu, %lu to %lu, %lu",
2027 old_time_window->start_time.tv_sec,
2028 old_time_window->start_time.tv_nsec,
2029 old_time_window->time_width.tv_sec,
2030 old_time_window->time_width.tv_nsec);
2031
2032 g_info("New time window HOOK : %lu, %lu to %lu, %lu",
2033 new_time_window->start_time.tv_sec,
2034 new_time_window->start_time.tv_nsec,
2035 new_time_window->time_width.tv_sec,
2036 new_time_window->time_width.tv_nsec);
2037
2038 if( new_time_window->time_width.tv_sec == old_time_window->time_width.tv_sec
2039 && new_time_window->time_width.tv_nsec == old_time_window->time_width.tv_nsec)
2040 {
2041 /* Same scale (scrolling) */
2042 g_info("scrolling");
2043 LttTime *ns = &new_time_window->start_time;
2044 LttTime *nw = &new_time_window->time_width;
2045 LttTime *os = &old_time_window->start_time;
2046 LttTime *ow = &old_time_window->time_width;
2047 LttTime old_end = old_time_window->end_time;
2048 LttTime new_end = new_time_window->end_time;
2049 //if(ns<os+w<ns+w)
2050 //if(ns<os+w && os+w<ns+w)
2051 //if(ns<old_end && os<ns)
2052 if(ltt_time_compare(*ns, old_end) == -1
2053 && ltt_time_compare(*os, *ns) == -1)
2054 {
2055 g_info("scrolling near right");
2056 /* Scroll right, keep right part of the screen */
2057 guint x = 0;
2058 guint width = control_flow_data->drawing->width;
2059 convert_time_to_pixels(
2060 *old_time_window,
2061 *ns,
2062 width,
2063 &x);
2064
2065 /* Copy old data to new location */
2066 copy_pixmap_region(process_list,
2067 NULL,
2068 control_flow_data->drawing->drawing_area->style->black_gc,
2069 NULL,
2070 x, 0,
2071 0, 0,
2072 control_flow_data->drawing->width-x+SAFETY, -1);
2073
2074 if(drawing->damage_begin == drawing->damage_end)
2075 drawing->damage_begin = control_flow_data->drawing->width-x;
2076 else
2077 drawing->damage_begin = 0;
2078
2079 drawing->damage_end = control_flow_data->drawing->width;
2080
2081 /* Clear the data request background, but not SAFETY */
2082 rectangle_pixmap(process_list,
2083 control_flow_data->drawing->drawing_area->style->black_gc,
2084 TRUE,
2085 drawing->damage_begin+SAFETY, 0,
2086 drawing->damage_end - drawing->damage_begin, // do not overlap
2087 -1);
2088 gtk_widget_queue_draw(drawing->drawing_area);
2089 //gtk_widget_queue_draw_area (drawing->drawing_area,
2090 // 0,0,
2091 // control_flow_data->drawing->width,
2092 // control_flow_data->drawing->height);
2093
2094 /* Get new data for the rest. */
2095 drawing_data_request(control_flow_data->drawing,
2096 drawing->damage_begin, 0,
2097 drawing->damage_end - drawing->damage_begin,
2098 control_flow_data->drawing->height);
2099 } else {
2100 //if(ns<os<ns+w)
2101 //if(ns<os && os<ns+w)
2102 //if(ns<os && os<new_end)
2103 if(ltt_time_compare(*ns,*os) == -1
2104 && ltt_time_compare(*os,new_end) == -1)
2105 {
2106 g_info("scrolling near left");
2107 /* Scroll left, keep left part of the screen */
2108 guint x = 0;
2109 guint width = control_flow_data->drawing->width;
2110 convert_time_to_pixels(
2111 *new_time_window,
2112 *os,
2113 width,
2114 &x);
2115
2116 /* Copy old data to new location */
2117 copy_pixmap_region (process_list,
2118 NULL,
2119 control_flow_data->drawing->drawing_area->style->black_gc,
2120 NULL,
2121 0, 0,
2122 x, 0,
2123 -1, -1);
2124
2125 if(drawing->damage_begin == drawing->damage_end)
2126 drawing->damage_end = x;
2127 else
2128 drawing->damage_end =
2129 control_flow_data->drawing->width;
2130
2131 drawing->damage_begin = 0;
2132
2133 rectangle_pixmap (process_list,
2134 control_flow_data->drawing->drawing_area->style->black_gc,
2135 TRUE,
2136 drawing->damage_begin, 0,
2137 drawing->damage_end - drawing->damage_begin, // do not overlap
2138 -1);
2139
2140 gtk_widget_queue_draw(drawing->drawing_area);
2141 //gtk_widget_queue_draw_area (drawing->drawing_area,
2142 // 0,0,
2143 // control_flow_data->drawing->width,
2144 // control_flow_data->drawing->height);
2145
2146
2147 /* Get new data for the rest. */
2148 drawing_data_request(control_flow_data->drawing,
2149 drawing->damage_begin, 0,
2150 drawing->damage_end - drawing->damage_begin,
2151 control_flow_data->drawing->height);
2152
2153 } else {
2154 if(ltt_time_compare(*ns,*os) == 0)
2155 {
2156 g_info("not scrolling");
2157 } else {
2158 g_info("scrolling far");
2159 /* Cannot reuse any part of the screen : far jump */
2160
2161
2162 rectangle_pixmap (process_list,
2163 control_flow_data->drawing->drawing_area->style->black_gc,
2164 TRUE,
2165 0, 0,
2166 control_flow_data->drawing->width+SAFETY, // do not overlap
2167 -1);
2168
2169 //gtk_widget_queue_draw_area (drawing->drawing_area,
2170 // 0,0,
2171 // control_flow_data->drawing->width,
2172 // control_flow_data->drawing->height);
2173 gtk_widget_queue_draw(drawing->drawing_area);
2174
2175 drawing->damage_begin = 0;
2176 drawing->damage_end = control_flow_data->drawing->width;
2177
2178 drawing_data_request(control_flow_data->drawing,
2179 0, 0,
2180 control_flow_data->drawing->width,
2181 control_flow_data->drawing->height);
2182
2183 }
2184 }
2185 }
2186 } else {
2187 /* Different scale (zoom) */
2188 g_info("zoom");
2189
2190 rectangle_pixmap (process_list,
2191 control_flow_data->drawing->drawing_area->style->black_gc,
2192 TRUE,
2193 0, 0,
2194 control_flow_data->drawing->width+SAFETY, // do not overlap
2195 -1);
2196
2197 //gtk_widget_queue_draw_area (drawing->drawing_area,
2198 // 0,0,
2199 // control_flow_data->drawing->width,
2200 // control_flow_data->drawing->height);
2201 gtk_widget_queue_draw(drawing->drawing_area);
2202
2203 drawing->damage_begin = 0;
2204 drawing->damage_end = control_flow_data->drawing->width;
2205
2206 drawing_data_request(control_flow_data->drawing,
2207 0, 0,
2208 control_flow_data->drawing->width,
2209 control_flow_data->drawing->height);
2210 }
2211
2212 /* Update directly when scrolling */
2213 gdk_window_process_updates(control_flow_data->drawing->drawing_area->window,
2214 TRUE);
2215
2216 return 0;
2217}
2218
2219gint traceset_notify(void *hook_data, void *call_data)
2220{
2221 ControlFlowData *control_flow_data = (ControlFlowData*) hook_data;
2222 Drawing_t *drawing = control_flow_data->drawing;
2223
2224 if(unlikely(drawing->gc == NULL)) {
2225 return FALSE;
2226 }
2227 if(drawing->dotted_gc == NULL) {
2228 return FALSE;
2229 }
2230
2231 drawing_clear(control_flow_data->drawing);
2232 processlist_clear(control_flow_data->process_list);
2233 gtk_widget_set_size_request(
2234 control_flow_data->drawing->drawing_area,
2235 -1, processlist_get_height(control_flow_data->process_list));
2236 redraw_notify(control_flow_data, NULL);
2237
2238 request_background_data(control_flow_data);
2239
2240 return FALSE;
2241}
2242
2243gint redraw_notify(void *hook_data, void *call_data)
2244{
2245 ControlFlowData *control_flow_data = (ControlFlowData*) hook_data;
2246 Drawing_t *drawing = control_flow_data->drawing;
2247 GtkWidget *widget = drawing->drawing_area;
2248
2249 drawing->damage_begin = 0;
2250 drawing->damage_end = drawing->width;
2251
2252 /* fun feature, to be separated someday... */
2253 drawing_clear(control_flow_data->drawing);
2254 processlist_clear(control_flow_data->process_list);
2255 gtk_widget_set_size_request(
2256 control_flow_data->drawing->drawing_area,
2257 -1, processlist_get_height(control_flow_data->process_list));
2258 // Clear the images
2259 rectangle_pixmap (control_flow_data->process_list,
2260 widget->style->black_gc,
2261 TRUE,
2262 0, 0,
2263 drawing->alloc_width,
2264 -1);
2265
2266 gtk_widget_queue_draw(drawing->drawing_area);
2267
2268 if(drawing->damage_begin < drawing->damage_end)
2269 {
2270 drawing_data_request(drawing,
2271 drawing->damage_begin,
2272 0,
2273 drawing->damage_end-drawing->damage_begin,
2274 drawing->height);
2275 }
2276
2277 //gtk_widget_queue_draw_area(drawing->drawing_area,
2278 // 0,0,
2279 // drawing->width,
2280 // drawing->height);
2281 return FALSE;
2282
2283}
2284
2285
2286gint continue_notify(void *hook_data, void *call_data)
2287{
2288 ControlFlowData *control_flow_data = (ControlFlowData*) hook_data;
2289 Drawing_t *drawing = control_flow_data->drawing;
2290
2291 //g_assert(widget->allocation.width == drawing->damage_end);
2292
2293 if(drawing->damage_begin < drawing->damage_end)
2294 {
2295 drawing_data_request(drawing,
2296 drawing->damage_begin,
2297 0,
2298 drawing->damage_end-drawing->damage_begin,
2299 drawing->height);
2300 }
2301
2302 return FALSE;
2303}
2304
2305
2306gint update_current_time_hook(void *hook_data, void *call_data)
2307{
2308 ControlFlowData *control_flow_data = (ControlFlowData*)hook_data;
2309 Drawing_t *drawing = control_flow_data->drawing;
2310
2311 LttTime current_time = *((LttTime*)call_data);
2312
2313 TimeWindow time_window =
2314 lttvwindow_get_time_window(control_flow_data->tab);
2315
2316 LttTime time_begin = time_window.start_time;
2317 LttTime width = time_window.time_width;
2318 LttTime half_width;
2319 {
2320 guint64 time_ll = ltt_time_to_uint64(width);
2321 time_ll = time_ll >> 1; /* divide by two */
2322 half_width = ltt_time_from_uint64(time_ll);
2323 }
2324 LttTime time_end = ltt_time_add(time_begin, width);
2325
2326 LttvTracesetContext * tsc =
2327 lttvwindow_get_traceset_context(control_flow_data->tab);
2328
2329 LttTime trace_start = tsc->time_span.start_time;
2330 LttTime trace_end = tsc->time_span.end_time;
2331
2332 g_info("New current time HOOK : %lu, %lu", current_time.tv_sec,
2333 current_time.tv_nsec);
2334
2335
2336
2337 /* If current time is inside time interval, just move the highlight
2338 * bar */
2339
2340 /* Else, we have to change the time interval. We have to tell it
2341 * to the main window. */
2342 /* The time interval change will take care of placing the current
2343 * time at the center of the visible area, or nearest possible if we are
2344 * at one end of the trace. */
2345
2346
2347 if(ltt_time_compare(current_time, time_begin) < 0)
2348 {
2349 TimeWindow new_time_window;
2350
2351 if(ltt_time_compare(current_time,
2352 ltt_time_add(trace_start,half_width)) < 0)
2353 time_begin = trace_start;
2354 else
2355 time_begin = ltt_time_sub(current_time,half_width);
2356
2357 new_time_window.start_time = time_begin;
2358 new_time_window.time_width = width;
2359 new_time_window.time_width_double = ltt_time_to_double(width);
2360 new_time_window.end_time = ltt_time_add(time_begin, width);
2361
2362 lttvwindow_report_time_window(control_flow_data->tab, new_time_window);
2363 }
2364 else if(ltt_time_compare(current_time, time_end) > 0)
2365 {
2366 TimeWindow new_time_window;
2367
2368 if(ltt_time_compare(current_time, ltt_time_sub(trace_end, half_width)) > 0)
2369 time_begin = ltt_time_sub(trace_end,width);
2370 else
2371 time_begin = ltt_time_sub(current_time,half_width);
2372
2373 new_time_window.start_time = time_begin;
2374 new_time_window.time_width = width;
2375 new_time_window.time_width_double = ltt_time_to_double(width);
2376 new_time_window.end_time = ltt_time_add(time_begin, width);
2377
2378 lttvwindow_report_time_window(control_flow_data->tab, new_time_window);
2379
2380 }
2381 gtk_widget_queue_draw(control_flow_data->drawing->drawing_area);
2382
2383 /* Update directly when scrolling */
2384 gdk_window_process_updates(control_flow_data->drawing->drawing_area->window,
2385 TRUE);
2386
2387 return 0;
2388}
2389
2390typedef struct _ClosureData {
2391 EventsRequest *events_request;
2392 LttvTracesetState *tss;
2393 LttTime end_time;
2394 guint x_end;
2395} ClosureData;
2396
2397
2398void draw_closure(gpointer key, gpointer value, gpointer user_data)
2399{
2400 ProcessInfo *process_info = (ProcessInfo*)key;
2401 HashedProcessData *hashed_process_data = (HashedProcessData*)value;
2402 ClosureData *closure_data = (ClosureData*)user_data;
2403
2404 EventsRequest *events_request = closure_data->events_request;
2405 ControlFlowData *control_flow_data = events_request->viewer_data;
2406
2407 LttvTracesetState *tss = closure_data->tss;
2408 LttvTracesetContext *tsc = (LttvTracesetContext*)tss;
2409
2410 LttTime evtime = closure_data->end_time;
2411
2412 gboolean dodraw = TRUE;
2413
2414 {
2415 /* For the process */
2416 /* First, check if the current process is in the state computation
2417 * process list. If it is there, that means we must add it right now and
2418 * draw items from the beginning of the read for it. If it is not
2419 * present, it's a new process and it was not present : it will
2420 * be added after the state update. */
2421#ifdef EXTRA_CHECK
2422 g_assert(lttv_traceset_number(tsc->ts) > 0);
2423#endif //EXTRA_CHECK
2424 LttvTraceContext *tc = tsc->traces[process_info->trace_num];
2425 LttvTraceState *ts = (LttvTraceState*)tc;
2426
2427#if 0
2428 //FIXME : optimize data structures.
2429 LttvTracefileState *tfs;
2430 LttvTracefileContext *tfc;
2431 guint i;
2432 for(i=0;i<tc->tracefiles->len;i++) {
2433 tfc = g_array_index(tc->tracefiles, LttvTracefileContext*, i);
2434 if(ltt_tracefile_name(tfc->tf) == LTT_NAME_CPU
2435 && tfs->cpu == process_info->cpu)
2436 break;
2437
2438 }
2439 g_assert(i<tc->tracefiles->len);
2440 tfs = LTTV_TRACEFILE_STATE(tfc);
2441#endif //0
2442 // LttvTracefileState *tfs =
2443 // (LttvTracefileState*)tsc->traces[process_info->trace_num]->
2444 // tracefiles[process_info->cpu];
2445
2446 LttvProcessState *process;
2447 process = lttv_state_find_process(ts, process_info->cpu,
2448 process_info->pid);
2449
2450 if(unlikely(process != NULL)) {
2451
2452 LttvFilter *filter = control_flow_data->filter;
2453 if(filter != NULL && filter->head != NULL)
2454 if(!lttv_filter_tree_parse(filter->head,NULL,NULL,
2455 tc->t,NULL,process,tc))
2456 dodraw = FALSE;
2457
2458 /* Only draw for processes that are currently in the trace states */
2459
2460 ProcessList *process_list = control_flow_data->process_list;
2461#ifdef EXTRA_CHECK
2462 /* Should be alike when background info is ready */
2463 if(control_flow_data->background_info_waiting==0)
2464 g_assert(ltt_time_compare(process->creation_time,
2465 process_info->birth) == 0);
2466#endif //EXTRA_CHECK
2467
2468 /* Now, the process is in the state hash and our own process hash.
2469 * We definitely can draw the items related to the ending state.
2470 */
2471
2472 if(unlikely(ltt_time_compare(hashed_process_data->next_good_time,
2473 evtime) <= 0))
2474 {
2475 TimeWindow time_window =
2476 lttvwindow_get_time_window(control_flow_data->tab);
2477
2478#ifdef EXTRA_CHECK
2479 if(ltt_time_compare(evtime, time_window.start_time) == -1
2480 || ltt_time_compare(evtime, time_window.end_time) == 1)
2481 return;
2482#endif //EXTRA_CHECK
2483 Drawing_t *drawing = control_flow_data->drawing;
2484 guint width = drawing->width;
2485
2486 guint x = closure_data->x_end;
2487
2488 DrawContext draw_context;
2489
2490 /* Now create the drawing context that will be used to draw
2491 * items related to the last state. */
2492 draw_context.drawable = hashed_process_data->pixmap;
2493 draw_context.gc = drawing->gc;
2494 draw_context.pango_layout = drawing->pango_layout;
2495 draw_context.drawinfo.end.x = x;
2496
2497 draw_context.drawinfo.y.over = 1;
2498 draw_context.drawinfo.y.middle = (hashed_process_data->height/2);
2499 draw_context.drawinfo.y.under = hashed_process_data->height;
2500
2501 draw_context.drawinfo.start.offset.over = 0;
2502 draw_context.drawinfo.start.offset.middle = 0;
2503 draw_context.drawinfo.start.offset.under = 0;
2504 draw_context.drawinfo.end.offset.over = 0;
2505 draw_context.drawinfo.end.offset.middle = 0;
2506 draw_context.drawinfo.end.offset.under = 0;
2507#if 0
2508 /* Jump over draw if we are at the same x position */
2509 if(x == hashed_process_data->x.over)
2510 {
2511 /* jump */
2512 } else {
2513 draw_context.drawinfo.start.x = hashed_process_data->x.over;
2514 /* Draw the line */
2515 PropertiesLine prop_line = prepare_execmode_line(process);
2516 draw_line((void*)&prop_line, (void*)&draw_context);
2517
2518 hashed_process_data->x.over = x;
2519 }
2520#endif //0
2521
2522 if(unlikely(x == hashed_process_data->x.middle &&
2523 hashed_process_data->x.middle_used)) {
2524#if 0 /* do not mark closure : not missing information */
2525 if(hashed_process_data->x.middle_marked == FALSE) {
2526 /* Draw collision indicator */
2527 gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
2528 gdk_draw_point(drawing->pixmap,
2529 drawing->gc,
2530 x,
2531 y+(height/2)-3);
2532 hashed_process_data->x.middle_marked = TRUE;
2533 }
2534#endif //0
2535 /* Jump */
2536 } else {
2537 draw_context.drawinfo.start.x = hashed_process_data->x.middle;
2538 /* Draw the line */
2539 if(dodraw) {
2540 PropertiesLine prop_line = prepare_s_e_line(process);
2541 draw_line((void*)&prop_line, (void*)&draw_context);
2542 }
2543
2544 /* become the last x position */
2545 if(likely(x != hashed_process_data->x.middle)) {
2546 hashed_process_data->x.middle = x;
2547 /* but don't use the pixel */
2548 hashed_process_data->x.middle_used = FALSE;
2549
2550 /* Calculate the next good time */
2551 convert_pixels_to_time(width, x+1, time_window,
2552 &hashed_process_data->next_good_time);
2553 }
2554 }
2555 }
2556 }
2557 }
2558 return;
2559}
2560
2561int before_chunk(void *hook_data, void *call_data)
2562{
2563 EventsRequest *events_request = (EventsRequest*)hook_data;
2564 LttvTracesetState *tss = (LttvTracesetState*)call_data;
2565 ControlFlowData *cfd = (ControlFlowData*)events_request->viewer_data;
2566#if 0
2567 /* Desactivate sort */
2568 gtk_tree_sortable_set_sort_column_id(
2569 GTK_TREE_SORTABLE(cfd->process_list->list_store),
2570 TRACE_COLUMN,
2571 GTK_SORT_ASCENDING);
2572#endif //0
2573 drawing_chunk_begin(events_request, tss);
2574
2575 return 0;
2576}
2577
2578int before_request(void *hook_data, void *call_data)
2579{
2580 EventsRequest *events_request = (EventsRequest*)hook_data;
2581 LttvTracesetState *tss = (LttvTracesetState*)call_data;
2582
2583 drawing_data_request_begin(events_request, tss);
2584
2585 return 0;
2586}
2587
2588
2589/*
2590 * after request is necessary in addition of after chunk in order to draw
2591 * lines until the end of the screen. after chunk just draws lines until
2592 * the last event.
2593 *
2594 * for each process
2595 * draw closing line
2596 * expose
2597 */
2598int after_request(void *hook_data, void *call_data)
2599{
2600 EventsRequest *events_request = (EventsRequest*)hook_data;
2601 ControlFlowData *control_flow_data = events_request->viewer_data;
2602 LttvTracesetState *tss = (LttvTracesetState*)call_data;
2603
2604 ProcessList *process_list = control_flow_data->process_list;
2605 LttTime end_time = events_request->end_time;
2606
2607 ClosureData closure_data;
2608 closure_data.events_request = (EventsRequest*)hook_data;
2609 closure_data.tss = tss;
2610 closure_data.end_time = end_time;
2611
2612 TimeWindow time_window =
2613 lttvwindow_get_time_window(control_flow_data->tab);
2614 guint width = control_flow_data->drawing->width;
2615 convert_time_to_pixels(
2616 time_window,
2617 end_time,
2618 width,
2619 &closure_data.x_end);
2620
2621
2622 /* Draw last items */
2623 g_hash_table_foreach(process_list->process_hash, draw_closure,
2624 (void*)&closure_data);
2625
2626
2627 /* Request expose */
2628 drawing_request_expose(events_request, tss, end_time);
2629 return 0;
2630}
2631
2632/*
2633 * for each process
2634 * draw closing line
2635 * expose
2636 */
2637int after_chunk(void *hook_data, void *call_data)
2638{
2639 EventsRequest *events_request = (EventsRequest*)hook_data;
2640 ControlFlowData *control_flow_data = events_request->viewer_data;
2641 LttvTracesetState *tss = (LttvTracesetState*)call_data;
2642 LttvTracesetContext *tsc = (LttvTracesetContext*)call_data;
2643 LttvTracefileContext *tfc = lttv_traceset_context_get_current_tfc(tsc);
2644 LttTime end_time;
2645
2646 ProcessList *process_list = control_flow_data->process_list;
2647 guint i;
2648 LttvTraceset *traceset = tsc->ts;
2649 guint nb_trace = lttv_traceset_number(traceset);
2650
2651 /* Only execute when called for the first trace's events request */
2652 if(!process_list->current_hash_data) return;
2653
2654 for(i = 0 ; i < nb_trace ; i++) {
2655 g_free(process_list->current_hash_data[i]);
2656 }
2657 g_free(process_list->current_hash_data);
2658 process_list->current_hash_data = NULL;
2659
2660 if(tfc != NULL)
2661 end_time = LTT_TIME_MIN(tfc->timestamp, events_request->end_time);
2662 else /* end of traceset, or position now out of request : end */
2663 end_time = events_request->end_time;
2664
2665 ClosureData closure_data;
2666 closure_data.events_request = (EventsRequest*)hook_data;
2667 closure_data.tss = tss;
2668 closure_data.end_time = end_time;
2669
2670 TimeWindow time_window =
2671 lttvwindow_get_time_window(control_flow_data->tab);
2672 guint width = control_flow_data->drawing->width;
2673 convert_time_to_pixels(
2674 time_window,
2675 end_time,
2676 width,
2677 &closure_data.x_end);
2678
2679 /* Draw last items */
2680 g_hash_table_foreach(process_list->process_hash, draw_closure,
2681 (void*)&closure_data);
2682#if 0
2683 /* Reactivate sort */
2684 gtk_tree_sortable_set_sort_column_id(
2685 GTK_TREE_SORTABLE(control_flow_data->process_list->list_store),
2686 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
2687 GTK_SORT_ASCENDING);
2688
2689 update_index_to_pixmap(control_flow_data->process_list);
2690 /* Request a full expose : drawing scrambled */
2691 gtk_widget_queue_draw(control_flow_data->drawing->drawing_area);
2692#endif //0
2693 /* Request expose (updates damages zone also) */
2694 drawing_request_expose(events_request, tss, end_time);
2695
2696 return 0;
2697}
2698
2699/* after_statedump_end
2700 *
2701 * @param hook_data ControlFlowData structure of the viewer.
2702 * @param call_data Event context.
2703 *
2704 * This function adds items to be drawn in a queue for each process.
2705 *
2706 */
2707int before_statedump_end(void *hook_data, void *call_data)
2708{
2709 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility*)hook_data;
2710 EventsRequest *events_request = (EventsRequest*)thf->hook_data;
2711 ControlFlowData *control_flow_data = events_request->viewer_data;
2712
2713 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
2714
2715 LttvTracefileState *tfs = (LttvTracefileState *)call_data;
2716
2717 LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
2718
2719 LttvTracesetState *tss = (LttvTracesetState*)tfc->t_context->ts_context;
2720 ProcessList *process_list = control_flow_data->process_list;
2721
2722 LttEvent *e;
2723 e = ltt_tracefile_get_event(tfc->tf);
2724
2725 LttvFilter *filter = control_flow_data->filter;
2726 if(filter != NULL && filter->head != NULL)
2727 if(!lttv_filter_tree_parse(filter->head,e,tfc->tf,
2728 tfc->t_context->t,tfc,NULL,NULL))
2729 return FALSE;
2730
2731 LttTime evtime = ltt_event_time(e);
2732
2733 ClosureData closure_data;
2734 closure_data.events_request = events_request;
2735 closure_data.tss = tss;
2736 closure_data.end_time = evtime;
2737
2738 TimeWindow time_window =
2739 lttvwindow_get_time_window(control_flow_data->tab);
2740 guint width = control_flow_data->drawing->width;
2741 convert_time_to_pixels(
2742 time_window,
2743 evtime,
2744 width,
2745 &closure_data.x_end);
2746
2747 /* Draw last items */
2748 g_hash_table_foreach(process_list->process_hash, draw_closure,
2749 (void*)&closure_data);
2750#if 0
2751 /* Reactivate sort */
2752 gtk_tree_sortable_set_sort_column_id(
2753 GTK_TREE_SORTABLE(control_flow_data->process_list->list_store),
2754 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
2755 GTK_SORT_ASCENDING);
2756
2757 update_index_to_pixmap(control_flow_data->process_list);
2758 /* Request a full expose : drawing scrambled */
2759 gtk_widget_queue_draw(control_flow_data->drawing->drawing_area);
2760#endif //0
2761 /* Request expose (updates damages zone also) */
2762 drawing_request_expose(events_request, tss, evtime);
2763
2764 return 0;
2765}
This page took 0.129268 seconds and 4 git commands to generate.