1 /*! \defgroup guiEvents libguiControlFlow: The GUI ControlFlow display plugin */
4 /*! \file guiControlFlow.c
5 * \brief Graphical plugin for showing control flow of a trace.
7 * This plugin adds a Control Flow Viewer functionnality to Linux TraceToolkit
8 * GUI when this plugin is loaded. The init and destroy functions add the
9 * viewer's insertion menu item and toolbar icon by calling gtkTraceSet's
10 * API functions. Then, when a viewer's object is created, the constructor
11 * creates ans register through API functions what is needed to interact
12 * with the TraceSet window.
14 * This plugin uses the gdk library to draw the events and gtk to interact
17 * Author : Mathieu Desnoyers, June 2003
25 #include <lttv/hook.h>
26 #include <lttv/module.h>
28 //#include "guiControlFlow.h"
29 #include "icons/hGuiControlFlowInsert.xpm"
31 #include "gtktreeprivate.h"
33 //FIXME by including ltt.h
35 typedef time_t ltt_time
;
37 typedef struct _ltt_time_interval
39 ltt_time time_begin
, time_end
;
43 /*****************************************************************************
44 * Definition of structures *
45 *****************************************************************************/
47 typedef struct _DrawingAreaInfo
{
53 typedef struct _ControlFlowData
{
55 GtkWidget
*Drawing_Area_V
;
56 GtkWidget
*Scrolled_Window_VC
;
58 GtkWidget
*Process_List_VC
;
60 /* Model containing list data */
61 GtkListStore
*Store_M
;
64 GtkWidget
*Inside_HBox_V
;
66 GtkAdjustment
*VAdjust_C
;
68 /* Trace information */
70 TraceStatistics
*Trace_Statistics
;
72 /* Shown events information */
73 guint First_Event
, Last_Event
;
74 ltt_time Begin_Time
, End_Time
;
77 /* Drawing Area Info */
78 DrawingAreaInfo Drawing_Area_Info
;
80 /* TEST DATA, TO BE READ FROM THE TRACE */
81 gint Number_Of_Events
;
82 guint Currently_Selected_Event
;
83 gboolean Selected_Event
;
84 guint Number_Of_Process
;
88 /* Structure used to store and use information relative to one events refresh
89 * request. Typically filled in by the expose event callback, then passed to the
90 * library call, then used by the drawing hooks. Then, once all the events are
91 * sent, it is freed by the hook called after the reading.
93 typedef struct _EventRequest
95 ControlFlowData
*Control_Flow_Data
;
96 ltt_time time_begin
, time_end
;
97 /* Fill the Events_Context during the initial expose, before calling for
100 GArray Events_Context
; //FIXME
104 /** Array containing instanced objects. Used when module is unloaded */
105 static GSList
*sControl_Flow_Data_List
= NULL
;
108 /*****************************************************************************
109 * Function prototypes *
110 *****************************************************************************/
111 //! Control Flow Viewer's constructor hook
112 GtkWidget
*hGuiControlFlow(GtkWidget
*pmParentWindow
);
113 //! Control Flow Viewer's constructor
114 ControlFlowData
*GuiControlFlow(void);
115 //! Control Flow Viewer's destructor
116 void GuiControlFlow_Destructor(ControlFlowData
*Control_Flow_Data
);
119 static int Event_Selected_Hook(void *hook_data
, void *call_data
);
126 Draw_Before_Hook(void *hook_data
, void *call_data
)
127 Draw_Event_Hook(void *hook_data
, void *call_data
)
128 Draw_After_Hook(void *hook_data
, void *call_data
)
131 //void Tree_V_set_cursor(ControlFlowData *Control_Flow_Data);
132 //void Tree_V_get_cursor(ControlFlowData *Control_Flow_Data);
134 /* Prototype for selection handler callback */
135 //static void tree_selection_changed_cb (GtkTreeSelection *selection, gpointer data);
136 static void v_scroll_cb (GtkAdjustment
*adjustment
, gpointer data
);
137 //static void Tree_V_size_allocate_cb (GtkWidget *widget, GtkAllocation *alloc, gpointer data);
138 //static void Tree_V_size_request_cb (GtkWidget *widget, GtkRequisition *requisition, gpointer data);
139 //static void Tree_V_cursor_changed_cb (GtkWidget *widget, gpointer data);
140 //static void Tree_V_move_cursor_cb (GtkWidget *widget, GtkMovementStep arg1, gint arg2, gpointer data);
142 static void expose_event_cb (GtkWidget
*widget
, GdkEventExpose
*expose
, gpointer data
);
144 void add_test_process(ControlFlowData
*Control_Flow_Data
);
146 static void get_test_data(guint Event_Number
, guint List_Height
,
147 ControlFlowData
*Control_Flow_Data
);
149 void add_test_data(ControlFlowData
*Control_Flow_Data
);
150 void test_draw(ControlFlowData
*Control_Flow_Data
);
152 void Drawing_Area_Init(ControlFlowData
*Control_Flow_Data
);
156 /*****************************************************************************
157 * Functions for module loading/unloading *
158 *****************************************************************************/
160 * plugin's init function
162 * This function initializes the Control Flow Viewer functionnality through the
165 G_MODULE_EXPORT
void init() {
166 g_critical("GUI ControlFlow Viewer init()");
168 /* Register the toolbar insert button */
169 //ToolbarItemReg(guiEventsInsert_xpm, "Insert Control Flow Viewer", guiEvent);
171 /* Register the menu item insert entry */
172 //MenuItemReg("/", "Insert Control Flow Viewer", guiEvent);
174 /* Setup the hooks */
175 Draw_Before_Hooks
= lttv_hooks_new();
176 Draw_Event_Hooks
= lttv_hooks_new();
177 Draw_After_Hooks
= lttv_hooks_new();
179 lttv_hooks_add(Draw_Before_Hooks
, Draw_Before_Hook
, NULL
);
180 lttv_hooks_add(Draw_Event_Hooks
, Draw_Event_Hook
, NULL
);
181 lttv_hooks_add(Draw_After_Hooks
, Draw_After_Hook
, NULL
);
185 void destroy_walk(gpointer data
, gpointer user_data
)
187 GuiControlFlow_Destructor((ControlFlowData
*)data
);
193 * plugin's destroy function
195 * This function releases the memory reserved by the module and unregisters
196 * everything that has been registered in the gtkTraceSet API.
198 G_MODULE_EXPORT
void destroy() {
199 g_critical("GUI Control Flow Viewer destroy()");
202 ControlFlowData
*Control_Flow_Data
;
204 g_critical("GUI Event Viewer destroy()");
206 g_slist_foreach(sControl_Flow_Data_List
, destroy_walk
, NULL
);
208 lttv_hooks_destroy(Draw_Before_Hooks
);
209 lttv_hooks_destroy(Draw_Event_Hooks
);
210 lttv_hooks_destroy(Draw_After_Hooks
);
212 /* Unregister the toolbar insert button */
213 //ToolbarItemUnreg(hGuiEvents);
215 /* Unregister the menu item insert entry */
216 //MenuItemUnreg(hGuiEvents);
220 /*****************************************************************************
221 * Control Flow Viewer class implementation *
222 *****************************************************************************/
225 /* Enumeration of the columns */
235 * Control Flow Viewer's constructor
237 * This constructor is given as a parameter to the menuitem and toolbar button
238 * registration. It creates the drawing widget.
239 * @param ParentWindow A pointer to the parent window.
240 * @return The widget created.
246 GtkTreeViewColumn
*column
;
247 GtkCellRenderer
*renderer
;
249 ControlFlowData
* Control_Flow_Data
= g_new(ControlFlowData
,1) ;
250 Control_Flow_Data
->Drawing_Area_V
= gtk_drawing_area_new ();
253 /* TEST DATA, TO BE READ FROM THE TRACE */
254 Control_Flow_Data
->Number_Of_Events
= 1000 ;
255 Control_Flow_Data
->Currently_Selected_Event
= FALSE
;
256 Control_Flow_Data
->Selected_Event
= 0;
257 Control_Flow_Data
->Number_Of_Process
= 10;
259 /* FIXME register Event_Selected_Hook */
263 /* Create the Process list */
264 Control_Flow_Data
->Store_M
= gtk_list_store_new ( N_COLUMNS
,
268 Control_Flow_Data
->Process_List_VC
= gtk_tree_view_new_with_model (GTK_TREE_MODEL (Control_Flow_Data
->Store_M
));
270 g_object_unref (G_OBJECT (Control_Flow_Data
->Store_M
));
272 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(Control_Flow_Data
->Process_List_VC
), FALSE
);
274 /* Create a column, associating the "text" attribute of the
275 * cell_renderer to the first column of the model */
276 /* Columns alignment : 0.0 : Left 0.5 : Center 1.0 : Right */
277 renderer
= gtk_cell_renderer_text_new ();
278 column
= gtk_tree_view_column_new_with_attributes ("Process",
280 "text", PROCESS_COLUMN
,
282 gtk_tree_view_column_set_alignment (column
, 0.0);
283 gtk_tree_view_column_set_fixed_width (column
, 45);
284 gtk_tree_view_append_column (GTK_TREE_VIEW (Control_Flow_Data
->Process_List_VC
), column
);
288 Control_Flow_Data
->Inside_HBox_V
= gtk_hbox_new(0, 0);
290 gtk_box_pack_start(GTK_BOX(Control_Flow_Data
->Inside_HBox_V
), Control_Flow_Data
->Process_List_VC
, FALSE
, TRUE
, 0);
291 gtk_box_pack_start(GTK_BOX(Control_Flow_Data
->Inside_HBox_V
), Control_Flow_Data
->Drawing_Area_V
, TRUE
, TRUE
, 0);
294 Control_Flow_Data
->VAdjust_C
= GTK_ADJUSTMENT(gtk_adjustment_new(0.0, /* Value */
299 0.0 )); /* page size */
302 Control_Flow_Data
->Scrolled_Window_VC
= gtk_scrolled_window_new (NULL
,
303 Control_Flow_Data
->VAdjust_C
);
304 gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(Control_Flow_Data
->Scrolled_Window_VC
) ,
306 GTK_POLICY_AUTOMATIC
);
308 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(Control_Flow_Data
->Scrolled_Window_VC
),
309 Control_Flow_Data
->Inside_HBox_V
);
312 g_signal_connect (G_OBJECT (Control_Flow_Data
->Drawing_Area_V
), "expose_event",
313 G_CALLBACK (expose_event_cb
), Control_Flow_Data
);
317 g_signal_connect (G_OBJECT (Control_Flow_Data
->VAdjust_C
), "value-changed",
318 G_CALLBACK (v_scroll_cb
),
321 add_test_process(Control_Flow_Data
);
325 /* Set the size of the drawing area */
326 Drawing_Area_Init(Control_Flow_Data
);
328 /* Get trace statistics */
329 Control_Flow_Data
->Trace_Statistics
= get_trace_statistics(Trace
);
332 gtk_widget_show(Control_Flow_Data
->Drawing_Area_V
);
333 gtk_widget_show(Control_Flow_Data
->Process_List_VC
);
334 gtk_widget_show(Control_Flow_Data
->Inside_HBox_V
);
335 gtk_widget_show(Control_Flow_Data
->Scrolled_Window_VC
);
337 test_draw(Control_Flow_Data
);
339 return Control_Flow_Data
;
344 GuiControlFlow_Destructor(ControlFlowData
*Control_Flow_Data
)
348 /* May already been done by GTK window closing */
349 if(GTK_IS_WIDGET(Control_Flow_Data
->HBox_V
))
350 gtk_widget_destroy(Control_Flow_Data
->HBox_V
);
352 /* Destroy the Tree View */
353 //gtk_widget_destroy(Control_Flow_Data->Tree_V);
355 /* Clear raw event list */
356 //gtk_list_store_clear(Control_Flow_Data->Store_M);
357 //gtk_widget_destroy(GTK_WIDGET(Control_Flow_Data->Store_M));
359 g_slist_remove(sControl_Flow_Data_List
,Control_Flow_Data
);
362 //FIXME : call hGuiEvents_Destructor for corresponding data upon widget destroy
366 /*****************************************************************************
367 * Drawing functions *
368 *****************************************************************************/
380 /* Vector of unallocated colors */
381 static GdkColor CF_Colors
[] =
383 { 0, 0xffff, 0x0000, 0x0000 }, // RED
384 { 0, 0x0000, 0xffff, 0x0000 }, // GREEN
385 { 0, 0x0000, 0x0000, 0xffff }, // BLUE
386 { 0, 0xffff, 0xffff, 0xffff }, // WHITE
387 { 0, 0x0000, 0x0000, 0x0000 } // BLACK
391 gint
get_cell_height(GtkTreeView
*TreeView
)
394 GtkTreeViewColumn
*Column
= gtk_tree_view_get_column(TreeView
, 0);
395 GList
*Render_List
= gtk_tree_view_column_get_cell_renderers(Column
);
396 GtkCellRenderer
*Renderer
= g_list_first(Render_List
)->data
;
398 gtk_tree_view_column_cell_get_size(Column
, NULL
, NULL
, NULL
, NULL
, &height
);
399 g_critical("cell 0 height : %u",height
);
405 /* get_time_from_pixels
407 * Get the time interval from window time and pixels, and pixels requested. This
408 * function uses TimeMul, which should only be used if the float value is lower
409 * that 4, and here it's always lower than 1, so it's ok.
411 void get_time_from_pixels(guint area_x
, guint area_width
,
413 ltt_time
&window_time_begin
, ltt_time
&window_time_end
,
414 ltt_time
&time_begin
, ltt_time
&time_end
)
416 ltt_time window_time_interval
;
418 TimeSub(window_time_interval
, window_time_end
, window_time_begin
);
421 TimeMul(time_begin
, window_time_interval
, (area_x
/(float)window_width
));
422 TimeAdd(time_begin
, window_time_begin
, time_begin
);
424 TimeMul(time_end
, window_time_interval
, (area_width
/(float)window_width
));
425 TimeAdd(time_end
, time_begin
, time_end
);
429 void Drawing_Area_Init(ControlFlowData
*Control_Flow_Data
)
431 DrawingAreaInfo
*Drawing_Area_Info
= &Control_Flow_Data
->Drawing_Area_Info
;
437 Drawing_Area_Info
->height
=
438 get_cell_height(GTK_TREE_VIEW(Control_Flow_Data
->Process_List_VC
))
439 * Control_Flow_Data
->Number_Of_Process
;
441 gtk_widget_modify_bg(Control_Flow_Data
->Drawing_Area_V
,
446 gtk_widget_set_size_request (Control_Flow_Data
->Drawing_Area_V
,
448 Drawing_Area_Info
->height
);
455 void add_test_process(ControlFlowData
*Control_Flow_Data
)
459 gchar
*process
[] = { "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten" };
461 for(i
=0; i
<Control_Flow_Data
->Number_Of_Process
; i
++)
463 /* Add a new row to the model */
464 gtk_list_store_append (Control_Flow_Data
->Store_M
, &iter
);
465 gtk_list_store_set (Control_Flow_Data
->Store_M
, &iter
,
466 PROCESS_COLUMN
, process
[i
],
474 void test_draw(ControlFlowData
*Control_Flow_Data
)
476 /* Draw event states using available height, Number of process, cell height
477 * (don't forget to remove two pixels at beginning and end).
478 * For horizontal : use width, Time_Begin, Time_End.
479 * This function calls the reading library to get the draw_hook called
480 * for the desired period of time. */
482 DrawingAreaInfo
*Drawing_Area_Info
= &Control_Flow_Data
->Drawing_Area_Info
;
488 /*****************************************************************************
489 * Hooks to be called by the main window *
490 *****************************************************************************/
492 * Event Viewer's constructor hook
494 * This constructor is given as a parameter to the menuitem and toolbar button
495 * registration. It creates the list.
496 * @param pmParentWindow A pointer to the parent window.
497 * @return The widget created.
500 hGuiControlFlow(GtkWidget
*pmParentWindow
)
502 ControlFlowData
* Control_Flow_Data
= GuiControlFlow() ;
504 return Control_Flow_Data
->HBox_V
;
508 int Event_Selected_Hook(void *hook_data
, void *call_data
)
510 ControlFlowData
*Control_Flow_Data
= (ControlFlowData
*) hook_data
;
511 guint
*Event_Number
= (guint
*) call_data
;
513 g_critical("DEBUG : event selected by main window : %u", *Event_Number
);
515 // Control_Flow_Data->Currently_Selected_Event = *Event_Number;
516 // Control_Flow_Data->Selected_Event = TRUE ;
518 // Tree_V_set_cursor(Control_Flow_Data);
523 /* Hook called before drawing. Gets the initial context at the beginning of the
524 * drawing interval and copy it to the context in Event_Request.
526 Draw_Before_Hook(void *hook_data
, void *call_data
)
528 EventRequest
*Event_Request
= (EventRequest
*)hook_data
;
529 EventsContext Events_Context
= (EventsContext
*)call_data
;
531 Event_Request
->Events_Context
= Events_Context
;
535 * The draw event hook is called by the reading API to have a
536 * particular event drawn on the screen.
537 * @param hook_data ControlFlowData structure of the viewer.
538 * @param call_data Event context.
540 * This function basically draw lines and icons. Two types of lines are drawn :
541 * one small (3 pixels?) representing the state of the process and the second
542 * type is thicker (10 pixels?) representing on which CPU a process is running
543 * (and this only in running state).
545 * Extremums of the lines :
546 * x_min : time of the last event context for this process kept in memory.
547 * x_max : time of the current event.
548 * y : middle of the process in the process list. The process is found in the
549 * list, therefore is it's position in pixels.
551 * The choice of lines'color is defined by the context of the last event for this
554 Draw_Event_Hook(void *hook_data
, void *call_data
)
556 EventRequest
*Event_Request
= (EventRequest
*)hook_data
;
561 Draw_After_Hook(void *hook_data
, void *call_data
)
563 EventRequest
*Event_Request
= (EventRequest
*)hook_data
;
565 g_free(Event_Request
);
568 /*****************************************************************************
569 * Callbacks used for the viewer *
570 *****************************************************************************/
571 void expose_event_cb (GtkWidget
*widget
, GdkEventExpose
*expose
, gpointer data
)
573 ControlFlowData
*Control_Flow_Data
= (ControlFlowData
*)data
;
575 EventRequest
*Event_Request
= g_new(sizeof(EventRequest
));
577 Event_Request
->Control_Flow_Data
= Control_Flow_Data
;
579 /* Calculate, from pixels in expose, the time interval to get data */
581 get_time_from_pixels(expose
->area
.x
, expose
->area
.width
,
582 Control_Flow_Data
->Drawing_Area_Info
.width
,
583 &Control_Flow_Data
->Begin_Time
, &Control_Flow_Data
->End_Time
,
584 &Event_Request
->time_begin
, &Event_Request
->time_end
)
586 /* Look in statistics of the trace the processes present during the
587 * whole time interval _shown on the screen_. Modify the list of
588 * processes to match it. NOTE : modify, not recreate. If recreation is
589 * needed,keep a pointer to the currently selected event in the list.
592 /* Call the reading API to have events sent to drawing hooks */
593 lttv_trace_set_process( Control_Flow_Data
->Trace_Set
,
597 NULL
, //FIXME : filter here
598 Event_Request
->time_begin
,
599 Event_Request
->time_end
);
605 gint cell_height
= get_cell_height(GTK_TREE_VIEW(Control_Flow_Data
->Process_List_VC
));
606 GdkGC
*GC
= gdk_gc_new(widget
->window
);
607 GdkColor color
= CF_Colors
[GREEN
];
609 gdk_color_alloc (gdk_colormap_get_system () , &color
);
611 g_critical("expose");
613 /* When redrawing, use widget->allocation.width to get the width of
615 Control_Flow_Data
->Drawing_Area_Info
.width
= widget
->allocation
.width
;
617 test_draw(Control_Flow_Data
);
619 gdk_gc_copy(GC
,widget
->style
->white_gc
);
620 gdk_gc_set_foreground(GC
,&color
);
622 //gdk_draw_arc (widget->window,
623 // widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
625 // //0, 0, widget->allocation.width, widget->allocation.height,
626 // 0, 0, widget->allocation.width,
627 // Control_Flow_Data->Drawing_Area_Info.height,
631 //Drawing_Area_Init(Control_Flow_Data);
633 // 2 pixels for the box around the drawing area, 1 pixel for off-by-one
635 //gdk_gc_copy (&GC, widget->style->fg_gc[GTK_WIDGET_STATE (widget)]);
637 gdk_gc_set_line_attributes(GC
,12, GDK_LINE_SOLID
, GDK_CAP_NOT_LAST
,GDK_JOIN_MITER
);
639 gdk_draw_line (widget
->window
,
641 0, (cell_height
-1)/2,
642 widget
->allocation
.width
, (cell_height
-1)/2);
644 color
= CF_Colors
[BLUE
];
646 gdk_color_alloc (gdk_colormap_get_system () , &color
);
648 gdk_gc_set_foreground(GC
,&color
);
651 gdk_gc_set_line_attributes(GC
,3, GDK_LINE_SOLID
, GDK_CAP_NOT_LAST
,GDK_JOIN_MITER
);
653 gdk_draw_line (widget
->window
,
655 0, (cell_height
-1)/2,
656 widget
->allocation
.width
,(cell_height
-1)/2);
665 //gdk_colormap_alloc_colors(gdk_colormap_get_system(), TRUE,
667 //gdk_gc_set_line_attributes(GC,5, GDK_LINE_SOLID, GDK_CAP_NOT_LAST,GDK_JOIN_MITER);
668 //gdk_gc_set_foreground(GC,
670 //gdk_draw_line (widget->window,
672 // 0, (2*cell_height)-2-1,
673 // 50, (2*cell_height)-2-1);
678 void v_scroll_cb (GtkAdjustment
*adjustment
, gpointer data
)
680 ControlFlowData
*Control_Flow_Data
= (ControlFlowData
*)data
;
681 GtkTreePath
*Tree_Path
;
683 g_critical("DEBUG : scroll signal, value : %f", adjustment
->value
);
685 //get_test_data((int)adjustment->value, Control_Flow_Data->Num_Visible_Events,
686 // Control_Flow_Data);
697 static void destroy_cb( GtkWidget
*widget
,
705 /*****************************************************************************
707 *****************************************************************************/
710 int main(int argc
, char **argv
)
713 GtkWidget
*CF_Viewer
;
715 GtkWidget
*HScroll_VC
;
716 ControlFlowData
*Control_Flow_Data
;
718 /* Horizontal scrollbar and it's adjustment */
719 GtkWidget
*VScroll_VC
;
720 GtkAdjustment
*VAdjust_C
;
722 /* Initialize i18n support */
725 /* Initialize the widget set */
726 gtk_init (&argc
, &argv
);
730 Window
= gtk_window_new (GTK_WINDOW_TOPLEVEL
);
731 gtk_window_set_title (GTK_WINDOW (Window
), ("Test Window"));
733 g_signal_connect (G_OBJECT (Window
), "destroy",
734 G_CALLBACK (destroy_cb
), NULL
);
737 VBox_V
= gtk_vbox_new(0, 0);
738 gtk_container_add (GTK_CONTAINER (Window
), VBox_V
);
740 //ListViewer = hGuiEvents(Window);
741 //gtk_box_pack_start(GTK_BOX(VBox_V), ListViewer, TRUE, TRUE, 0);
743 //ListViewer = hGuiEvents(Window);
744 //gtk_box_pack_start(GTK_BOX(VBox_V), ListViewer, FALSE, TRUE, 0);
746 Control_Flow_Data
= GuiControlFlow();
747 CF_Viewer
= Control_Flow_Data
->Scrolled_Window_VC
;
748 gtk_box_pack_start(GTK_BOX(VBox_V
), CF_Viewer
, TRUE
, TRUE
, 0);
750 /* Create horizontal scrollbar and pack it */
751 HScroll_VC
= gtk_hscrollbar_new(NULL
);
752 gtk_box_pack_start(GTK_BOX(VBox_V
), HScroll_VC
, FALSE
, TRUE
, 0);
755 gtk_widget_show (HScroll_VC
);
756 gtk_widget_show (VBox_V
);
757 gtk_widget_show (Window
);
759 //Event_Selected_Hook(Control_Flow_Data, &ev_sel);
763 g_critical("main loop finished");
765 //hGuiEvents_Destructor(ListViewer);
767 //g_critical("GuiEvents Destructor finished");