1 /*****************************************************************************
2 * Hooks to be called by the main window *
3 *****************************************************************************/
6 #define g_info(format...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, format)
7 #define g_debug(format...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, format)
9 //#define PANGO_ENABLE_BACKEND
16 //#include <pango/pango.h>
18 #include <ltt/event.h>
22 #include <lttv/hook.h>
23 #include <lttv/common.h>
24 #include <lttv/state.h>
27 #include "Event_Hooks.h"
29 #include "Process_List.h"
31 #include "CFV-private.h"
34 #define MAX_PATH_LEN 256
38 * Event Viewer's constructor hook
40 * This constructor is given as a parameter to the menuitem and toolbar button
41 * registration. It creates the list.
42 * @param pmParentWindow A pointer to the parent window.
43 * @return The widget created.
46 h_guicontrolflow(MainWindow
*pmParentWindow
, LttvTracesetSelector
* s
, char * key
)
48 g_info("h_guicontrolflow, %p, %p, %s", pmParentWindow
, s
, key
);
49 ControlFlowData
*Control_Flow_Data
= guicontrolflow() ;
51 Control_Flow_Data
->Parent_Window
= pmParentWindow
;
52 TimeWindow
*time_window
= guicontrolflow_get_time_window(Control_Flow_Data
);
53 time_window
->start_time
.tv_sec
= 0;
54 time_window
->start_time
.tv_nsec
= 0;
55 time_window
->time_width
.tv_sec
= 0;
56 time_window
->time_width
.tv_nsec
= 0;
58 LttTime
*current_time
= guicontrolflow_get_current_time(Control_Flow_Data
);
59 current_time
->tv_sec
= 0;
60 current_time
->tv_nsec
= 0;
62 //g_critical("time width1 : %u",time_window->time_width);
64 get_time_window(pmParentWindow
,
66 get_current_time(pmParentWindow
,
69 //g_critical("time width2 : %u",time_window->time_width);
70 // Unreg done in the GuiControlFlow_Destructor
71 reg_update_time_window(update_time_window_hook
, Control_Flow_Data
,
73 reg_update_current_time(update_current_time_hook
, Control_Flow_Data
,
75 return guicontrolflow_get_widget(Control_Flow_Data
) ;
79 int event_selected_hook(void *hook_data
, void *call_data
)
81 ControlFlowData
*Control_Flow_Data
= (ControlFlowData
*) hook_data
;
82 guint
*Event_Number
= (guint
*) call_data
;
84 g_critical("DEBUG : event selected by main window : %u", *Event_Number
);
86 // Control_Flow_Data->Currently_Selected_Event = *Event_Number;
87 // Control_Flow_Data->Selected_Event = TRUE ;
89 // tree_v_set_cursor(Control_Flow_Data);
93 /* Hook called before drawing. Gets the initial context at the beginning of the
94 * drawing interval and copy it to the context in Event_Request.
96 int draw_before_hook(void *hook_data
, void *call_data
)
98 EventRequest
*Event_Request
= (EventRequest
*)hook_data
;
99 //EventsContext Events_Context = (EventsContext*)call_data;
101 //Event_Request->Events_Context = Events_Context;
107 * The draw event hook is called by the reading API to have a
108 * particular event drawn on the screen.
109 * @param hook_data ControlFlowData structure of the viewer.
110 * @param call_data Event context.
112 * This function basically draw lines and icons. Two types of lines are drawn :
113 * one small (3 pixels?) representing the state of the process and the second
114 * type is thicker (10 pixels?) representing on which CPU a process is running
115 * (and this only in running state).
117 * Extremums of the lines :
118 * x_min : time of the last event context for this process kept in memory.
119 * x_max : time of the current event.
120 * y : middle of the process in the process list. The process is found in the
121 * list, therefore is it's position in pixels.
123 * The choice of lines'color is defined by the context of the last event for this
126 int draw_event_hook(void *hook_data
, void *call_data
)
128 EventRequest
*Event_Request
= (EventRequest
*)hook_data
;
129 ControlFlowData
*control_flow_data
= Event_Request
->Control_Flow_Data
;
133 //g_critical("%i", i);
134 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
136 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
143 GString
*string
= g_string_new("");;
144 gboolean field_names
= TRUE
, state
= TRUE
;
146 lttv_event_to_string(e
, tfc
->tf
, string
, TRUE
, field_names
, tfs
);
147 g_string_append_printf(string
,"\n");
150 g_string_append_printf(string
, " %s",
151 g_quark_to_string(tfs
->process
->state
->s
));
154 g_info("%s",string
->str
);
156 g_string_free(string
, TRUE
);
158 /* End of text dump */
161 /* Add process to process list (if not present) and get drawing "y" from
162 * process position */
163 guint pid
= tfs
->process
->pid
;
164 LttTime birth
= tfs
->process
->creation_time
;
165 gchar
*name
= strdup(g_quark_to_string(tfs
->process
->name
));
166 guint y
= 0, height
= 0, pl_height
= 0;
167 HashedProcessData
*Hashed_Process_Data
= NULL
;
169 ProcessList
*process_list
=
170 guicontrolflow_get_process_list(Event_Request
->Control_Flow_Data
);
172 if(processlist_get_process_pixels(process_list
,
177 &Hashed_Process_Data
) == 1)
179 /* Process not present */
180 processlist_add(process_list
,
185 &Hashed_Process_Data
);
187 drawing_insert_square( Event_Request
->Control_Flow_Data
->Drawing
, y
, height
);
190 /* Find pixels corresponding to time of the event. If the time does
191 * not fit in the window, show a warning, not supposed to happend. */
193 guint width
= control_flow_data
->Drawing
->Drawing_Area_V
->allocation
.width
;
195 LttTime time
= ltt_event_time(e
);
197 LttTime window_end
= ltt_time_add(control_flow_data
->Time_Window
.time_width
,
198 control_flow_data
->Time_Window
.start_time
);
201 convert_time_to_pixels(
202 control_flow_data
->Time_Window
.start_time
,
210 /* Finally, draw what represents the event. */
212 GdkColor color
= { 0, 0xffff, 0x0000, 0x0000 };
213 PropertiesArc prop_arc
;
214 prop_arc
.color
= &color
;
216 prop_arc
.filled
= TRUE
;
217 prop_arc
.position
= OVER
;
219 DrawContext
*draw_context
= Hashed_Process_Data
->draw_context
;
220 draw_context
->Current
->modify_over
->x
= x
;
221 draw_context
->Current
->modify_over
->y
= y
;
222 draw_context
->drawable
= control_flow_data
->Drawing
->Pixmap
;
223 draw_context
->pango_layout
= control_flow_data
->Drawing
->pango_layout
;
224 GtkWidget
*widget
= control_flow_data
->Drawing
->Drawing_Area_V
;
225 //draw_context->gc = widget->style->fg_gc[GTK_WIDGET_STATE (widget)];
226 draw_context
->gc
= widget
->style
->black_gc
;
228 //draw_arc((void*)&prop_arc, (void*)draw_context);
229 //test_draw_item(control_flow_data->Drawing, control_flow_data->Drawing->Pixmap);
231 //GdkColor colorfg = { 0, 0xffff, 0x0000, 0x0000 };
233 colorfg
.red
= 0xffff;
234 colorfg
.green
= 0x0000;
235 colorfg
.blue
= 0x0000;
236 //GdkColor colorbg = { 0, 0xffff, 0x0000, 0xffff };
238 colorbg
.red
= 0x0000;
239 colorbg
.green
= 0x0000;
240 colorbg
.blue
= 0x0000;
242 PropertiesText prop_text
;
243 prop_text
.foreground
= &colorfg
;
244 prop_text
.background
= &colorbg
;
246 prop_text
.position
= OVER
;
248 /* Print status of the process : U, WF, WC, E, W, R */
249 if(tfs
->process
->state
->s
== LTTV_STATE_UNNAMED
)
250 prop_text
.Text
= "U";
251 else if(tfs
->process
->state
->s
== LTTV_STATE_WAIT_FORK
)
252 prop_text
.Text
= "WF";
253 else if(tfs
->process
->state
->s
== LTTV_STATE_WAIT_CPU
)
254 prop_text
.Text
= "WC";
255 else if(tfs
->process
->state
->s
== LTTV_STATE_EXIT
)
256 prop_text
.Text
= "E";
257 else if(tfs
->process
->state
->s
== LTTV_STATE_WAIT
)
258 prop_text
.Text
= "W";
259 else if(tfs
->process
->state
->s
== LTTV_STATE_RUN
)
260 prop_text
.Text
= "R";
262 prop_text
.Text
= "U";
264 draw_text((void*)&prop_text
, (void*)draw_context
);
270 int draw_after_hook(void *hook_data
, void *call_data
)
272 EventRequest
*Event_Request
= (EventRequest
*)hook_data
;
273 ControlFlowData
*control_flow_data
= Event_Request
->Control_Flow_Data
;
275 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
277 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
283 if(strcmp(ltt_eventtype_name(ltt_event_eventtype(e
)),"schedchange") == 0)
285 g_critical("schedchange!");
287 /* Add process to process list (if not present) and get drawing "y" from
288 * process position */
289 guint pid_out
, pid_in
;
290 LttvProcessState
*process_out
, *process_in
;
292 guint y_in
= 0, y_out
= 0, height
= 0, pl_height
= 0;
294 ProcessList
*process_list
=
295 guicontrolflow_get_process_list(Event_Request
->Control_Flow_Data
);
298 LttField
*f
= ltt_event_field(e
);
300 element
= ltt_field_member(f
,0);
301 pid_out
= ltt_event_get_long_unsigned(e
,element
);
302 element
= ltt_field_member(f
,1);
303 pid_in
= ltt_event_get_long_unsigned(e
,element
);
304 g_critical("out : %u in : %u", pid_out
, pid_in
);
307 /* Find process pid_out in the list... */
308 process_out
= lttv_state_find_process(tfs
, pid_out
);
309 g_critical("out : %s",g_quark_to_string(process_out
->state
->s
));
311 birth
= process_out
->creation_time
;
312 gchar
*name
= strdup(g_quark_to_string(process_out
->name
));
313 HashedProcessData
*Hashed_Process_Data_out
= NULL
;
315 if(processlist_get_process_pixels(process_list
,
320 &Hashed_Process_Data_out
) == 1)
322 /* Process not present */
323 processlist_add(process_list
,
328 &Hashed_Process_Data_out
);
329 processlist_get_process_pixels(process_list
,
334 &Hashed_Process_Data_out
);
335 drawing_insert_square( Event_Request
->Control_Flow_Data
->Drawing
, y_out
, height
);
340 /* Find process pid_in in the list... */
341 process_in
= lttv_state_find_process(tfs
, pid_in
);
342 g_critical("in : %s",g_quark_to_string(process_in
->state
->s
));
344 birth
= process_in
->creation_time
;
345 name
= strdup(g_quark_to_string(process_in
->name
));
346 HashedProcessData
*Hashed_Process_Data_in
= NULL
;
348 if(processlist_get_process_pixels(process_list
,
353 &Hashed_Process_Data_in
) == 1)
355 /* Process not present */
356 processlist_add(process_list
,
361 &Hashed_Process_Data_in
);
362 processlist_get_process_pixels(process_list
,
367 &Hashed_Process_Data_in
);
369 drawing_insert_square( Event_Request
->Control_Flow_Data
->Drawing
, y_in
, height
);
374 /* Find pixels corresponding to time of the event. If the time does
375 * not fit in the window, show a warning, not supposed to happend. */
377 guint width
= control_flow_data
->Drawing
->Drawing_Area_V
->allocation
.width
;
379 LttTime time
= ltt_event_time(e
);
381 LttTime window_end
= ltt_time_add(control_flow_data
->Time_Window
.time_width
,
382 control_flow_data
->Time_Window
.start_time
);
385 convert_time_to_pixels(
386 control_flow_data
->Time_Window
.start_time
,
394 /* draw what represents the event for outgoing process. */
396 DrawContext
*draw_context_out
= Hashed_Process_Data_out
->draw_context
;
397 draw_context_out
->Current
->modify_over
->x
= x
;
398 draw_context_out
->Current
->modify_over
->y
= y_out
;
399 draw_context_out
->drawable
= control_flow_data
->Drawing
->Pixmap
;
400 draw_context_out
->pango_layout
= control_flow_data
->Drawing
->pango_layout
;
401 GtkWidget
*widget
= control_flow_data
->Drawing
->Drawing_Area_V
;
402 //draw_context_out->gc = widget->style->fg_gc[GTK_WIDGET_STATE (widget)];
403 draw_context_out
->gc
= widget
->style
->black_gc
;
405 //draw_arc((void*)&prop_arc, (void*)draw_context_out);
406 //test_draw_item(control_flow_data->Drawing, control_flow_data->Drawing->Pixmap);
408 GdkColor colorfg_out
= { 0, 0xffff, 0x0000, 0x0000 };
409 GdkColor colorbg_out
= { 0, 0xffff, 0xffff, 0xffff };
410 PropertiesText prop_text_out
;
411 prop_text_out
.foreground
= &colorfg_out
;
412 prop_text_out
.background
= &colorbg_out
;
413 prop_text_out
.size
= 10;
414 prop_text_out
.position
= OVER
;
416 /* Print status of the process : U, WF, WC, E, W, R */
417 if(process_out
->state
->s
== LTTV_STATE_UNNAMED
)
418 prop_text_out
.Text
= "U";
419 else if(process_out
->state
->s
== LTTV_STATE_WAIT_FORK
)
420 prop_text_out
.Text
= "WF";
421 else if(process_out
->state
->s
== LTTV_STATE_WAIT_CPU
)
422 prop_text_out
.Text
= "WC";
423 else if(process_out
->state
->s
== LTTV_STATE_EXIT
)
424 prop_text_out
.Text
= "E";
425 else if(process_out
->state
->s
== LTTV_STATE_WAIT
)
426 prop_text_out
.Text
= "W";
427 else if(process_out
->state
->s
== LTTV_STATE_RUN
)
428 prop_text_out
.Text
= "R";
430 prop_text_out
.Text
= "U";
432 draw_text((void*)&prop_text_out
, (void*)draw_context_out
);
434 /* Finally, update the drawing context of the pid_in. */
436 DrawContext
*draw_context_in
= Hashed_Process_Data_in
->draw_context
;
437 draw_context_in
->Current
->modify_over
->x
= x
;
438 draw_context_in
->Current
->modify_over
->y
= y_in
;
439 draw_context_in
->drawable
= control_flow_data
->Drawing
->Pixmap
;
440 draw_context_in
->pango_layout
= control_flow_data
->Drawing
->pango_layout
;
441 widget
= control_flow_data
->Drawing
->Drawing_Area_V
;
442 //draw_context_in->gc = widget->style->fg_gc[GTK_WIDGET_STATE (widget)];
443 draw_context_in
->gc
= widget
->style
->black_gc
;
445 //draw_arc((void*)&prop_arc, (void*)draw_context_in);
446 //test_draw_item(control_flow_data->Drawing, control_flow_data->Drawing->Pixmap);
448 GdkColor colorfg_in
= { 0, 0x0000, 0xffff, 0x0000 };
449 GdkColor colorbg_in
= { 0, 0xffff, 0xffff, 0xffff };
450 PropertiesText prop_text_in
;
451 prop_text_in
.foreground
= &colorfg_in
;
452 prop_text_in
.background
= &colorbg_in
;
453 prop_text_in
.size
= 10;
454 prop_text_in
.position
= OVER
;
456 /* Print status of the process : U, WF, WC, E, W, R */
457 if(process_in
->state
->s
== LTTV_STATE_UNNAMED
)
458 prop_text_in
.Text
= "U";
459 else if(process_in
->state
->s
== LTTV_STATE_WAIT_FORK
)
460 prop_text_in
.Text
= "WF";
461 else if(process_in
->state
->s
== LTTV_STATE_WAIT_CPU
)
462 prop_text_in
.Text
= "WC";
463 else if(process_in
->state
->s
== LTTV_STATE_EXIT
)
464 prop_text_in
.Text
= "E";
465 else if(process_in
->state
->s
== LTTV_STATE_WAIT
)
466 prop_text_in
.Text
= "W";
467 else if(process_in
->state
->s
== LTTV_STATE_RUN
)
468 prop_text_in
.Text
= "R";
470 prop_text_in
.Text
= "U";
472 draw_text((void*)&prop_text_in
, (void*)draw_context_in
);
482 void update_time_window_hook(void *hook_data
, void *call_data
)
484 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
485 TimeWindow
*Old_Time_Window
=
486 guicontrolflow_get_time_window(control_flow_data
);
487 TimeWindow
*New_Time_Window
= ((TimeWindow
*)call_data
);
489 /* Two cases : zoom in/out or scrolling */
491 /* In order to make sure we can reuse the old drawing, the scale must
492 * be the same and the new time interval being partly located in the
493 * currently shown time interval. (reuse is only for scrolling)
496 g_info("Old time window HOOK : %u, %u to %u, %u",
497 Old_Time_Window
->start_time
.tv_sec
,
498 Old_Time_Window
->start_time
.tv_nsec
,
499 Old_Time_Window
->time_width
.tv_sec
,
500 Old_Time_Window
->time_width
.tv_nsec
);
502 g_info("New time window HOOK : %u, %u to %u, %u",
503 New_Time_Window
->start_time
.tv_sec
,
504 New_Time_Window
->start_time
.tv_nsec
,
505 New_Time_Window
->time_width
.tv_sec
,
506 New_Time_Window
->time_width
.tv_nsec
);
508 if( New_Time_Window
->time_width
.tv_sec
== Old_Time_Window
->time_width
.tv_sec
509 && New_Time_Window
->time_width
.tv_nsec
== Old_Time_Window
->time_width
.tv_nsec
)
511 /* Same scale (scrolling) */
513 LttTime
*ns
= &New_Time_Window
->start_time
;
514 LttTime
*os
= &Old_Time_Window
->start_time
;
515 LttTime old_end
= ltt_time_add(Old_Time_Window
->start_time
,
516 Old_Time_Window
->time_width
);
517 LttTime new_end
= ltt_time_add(New_Time_Window
->start_time
,
518 New_Time_Window
->time_width
);
520 //if(ns<os+w && os+w<ns+w)
521 //if(ns<old_end && os<ns)
522 if(ltt_time_compare(*ns
, old_end
) == -1
523 && ltt_time_compare(*os
, *ns
) == -1)
525 g_info("scrolling near right");
526 /* Scroll right, keep right part of the screen */
528 guint width
= control_flow_data
->Drawing
->Drawing_Area_V
->allocation
.width
;
529 convert_time_to_pixels(
536 /* Copy old data to new location */
537 gdk_draw_drawable (control_flow_data
->Drawing
->Pixmap
,
538 control_flow_data
->Drawing
->Drawing_Area_V
->style
->white_gc
,
539 control_flow_data
->Drawing
->Pixmap
,
544 convert_time_to_pixels(
551 *Old_Time_Window
= *New_Time_Window
;
552 /* Clear the data request background, but not SAFETY */
553 gdk_draw_rectangle (control_flow_data
->Drawing
->Pixmap
,
554 control_flow_data
->Drawing
->Drawing_Area_V
->style
->white_gc
,
557 control_flow_data
->Drawing
->width
- x
, // do not overlap
558 control_flow_data
->Drawing
->height
+SAFETY
);
559 /* Get new data for the rest. */
560 drawing_data_request(control_flow_data
->Drawing
,
561 &control_flow_data
->Drawing
->Pixmap
,
563 control_flow_data
->Drawing
->width
- x
,
564 control_flow_data
->Drawing
->height
);
566 drawing_refresh(control_flow_data
->Drawing
,
568 control_flow_data
->Drawing
->width
,
569 control_flow_data
->Drawing
->height
);
574 //if(ns<os && os<ns+w)
575 //if(ns<os && os<new_end)
576 if(ltt_time_compare(*ns
,*os
) == -1
577 && ltt_time_compare(*os
,new_end
) == -1)
579 g_info("scrolling near left");
580 /* Scroll left, keep left part of the screen */
582 guint width
= control_flow_data
->Drawing
->Drawing_Area_V
->allocation
.width
;
583 convert_time_to_pixels(
590 /* Copy old data to new location */
591 gdk_draw_drawable (control_flow_data
->Drawing
->Pixmap
,
592 control_flow_data
->Drawing
->Drawing_Area_V
->style
->white_gc
,
593 control_flow_data
->Drawing
->Pixmap
,
598 *Old_Time_Window
= *New_Time_Window
;
600 /* Clean the data request background */
601 gdk_draw_rectangle (control_flow_data
->Drawing
->Pixmap
,
602 control_flow_data
->Drawing
->Drawing_Area_V
->style
->white_gc
,
606 control_flow_data
->Drawing
->height
+SAFETY
);
607 /* Get new data for the rest. */
608 drawing_data_request(control_flow_data
->Drawing
,
609 &control_flow_data
->Drawing
->Pixmap
,
612 control_flow_data
->Drawing
->height
);
614 drawing_refresh(control_flow_data
->Drawing
,
616 control_flow_data
->Drawing
->width
,
617 control_flow_data
->Drawing
->height
);
620 g_info("scrolling far");
621 /* Cannot reuse any part of the screen : far jump */
622 *Old_Time_Window
= *New_Time_Window
;
625 gdk_draw_rectangle (control_flow_data
->Drawing
->Pixmap
,
626 control_flow_data
->Drawing
->Drawing_Area_V
->style
->white_gc
,
629 control_flow_data
->Drawing
->width
+SAFETY
, // do not overlap
630 control_flow_data
->Drawing
->height
+SAFETY
);
632 drawing_data_request(control_flow_data
->Drawing
,
633 &control_flow_data
->Drawing
->Pixmap
,
635 control_flow_data
->Drawing
->width
,
636 control_flow_data
->Drawing
->height
);
638 drawing_refresh(control_flow_data
->Drawing
,
640 control_flow_data
->Drawing
->width
,
641 control_flow_data
->Drawing
->height
);
645 /* Different scale (zoom) */
648 *Old_Time_Window
= *New_Time_Window
;
650 gdk_draw_rectangle (control_flow_data
->Drawing
->Pixmap
,
651 control_flow_data
->Drawing
->Drawing_Area_V
->style
->white_gc
,
654 control_flow_data
->Drawing
->width
+SAFETY
, // do not overlap
655 control_flow_data
->Drawing
->height
+SAFETY
);
658 drawing_data_request(control_flow_data
->Drawing
,
659 &control_flow_data
->Drawing
->Pixmap
,
661 control_flow_data
->Drawing
->width
,
662 control_flow_data
->Drawing
->height
);
664 drawing_refresh(control_flow_data
->Drawing
,
666 control_flow_data
->Drawing
->width
,
667 control_flow_data
->Drawing
->height
);
673 void update_current_time_hook(void *hook_data
, void *call_data
)
675 ControlFlowData
*Control_Flow_Data
= (ControlFlowData
*) hook_data
;
676 LttTime
* Current_Time
=
677 guicontrolflow_get_current_time(Control_Flow_Data
);
678 *Current_Time
= *((LttTime
*)call_data
);
679 g_info("New Current time HOOK : %u, %u", Current_Time
->tv_sec
,
680 Current_Time
->tv_nsec
);
682 /* If current time is inside time interval, just move the highlight
685 /* Else, we have to change the time interval. We have to tell it
686 * to the main window. */
687 /* The time interval change will take care of placing the current
688 * time at the center of the visible area */