fork resourceview dir from controlflow view
authorpmf <pmf@04897980-b3bd-0310-b5e0-8ef037075253>
Tue, 31 Jul 2007 19:46:12 +0000 (19:46 +0000)
committerpmf <pmf@04897980-b3bd-0310-b5e0-8ef037075253>
Tue, 31 Jul 2007 19:46:12 +0000 (19:46 +0000)
git-svn-id: http://ltt.polymtl.ca/svn@2555 04897980-b3bd-0310-b5e0-8ef037075253

18 files changed:
ltt/branches/poly/lttv/modules/gui/Makefile.am
ltt/branches/poly/lttv/modules/gui/resourceview/Makefile.am [new file with mode: 0644]
ltt/branches/poly/lttv/modules/gui/resourceview/cfv.c [new file with mode: 0644]
ltt/branches/poly/lttv/modules/gui/resourceview/cfv.h [new file with mode: 0644]
ltt/branches/poly/lttv/modules/gui/resourceview/drawing.c [new file with mode: 0644]
ltt/branches/poly/lttv/modules/gui/resourceview/drawing.h [new file with mode: 0644]
ltt/branches/poly/lttv/modules/gui/resourceview/drawitem.c [new file with mode: 0644]
ltt/branches/poly/lttv/modules/gui/resourceview/drawitem.h [new file with mode: 0644]
ltt/branches/poly/lttv/modules/gui/resourceview/eventhooks.c [new file with mode: 0644]
ltt/branches/poly/lttv/modules/gui/resourceview/eventhooks.h [new file with mode: 0644]
ltt/branches/poly/lttv/modules/gui/resourceview/hGuiControlFlowInsert.xpm [new file with mode: 0644]
ltt/branches/poly/lttv/modules/gui/resourceview/hLegendInsert.xpm [new file with mode: 0644]
ltt/branches/poly/lttv/modules/gui/resourceview/lttv_plugin_cfv.c [new file with mode: 0644]
ltt/branches/poly/lttv/modules/gui/resourceview/lttv_plugin_cfv.h [new file with mode: 0644]
ltt/branches/poly/lttv/modules/gui/resourceview/module.c [new file with mode: 0644]
ltt/branches/poly/lttv/modules/gui/resourceview/processlist.c [new file with mode: 0644]
ltt/branches/poly/lttv/modules/gui/resourceview/processlist.h [new file with mode: 0644]
ltt/branches/poly/lttv/modules/gui/resourceview/test.c [new file with mode: 0644]

index e92b6fcb84cec204151c440d90f99162b49ce4a8..0b25cb35f58b782998a839ad75c6c987b1c78961 100644 (file)
@@ -6,7 +6,7 @@
 
 # WARNING : subdirs order is important : mainWin depends on API
 
-SUBDIRS = lttvwindow controlflow detailedevents statistics filter tracecontrol interrupts diskperformance histogram tutorial
+SUBDIRS = lttvwindow controlflow detailedevents statistics filter tracecontrol interrupts diskperformance histogram tutorial resourceview
 
 
 
diff --git a/ltt/branches/poly/lttv/modules/gui/resourceview/Makefile.am b/ltt/branches/poly/lttv/modules/gui/resourceview/Makefile.am
new file mode 100644 (file)
index 0000000..d70b838
--- /dev/null
@@ -0,0 +1,38 @@
+# This file is part of the Linux Trace Toolkit viewer
+# Copyright (C) 2003-2004 Mathieu Desnoyers
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License Version 2 as
+# published by the Free Software Foundation;
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, 
+# MA 02111-1307, USA.
+
+
+#
+# Makefile for LTT New generation user interface : plugins.
+#
+# Created by Mathieu Desnoyers on September 27, 2003
+#
+
+AM_CFLAGS = $(GLIB_CFLAGS) 
+AM_CFLAGS += $(GTK_CFLAGS)
+LIBS += $(GLIB_LIBS)
+LIBS += $(GTK_LIBS) -L${top_builddir}/lttv/modules/gui/lttvwindow/lttvwindow -llttvwindow
+
+libdir = ${lttvplugindir}
+
+lib_LTLIBRARIES = libresourceview.la
+libguicontrolflow_la_LDFLAGS = -module -avoid-version
+libguicontrolflow_la_SOURCES =         module.c eventhooks.c cfv.c processlist.c drawing.c drawitem.c lttv_plugin_cfv.c
+
+noinst_HEADERS = eventhooks.h cfv.h processlist.h drawing.h drawitem.h lttv_plugin_cfv.h
+
+EXTRA_DIST = hGuiControlFlowInsert.xpm hLegendInsert.xpm
diff --git a/ltt/branches/poly/lttv/modules/gui/resourceview/cfv.c b/ltt/branches/poly/lttv/modules/gui/resourceview/cfv.c
new file mode 100644 (file)
index 0000000..f7a2582
--- /dev/null
@@ -0,0 +1,359 @@
+/* This file is part of the Linux Trace Toolkit viewer
+ * Copyright (C) 2003-2004 Mathieu Desnoyers
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License Version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, 
+ * MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include <gtk/gtk.h>
+#include <gdk/gdk.h>
+#include <lttv/lttv.h>
+#include <lttvwindow/lttvwindow.h>
+#include <lttvwindow/lttvwindowtraces.h>
+#include <lttvwindow/support.h>
+
+#include "cfv.h"
+#include "drawing.h"
+#include "processlist.h"
+#include "eventhooks.h"
+#include "lttv_plugin_cfv.h"
+
+extern GSList *g_control_flow_data_list;
+
+static gboolean
+header_size_allocate(GtkWidget *widget,
+                        GtkAllocation *allocation,
+                        gpointer user_data)
+{
+  Drawing_t *drawing = (Drawing_t*)user_data;
+
+  gtk_widget_set_size_request(drawing->ruler, -1, allocation->height);
+  //gtk_widget_queue_resize(drawing->padding);
+  //gtk_widget_queue_resize(drawing->ruler);
+  gtk_container_check_resize(GTK_CONTAINER(drawing->ruler_hbox));
+  return 0;
+}
+
+gboolean cfv_scroll_event(GtkWidget *widget, GdkEventScroll *event,
+    gpointer data)
+{
+  ControlFlowData *control_flow_data = (ControlFlowData*)data;
+  unsigned int cell_height =
+    get_cell_height(
+        GTK_TREE_VIEW(control_flow_data->process_list->process_list_widget));
+  gdouble new;
+
+  switch(event->direction) {
+    case GDK_SCROLL_UP:
+      {
+        new = gtk_adjustment_get_value(control_flow_data->v_adjust) 
+                                  - cell_height;
+      }
+      break;
+    case GDK_SCROLL_DOWN:
+      {
+        new = gtk_adjustment_get_value(control_flow_data->v_adjust) 
+                                  + cell_height;
+      }
+      break;
+    default:
+      return FALSE;
+  }
+  if(new >= control_flow_data->v_adjust->lower &&
+      new <= control_flow_data->v_adjust->upper 
+          - control_flow_data->v_adjust->page_size)
+    gtk_adjustment_set_value(control_flow_data->v_adjust, new);
+  return TRUE;
+}
+
+
+/* Toolbar callbacks */
+static void        property_button      (GtkToolButton *toolbutton,
+                                          gpointer       user_data)
+{
+  ControlFlowData *control_flow_data = (ControlFlowData*)user_data;
+
+  g_printf("CFV Property button clicked\n");
+
+}
+
+/* Toolbar callbacks */
+static void        filter_button      (GtkToolButton *toolbutton,
+                                          gpointer       user_data)
+{
+  LttvPluginCFV *plugin_cfv = (LttvPluginCFV*)user_data;
+  LttvAttribute *attribute;
+  LttvAttributeValue value;
+  gboolean ret;
+  g_printf("Filter button clicked\n");
+
+  attribute = LTTV_ATTRIBUTE(lttv_iattribute_find_subdir(
+        LTTV_IATTRIBUTE(lttv_global_attributes()),
+        LTTV_VIEWER_CONSTRUCTORS));
+  g_assert(attribute);
+
+  ret = lttv_iattribute_find_by_path(LTTV_IATTRIBUTE(attribute),
+      "guifilter", LTTV_POINTER, &value);
+  g_assert(ret);
+  lttvwindow_viewer_constructor constructor =
+    (lttvwindow_viewer_constructor)*(value.v_pointer);
+  if(constructor) constructor(&plugin_cfv->parent);
+  else g_warning("Filter module not loaded.");
+
+  //FIXME : viewer returned.
+}
+
+
+
+/*****************************************************************************
+ *                     Control Flow Viewer class implementation              *
+ *****************************************************************************/
+/**
+ * Control Flow Viewer's constructor
+ *
+ * This constructor is given as a parameter to the menuitem and toolbar button
+ * registration. It creates the drawing widget.
+ * @param ParentWindow A pointer to the parent window.
+ * @return The widget created.
+ */
+ControlFlowData *
+guicontrolflow(LttvPluginTab *ptab)
+{
+  Tab *tab = ptab->tab;
+  GtkWidget *tmp_toolbar_icon;
+  GtkWidget *process_list_widget, *drawing_widget, *drawing_area;
+  //ControlFlowData* control_flow_data = g_new(ControlFlowData,1) ;
+  LttvPluginCFV *plugin_cfv = g_object_new(LTTV_TYPE_PLUGIN_CFV, NULL);
+  GtkTooltips *tooltips = gtk_tooltips_new();
+  ControlFlowData* control_flow_data = plugin_cfv->cfd;
+  control_flow_data->ptab = ptab;
+  control_flow_data->tab = ptab->tab;
+
+  control_flow_data->v_adjust = 
+    GTK_ADJUSTMENT(gtk_adjustment_new(  0.0,  /* Value */
+              0.0,  /* Lower */
+              0.0,  /* Upper */
+              0.0,  /* Step inc. */
+              0.0,  /* Page inc. */
+              0.0));  /* page size */
+
+  /* Create the drawing */
+  control_flow_data->drawing = drawing_construct(control_flow_data);
+  
+  drawing_widget = 
+    drawing_get_widget(control_flow_data->drawing);
+  
+  drawing_area = 
+    drawing_get_drawing_area(control_flow_data->drawing);
+
+  control_flow_data->number_of_process = 0;
+  control_flow_data->background_info_waiting = 0;
+
+  /* Create the Process list */
+  control_flow_data->process_list = processlist_construct();
+  
+  process_list_widget = 
+    processlist_get_widget(control_flow_data->process_list);
+  
+  gtk_tree_view_set_vadjustment(GTK_TREE_VIEW(process_list_widget),
+                                GTK_ADJUSTMENT(
+                                   control_flow_data->v_adjust));
+
+  g_signal_connect (G_OBJECT(process_list_widget),
+        "scroll-event",
+        G_CALLBACK (cfv_scroll_event),
+        (gpointer)control_flow_data);
+   g_signal_connect (G_OBJECT(drawing_area),
+        "scroll-event",
+        G_CALLBACK (cfv_scroll_event),
+        (gpointer)control_flow_data);
+  
+  g_signal_connect (G_OBJECT(control_flow_data->process_list->button),
+        "size-allocate",
+        G_CALLBACK(header_size_allocate),
+        (gpointer)control_flow_data->drawing);
+#if 0  /* not ready */
+  g_signal_connect (
+       // G_OBJECT(control_flow_data->process_list->process_list_widget),
+        G_OBJECT(control_flow_data->process_list->list_store),
+        "row-changed",
+        G_CALLBACK (tree_row_activated),
+        (gpointer)control_flow_data);
+#endif //0
+  
+  control_flow_data->hbox = gtk_hbox_new(FALSE, 1);
+  control_flow_data->toolbar = gtk_toolbar_new();
+  gtk_toolbar_set_orientation(GTK_TOOLBAR(control_flow_data->toolbar),
+                              GTK_ORIENTATION_VERTICAL);
+
+  tmp_toolbar_icon = create_pixmap (main_window_get_widget(tab),
+      "guifilter16x16.png");
+  gtk_widget_show(tmp_toolbar_icon);
+  control_flow_data->button_filter = gtk_tool_button_new(tmp_toolbar_icon,
+      "Filter");
+  g_signal_connect (G_OBJECT(control_flow_data->button_filter),
+        "clicked",
+        G_CALLBACK (filter_button),
+        (gpointer)plugin_cfv);
+  gtk_toolbar_insert(GTK_TOOLBAR(control_flow_data->toolbar),
+      control_flow_data->button_filter,
+      0);
+  gtk_tool_item_set_tooltip(GTK_TOOL_ITEM(control_flow_data->button_filter),
+      tooltips, "Open the filter window", NULL);
+
+  tmp_toolbar_icon = create_pixmap (main_window_get_widget(tab),
+      "properties.png");
+  gtk_widget_show(tmp_toolbar_icon);
+  control_flow_data->button_prop = gtk_tool_button_new(tmp_toolbar_icon,
+      "Properties");
+  g_signal_connect (G_OBJECT(control_flow_data->button_prop),
+        "clicked",
+        G_CALLBACK (property_button),
+        (gpointer)control_flow_data);
+  gtk_toolbar_insert(GTK_TOOLBAR(control_flow_data->toolbar),
+      control_flow_data->button_prop,
+      1);
+
+  gtk_toolbar_set_style(GTK_TOOLBAR(control_flow_data->toolbar),
+      GTK_TOOLBAR_ICONS);
+
+  gtk_box_pack_start(GTK_BOX(control_flow_data->hbox), 
+      control_flow_data->toolbar,
+      FALSE, FALSE, 0);
+  control_flow_data->h_paned = gtk_hpaned_new();
+  control_flow_data->box = gtk_event_box_new();
+  gtk_box_pack_end(GTK_BOX(control_flow_data->hbox), 
+      control_flow_data->box,
+      TRUE, TRUE, 0);
+  control_flow_data->top_widget = control_flow_data->hbox;
+  plugin_cfv->parent.top_widget = control_flow_data->top_widget;
+  gtk_container_add(GTK_CONTAINER(control_flow_data->box),
+                    control_flow_data->h_paned);
+      
+  gtk_paned_pack1(GTK_PANED(control_flow_data->h_paned),
+                  process_list_widget, FALSE, TRUE);
+  gtk_paned_pack2(GTK_PANED(control_flow_data->h_paned),
+                  drawing_widget, TRUE, TRUE);
+  
+  gtk_container_set_border_width(GTK_CONTAINER(control_flow_data->box), 1);
+  
+  /* Set the size of the drawing area */
+  //drawing_Resize(drawing, h, w);
+
+  /* Get trace statistics */
+  //control_flow_data->Trace_Statistics = get_trace_statistics(Trace);
+
+  gtk_widget_show(drawing_widget);
+  gtk_widget_show(process_list_widget);
+  gtk_widget_show(control_flow_data->h_paned);
+  gtk_widget_show(control_flow_data->box);
+  gtk_widget_show(control_flow_data->toolbar);
+  gtk_widget_show(GTK_WIDGET(control_flow_data->button_prop));
+  gtk_widget_show(GTK_WIDGET(control_flow_data->button_filter));
+  gtk_widget_show(control_flow_data->hbox);
+  
+  g_object_set_data_full(
+      G_OBJECT(control_flow_data->top_widget),
+      "plugin_data",
+      plugin_cfv,
+      (GDestroyNotify)guicontrolflow_destructor);
+    
+  g_object_set_data(
+      G_OBJECT(drawing_area),
+      "control_flow_data",
+      control_flow_data);
+        
+  g_control_flow_data_list = g_slist_append(
+      g_control_flow_data_list,
+      plugin_cfv);
+  
+  control_flow_data->filter = NULL;
+
+  //WARNING : The widget must be 
+  //inserted in the main window before the drawing area
+  //can be configured (and this must happend bedore sending
+  //data)
+  
+  return control_flow_data;
+
+}
+
+/* Destroys widget also */
+void
+guicontrolflow_destructor_full(gpointer data)
+{
+  LttvPluginCFV *plugin_cfv = (LttvPluginCFV*)data;
+  g_info("CFV.c : guicontrolflow_destructor_full, %p", plugin_cfv);
+  /* May already have been done by GTK window closing */
+  if(GTK_IS_WIDGET(guicontrolflow_get_widget(plugin_cfv->cfd)))
+    gtk_widget_destroy(guicontrolflow_get_widget(plugin_cfv->cfd));
+  //control_flow_data->mw = NULL;
+  //FIXME guicontrolflow_destructor(control_flow_data);
+}
+
+/* When this destructor is called, the widgets are already disconnected */
+void
+guicontrolflow_destructor(gpointer data)
+{
+  LttvPluginCFV *plugin_cfv = (LttvPluginCFV*)data;
+  Tab *tab = plugin_cfv->cfd->tab;
+  ControlFlowData *control_flow_data = plugin_cfv->cfd;
+  
+  g_info("CFV.c : guicontrolflow_destructor, %p", plugin_cfv);
+  g_info("%p, %p, %p", update_time_window_hook, plugin_cfv, tab);
+  if(GTK_IS_WIDGET(guicontrolflow_get_widget(plugin_cfv->cfd)))
+    g_info("widget still exists");
+  
+  lttv_filter_destroy(plugin_cfv->cfd->filter);
+  /* Process List is removed with it's widget */
+  //ProcessList_destroy(control_flow_data->process_list);
+  if(tab != NULL)
+  {
+      /* Delete reading hooks */
+    lttvwindow_unregister_traceset_notify(tab,
+        traceset_notify,
+        control_flow_data);
+    
+    lttvwindow_unregister_time_window_notify(tab,
+        update_time_window_hook,
+        control_flow_data);
+  
+    lttvwindow_unregister_current_time_notify(tab,
+        update_current_time_hook,
+        control_flow_data);
+
+    lttvwindow_unregister_redraw_notify(tab, redraw_notify, control_flow_data);
+    lttvwindow_unregister_continue_notify(tab,
+                                          continue_notify,
+                                          control_flow_data);
+    
+    lttvwindow_events_request_remove_all(control_flow_data->tab,
+                                         control_flow_data);
+
+  }
+  lttvwindowtraces_background_notify_remove(control_flow_data);
+  g_control_flow_data_list = 
+         g_slist_remove(g_control_flow_data_list, control_flow_data);
+
+  g_info("CFV.c : guicontrolflow_destructor end, %p", control_flow_data);
+  //g_free(control_flow_data);
+  g_object_unref(plugin_cfv);
+}
+
+
diff --git a/ltt/branches/poly/lttv/modules/gui/resourceview/cfv.h b/ltt/branches/poly/lttv/modules/gui/resourceview/cfv.h
new file mode 100644 (file)
index 0000000..5c2276e
--- /dev/null
@@ -0,0 +1,94 @@
+/* This file is part of the Linux Trace Toolkit viewer
+ * Copyright (C) 2003-2004 Mathieu Desnoyers
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License Version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, 
+ * MA 02111-1307, USA.
+ */
+
+
+
+#ifndef _CFV_H
+#define _CFV_H
+
+#include <gtk/gtk.h>
+#include <lttvwindow/mainwindow.h>
+#include <lttv/filter.h>
+#include "processlist.h"
+#include <lttvwindow/lttv_plugin_tab.h>
+
+extern GQuark LTT_NAME_CPU;
+
+#ifndef TYPE_DRAWING_T_DEFINED
+#define TYPE_DRAWING_T_DEFINED
+typedef struct _Drawing_t Drawing_t;
+#endif //TYPE_DRAWING_T_DEFINED
+
+#ifndef TYPE_CONTROLFLOWDATA_DEFINED
+#define TYPE_CONTROLFLOWDATA_DEFINED
+typedef struct _ControlFlowData ControlFlowData;
+#endif //TYPE_CONTROLFLOWDATA_DEFINED
+
+struct _ControlFlowData {
+
+  GtkWidget *top_widget;
+  Tab *tab;
+  LttvPluginTab *ptab;
+  
+  GtkWidget *hbox;
+  GtkWidget *toolbar; /* Vbox that contains the viewer's toolbar */
+  GtkToolItem *button_prop; /* Properties button. */
+  GtkToolItem *button_filter; /* Properties button. */
+  GtkWidget *box; /* box that contains the hpaned. necessary for it to work */
+  GtkWidget *h_paned;
+
+  ProcessList *process_list;
+
+  Drawing_t *drawing;
+  GtkAdjustment *v_adjust ;
+
+  /* Shown events information */
+//  TimeWindow time_window;
+//  LttTime current_time;
+  
+  //guint currently_Selected_Event  ;
+  guint number_of_process;
+  guint background_info_waiting; /* Number of background requests waited for
+                                    in order to have all the info ready. */
+
+  LttvFilter *filter;
+
+} ;
+
+/* Control Flow Data constructor */
+ControlFlowData *guicontrolflow(LttvPluginTab *ptab);
+void
+guicontrolflow_destructor_full(gpointer data);
+void
+guicontrolflow_destructor(gpointer data);
+
+static inline GtkWidget *guicontrolflow_get_widget(
+                                     ControlFlowData *control_flow_data)
+{
+  return control_flow_data->top_widget ;
+}
+
+static inline ProcessList *guicontrolflow_get_process_list
+    (ControlFlowData *control_flow_data)
+{
+    return control_flow_data->process_list ;
+}
+
+
+
+#endif // _CFV_H
diff --git a/ltt/branches/poly/lttv/modules/gui/resourceview/drawing.c b/ltt/branches/poly/lttv/modules/gui/resourceview/drawing.c
new file mode 100644 (file)
index 0000000..e0b92aa
--- /dev/null
@@ -0,0 +1,1480 @@
+/* This file is part of the Linux Trace Toolkit viewer
+ * Copyright (C) 2003-2004 Mathieu Desnoyers
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License Version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, 
+ * MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <gtk/gtk.h>
+#include <gdk/gdk.h>
+#include <string.h>
+
+#include <ltt/trace.h>
+
+#include <lttv/lttv.h>
+#include <lttv/tracecontext.h>
+#include <lttvwindow/lttvwindow.h>
+#include <lttv/state.h>
+#include <lttv/hook.h>
+
+#include "drawing.h"
+#include "eventhooks.h"
+#include "cfv.h"
+
+#define g_info(format...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, format)
+#define g_debug(format...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, format)
+
+//FIXME
+// fixed #define TRACE_NUMBER 0
+#define EXTRA_ALLOC 1024 // pixels
+
+
+#if 0 /* colors for two lines representation */
+GdkColor drawing_colors[NUM_COLORS] =
+{ /* Pixel, R, G, B */
+  { 0, 0, 0, 0 }, /* COL_BLACK */
+  { 0, 0xFFFF, 0xFFFF, 0xFFFF }, /* COL_WHITE */
+  { 0, 0x0FFF, 0xFFFF, 0xFFFF }, /* COL_WAIT_FORK : pale blue */
+  { 0, 0xFFFF, 0xFFFF, 0x0000 }, /* COL_WAIT_CPU : yellow */
+  { 0, 0xFFFF, 0xA000, 0xFCFF }, /* COL_EXIT : pale magenta */
+  { 0, 0xFFFF, 0x0000, 0xFFFF }, /* COL_ZOMBIE : purple */
+  { 0, 0xFFFF, 0x0000, 0x0000 }, /* COL_WAIT : red */
+  { 0, 0x0000, 0xFFFF, 0x0000 }, /* COL_RUN : green */
+  { 0, 0x8800, 0xFFFF, 0x8A00 }, /* COL_USER_MODE : pale green */
+  { 0, 0x09FF, 0x01FF, 0xFFFF }, /* COL_SYSCALL : blue */
+  { 0, 0xF900, 0x4200, 0xFF00 }, /* COL_TRAP : pale purple */
+  { 0, 0xFFFF, 0x5AFF, 0x01FF }, /* COL_IRQ : orange */
+  { 0, 0xFFFF, 0xFFFF, 0xFFFF }  /* COL_MODE_UNKNOWN : white */
+
+};
+#endif //0
+
+
+GdkColor drawing_colors[NUM_COLORS] =
+{ /* Pixel, R, G, B */
+  { 0, 0, 0, 0 }, /* COL_BLACK */
+  { 0, 0xFFFF, 0xFFFF, 0xFFFF }, /* COL_WHITE */
+  { 0, 0x0000, 0xFF00, 0x0000 }, /* COL_RUN_USER_MODE : green */
+  { 0, 0x0100, 0x9E00, 0xFFFF }, /* COL_RUN_SYSCALL : pale blue */
+  { 0, 0xFF00, 0xFF00, 0x0100 }, /* COL_RUN_TRAP : yellow */
+  { 0, 0xFFFF, 0x5E00, 0x0000 }, /* COL_RUN_IRQ : orange */
+  { 0, 0xFFFF, 0x9400, 0x9600 }, /* COL_RUN_SOFT_IRQ : pink */
+  { 0, 0x6600, 0x0000, 0x0000 }, /* COL_WAIT : dark red */
+  { 0, 0x7700, 0x7700, 0x0000 }, /* COL_WAIT_CPU : dark yellow */
+  { 0, 0x6400, 0x0000, 0x5D00 }, /* COL_ZOMBIE : dark purple */
+  { 0, 0x0700, 0x6400, 0x0000 }, /* COL_WAIT_FORK : dark green */
+  { 0, 0x8900, 0x0000, 0x8400 }, /* COL_EXIT : "less dark" magenta */
+  { 0, 0xFFFF, 0xFFFF, 0xFFFF }, /* COL_MODE_UNKNOWN : white */
+  { 0, 0xFFFF, 0xFFFF, 0xFFFF }  /* COL_UNNAMED : white */
+
+};
+
+/*
+RUN+USER MODE green
+RUN+SYSCALL
+RUN+TRAP
+RUN+IRQ
+WAIT+foncé
+WAIT CPU + WAIT FORK vert foncé ou jaune
+IRQ rouge
+TRAP: orange
+SYSCALL: bleu pâle
+
+ZOMBIE + WAIT EXIT
+*/
+
+
+/*****************************************************************************
+ *                              drawing functions                            *
+ *****************************************************************************/
+
+static gboolean
+expose_ruler( GtkWidget *widget, GdkEventExpose *event, gpointer user_data );
+
+static gboolean
+motion_notify_ruler(GtkWidget *widget, GdkEventMotion *event, gpointer user_data);
+
+
+/* Function responsible for updating the exposed area.
+ * It must do an events request to the lttvwindow API to ask for this update.
+ * Note : this function cannot clear the background, because it may
+ * erase drawing already present (SAFETY).
+ */
+void drawing_data_request(Drawing_t *drawing,
+      gint x, gint y,
+      gint width,
+      gint height)
+{
+  if(width < 0) return ;
+  if(height < 0) return ;
+
+
+  Tab *tab = drawing->control_flow_data->tab;
+  TimeWindow time_window =
+              lttvwindow_get_time_window(tab);
+
+  ControlFlowData *control_flow_data = drawing->control_flow_data;
+  //    (ControlFlowData*)g_object_get_data(
+  //               G_OBJECT(drawing->drawing_area), "control_flow_data");
+
+  LttTime start, time_end;
+  LttTime window_end = time_window.end_time;
+
+  g_debug("req : window start_time : %lu, %lu", time_window.start_time.tv_sec, 
+                                       time_window.start_time.tv_nsec);
+
+  g_debug("req : window time width : %lu, %lu", time_window.time_width.tv_sec, 
+                                       time_window.time_width.tv_nsec);
+  
+  g_debug("req : window_end : %lu, %lu", window_end.tv_sec, 
+                                       window_end.tv_nsec);
+
+  g_debug("x is : %i, x+width is : %i", x, x+width);
+
+  convert_pixels_to_time(drawing->width, x,
+        time_window,
+        &start);
+
+  convert_pixels_to_time(drawing->width, x+width,
+        time_window,
+        &time_end);
+  time_end = ltt_time_add(time_end, ltt_time_one); // because main window
+                                                   // doesn't deliver end time.
+
+  lttvwindow_events_request_remove_all(tab,
+                                       control_flow_data);
+
+  {
+    /* find the tracehooks */
+    LttvTracesetContext *tsc = lttvwindow_get_traceset_context(tab);
+
+    LttvTraceset *traceset = tsc->ts;
+
+    guint i, k, l, nb_trace;
+
+    LttvTraceState *ts;
+
+    LttvTracefileState *tfs;
+
+    GArray *hooks;
+
+    LttvTraceHook *hook;
+
+    LttvTraceHookByFacility *thf;
+
+    guint ret;
+    gint before_hn, after_hn;
+
+    nb_trace = lttv_traceset_number(traceset);
+    // FIXME  (fixed) : eventually request for more traces
+    for(i = 0 ; i < nb_trace ; i++) {
+    //for(i = 0; i<MIN(TRACE_NUMBER+1, nb_trace);i++) {
+      EventsRequest *events_request = g_new(EventsRequest, 1);
+      // Create the hooks
+      //LttvHooks *event = lttv_hooks_new();
+      LttvHooksById *event_by_id = lttv_hooks_by_id_new();
+      LttvHooks *before_chunk_traceset = lttv_hooks_new();
+      LttvHooks *after_chunk_traceset = lttv_hooks_new();
+      LttvHooks *before_request_hook = lttv_hooks_new();
+      LttvHooks *after_request_hook = lttv_hooks_new();
+
+      lttv_hooks_add(before_chunk_traceset,
+                     before_chunk,
+                     events_request,
+                     LTTV_PRIO_DEFAULT);
+
+      lttv_hooks_add(after_chunk_traceset,
+                     after_chunk,
+                     events_request,
+                     LTTV_PRIO_DEFAULT);
+
+      lttv_hooks_add(before_request_hook,
+                     before_request,
+                     events_request,
+                     LTTV_PRIO_DEFAULT);
+
+      lttv_hooks_add(after_request_hook,
+                     after_request,
+                     events_request,
+                     LTTV_PRIO_DEFAULT);
+
+
+      ts = (LttvTraceState *)tsc->traces[i];
+
+      /* Find the eventtype id for the following events and register the
+         associated by id hooks. */
+
+      hooks = g_array_new(FALSE, FALSE, sizeof(LttvTraceHook));
+      hooks = g_array_set_size(hooks, 18);
+      before_hn = after_hn = 0;
+
+      /* before hooks */
+      
+      ret = lttv_trace_find_hook(ts->parent.t,
+          LTT_FACILITY_KERNEL_ARCH, LTT_EVENT_SYSCALL_ENTRY,
+          LTT_FIELD_SYSCALL_ID, 0, 0,
+          before_execmode_hook,
+          events_request,
+          &g_array_index(hooks, LttvTraceHook, before_hn++));
+      if(ret) before_hn--;
+
+      ret = lttv_trace_find_hook(ts->parent.t,
+          LTT_FACILITY_KERNEL_ARCH, LTT_EVENT_SYSCALL_EXIT,
+          0, 0, 0,
+          before_execmode_hook,
+          events_request,
+          &g_array_index(hooks, LttvTraceHook, before_hn++));
+      if(ret) before_hn--;
+
+      ret = lttv_trace_find_hook(ts->parent.t,
+          LTT_FACILITY_KERNEL_ARCH, LTT_EVENT_TRAP_ENTRY,
+          LTT_FIELD_TRAP_ID, 0, 0,
+          before_execmode_hook,
+          events_request,
+          &g_array_index(hooks, LttvTraceHook, before_hn++));
+      if(ret) before_hn--;
+
+      ret = lttv_trace_find_hook(ts->parent.t,
+          LTT_FACILITY_KERNEL_ARCH, LTT_EVENT_TRAP_EXIT,
+          0, 0, 0, 
+          before_execmode_hook,
+          events_request,
+          &g_array_index(hooks, LttvTraceHook, before_hn++));
+      if(ret) before_hn--;
+
+      ret = lttv_trace_find_hook(ts->parent.t,
+          LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_ENTRY,
+          LTT_FIELD_IRQ_ID, 0, 0,
+          before_execmode_hook,
+          events_request,
+          &g_array_index(hooks, LttvTraceHook, before_hn++));
+      if(ret) before_hn--;
+
+      ret = lttv_trace_find_hook(ts->parent.t,
+          LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_EXIT,
+          0, 0, 0, 
+          before_execmode_hook,
+          events_request,
+          &g_array_index(hooks, LttvTraceHook, before_hn++));
+      if(ret) before_hn--;
+
+      ret = lttv_trace_find_hook(ts->parent.t,
+          LTT_FACILITY_KERNEL, LTT_EVENT_SOFT_IRQ_ENTRY,
+          LTT_FIELD_SOFT_IRQ_ID, 0, 0,
+          before_execmode_hook,
+          events_request,
+          &g_array_index(hooks, LttvTraceHook, before_hn++));
+      if(ret) before_hn--;
+
+      ret = lttv_trace_find_hook(ts->parent.t,
+          LTT_FACILITY_KERNEL, LTT_EVENT_SOFT_IRQ_EXIT,
+          0, 0, 0, 
+          before_execmode_hook,
+          events_request,
+          &g_array_index(hooks, LttvTraceHook, before_hn++));
+      if(ret) before_hn--;
+
+
+      ret = lttv_trace_find_hook(ts->parent.t,
+          LTT_FACILITY_KERNEL, LTT_EVENT_SCHED_SCHEDULE,
+          LTT_FIELD_PREV_PID, LTT_FIELD_NEXT_PID, LTT_FIELD_PREV_STATE,
+          before_schedchange_hook,
+          events_request,
+          &g_array_index(hooks, LttvTraceHook, before_hn++));
+      if(ret) before_hn--;
+
+      ret = lttv_trace_find_hook(ts->parent.t,
+          LTT_FACILITY_KERNEL, LTT_EVENT_PROCESS_EXIT,
+          LTT_FIELD_PID, 0, 0,
+          before_process_exit_hook,
+          events_request,
+          &g_array_index(hooks, LttvTraceHook, before_hn++));
+      if(ret) before_hn--;
+      
+      ret = lttv_trace_find_hook(ts->parent.t,
+          LTT_FACILITY_KERNEL, LTT_EVENT_PROCESS_FREE,
+          LTT_FIELD_PID, 0, 0,
+          before_process_release_hook,
+          events_request,
+          &g_array_index(hooks, LttvTraceHook, before_hn++));
+      if(ret) before_hn--;
+
+      ret = lttv_trace_find_hook(ts->parent.t,
+          LTT_FACILITY_LIST, LTT_EVENT_STATEDUMP_END,
+          0, 0, 0,
+          before_statedump_end,
+          events_request,
+          &g_array_index(hooks, LttvTraceHook, before_hn++));
+      if(ret) before_hn--;
+
+#if 0
+      lttv_trace_find_hook(ts->parent.t,
+          "core", "process", "event_sub_id", 
+          "event_data1", "event_data2", before_process_hook,
+          &g_array_index(hooks, LttvTraceHook, hn++));
+#endif //0
+#if 0
+      lttv_trace_find_hook(ts->parent.t, "core", "process_fork", "child_pid", 
+          NULL, NULL, process_fork, &g_array_index(hooks, LttvTraceHook, hn++));
+
+      lttv_trace_find_hook(ts->parent.t, "core", "process_exit", NULL, NULL, 
+          NULL, process_exit, &g_array_index(hooks, LttvTraceHook, hn++));
+#endif //0
+
+      /* after hooks */
+      
+#if 0
+      /**** DESACTIVATED ****/
+      lttv_trace_find_hook(ts->parent.t, "core","syscall_entry","syscall_id", 
+    NULL, NULL, after_execmode_hook, &g_array_index(hooks, LttvTraceHook, hn++));
+      /**** DESACTIVATED ****/
+      lttv_trace_find_hook(ts->parent.t, "core", "syscall_exit", NULL, NULL, 
+          NULL, after_execmode_hook, &g_array_index(hooks, LttvTraceHook, hn++));
+
+      /**** DESACTIVATED ****/
+      lttv_trace_find_hook(ts->parent.t, "core", "trap_entry", "trap_id",
+    NULL, NULL, after_execmode_hook, &g_array_index(hooks, LttvTraceHook, hn++));
+
+      /**** DESACTIVATED ****/
+      lttv_trace_find_hook(ts->parent.t, "core", "trap_exit", NULL, NULL, NULL, 
+          after_execmode_hook, &g_array_index(hooks, LttvTraceHook, hn++));
+
+      /**** DESACTIVATED ****/
+      lttv_trace_find_hook(ts->parent.t, "core", "irq_entry", "irq_id", NULL, 
+          NULL, after_execmode_hook, &g_array_index(hooks, LttvTraceHook, hn++));
+
+      /**** DESACTIVATED ****/
+      lttv_trace_find_hook(ts->parent.t, "core", "irq_exit", NULL, NULL, NULL, 
+          after_execmode_hook, &g_array_index(hooks, LttvTraceHook, hn++));
+#endif //0
+#if 0
+      lttv_trace_find_hook(ts->parent.t, "core", "schedchange", "in", "out", 
+        "out_state", after_schedchange_hook, 
+        &g_array_index(hooks, LttvTraceHook, hn++));
+
+      lttv_trace_find_hook(ts->parent.t, "core", "process", "event_sub_id", 
+          "event_data1", "event_data2", after_process_hook,
+          &g_array_index(hooks, LttvTraceHook, hn++));
+#endif //0
+      after_hn = before_hn;
+      
+      ret = lttv_trace_find_hook(ts->parent.t,
+          LTT_FACILITY_KERNEL, LTT_EVENT_SCHED_SCHEDULE,
+          LTT_FIELD_PREV_PID, LTT_FIELD_NEXT_PID, LTT_FIELD_PREV_STATE,
+          after_schedchange_hook,
+          events_request,
+          &g_array_index(hooks, LttvTraceHook, after_hn++));
+      if(ret) after_hn--;
+
+      ret = lttv_trace_find_hook(ts->parent.t,
+          LTT_FACILITY_KERNEL, LTT_EVENT_PROCESS_FORK,
+          LTT_FIELD_PARENT_PID, LTT_FIELD_CHILD_PID, 0,
+          after_process_fork_hook,
+          events_request,
+          &g_array_index(hooks, LttvTraceHook, after_hn++));
+      if(ret) after_hn--;
+
+      ret = lttv_trace_find_hook(ts->parent.t,
+          LTT_FACILITY_KERNEL, LTT_EVENT_PROCESS_EXIT,
+          LTT_FIELD_PID, 0, 0,
+          after_process_exit_hook,
+          events_request,
+          &g_array_index(hooks, LttvTraceHook, after_hn++));
+      if(ret) after_hn--;
+
+      ret = lttv_trace_find_hook(ts->parent.t,
+          LTT_FACILITY_FS, LTT_EVENT_EXEC,
+          0, 0, 0,
+          after_fs_exec_hook,
+          events_request,
+          &g_array_index(hooks, LttvTraceHook, after_hn++));
+      if(ret) after_hn--;
+
+      ret = lttv_trace_find_hook(ts->parent.t,
+          LTT_FACILITY_USER_GENERIC, LTT_EVENT_THREAD_BRAND,
+          LTT_FIELD_NAME, 0, 0,
+          after_user_generic_thread_brand_hook,
+          events_request,
+          &g_array_index(hooks, LttvTraceHook, after_hn++));
+      if(ret) after_hn--;
+
+      ret = lttv_trace_find_hook(ts->parent.t,
+          LTT_FACILITY_LIST, LTT_EVENT_PROCESS_STATE,
+          LTT_FIELD_PID, LTT_FIELD_PARENT_PID, LTT_FIELD_NAME,
+          after_event_enum_process_hook,
+          events_request,
+          &g_array_index(hooks, LttvTraceHook, after_hn++));
+      if(ret) after_hn--;
+
+      hooks = g_array_set_size(hooks, after_hn);
+
+#if 0
+      lttv_trace_find_hook(ts->parent.t, "core", "process_fork", "child_pid", 
+          NULL, NULL, process_fork, &g_array_index(hooks, LttvTraceHook, hn++));
+
+      lttv_trace_find_hook(ts->parent.t, "core", "process_exit", NULL, NULL, 
+          NULL, process_exit, &g_array_index(hooks, LttvTraceHook, hn++));
+#endif //0
+
+
+      
+      /* Add these hooks to each event_by_id hooks list */
+      /* add before */
+      for(k = 0 ; k < before_hn ; k++) {
+        hook = &g_array_index(hooks, LttvTraceHook, k);
+        for(l=0;l<hook->fac_list->len;l++) {
+          thf = g_array_index(hook->fac_list, LttvTraceHookByFacility*, l);
+          lttv_hooks_add(lttv_hooks_by_id_find(event_by_id, thf->id),
+                          thf->h,
+                          thf,
+                          LTTV_PRIO_STATE-5);
+        }
+      }
+
+      /* add after */
+      for(k = before_hn ; k < after_hn ; k++) {
+        hook = &g_array_index(hooks, LttvTraceHook, k);
+        for(l=0;l<hook->fac_list->len;l++) {
+          thf = g_array_index(hook->fac_list, LttvTraceHookByFacility*, l);
+          lttv_hooks_add(lttv_hooks_by_id_find(event_by_id, thf->id),
+                         thf->h,
+                         thf,
+                         LTTV_PRIO_STATE+5);
+        }
+      }
+      
+      events_request->hooks = hooks;
+
+      // Fill the events request
+      events_request->owner = control_flow_data;
+      events_request->viewer_data = control_flow_data;
+      events_request->servicing = FALSE;
+      events_request->start_time = start;
+      events_request->start_position = NULL;
+      events_request->stop_flag = FALSE;
+      events_request->end_time = time_end;
+      events_request->num_events = G_MAXUINT;
+      events_request->end_position = NULL;
+      events_request->trace = i; //fixed    /* FIXME */
+      events_request->before_chunk_traceset = before_chunk_traceset;
+      events_request->before_chunk_trace = NULL;
+      events_request->before_chunk_tracefile = NULL;
+      events_request->event = NULL;
+      events_request->event_by_id = event_by_id;
+      events_request->after_chunk_tracefile = NULL;
+      events_request->after_chunk_trace = NULL;
+      events_request->after_chunk_traceset = after_chunk_traceset;
+      events_request->before_request = before_request_hook;
+      events_request->after_request = after_request_hook;
+
+      g_debug("req : start : %lu, %lu", start.tv_sec, 
+                                          start.tv_nsec);
+
+      g_debug("req : end : %lu, %lu", time_end.tv_sec, 
+                                         time_end.tv_nsec);
+
+      lttvwindow_events_request(tab, events_request);
+
+    }
+
+  }
+
+#if 0
+  lttv_hooks_add(event,
+                 before_schedchange_hook,
+                 events_request,
+                 LTTV_PRIO_STATE-5);
+  lttv_hooks_add(event,
+                 after_schedchange_hook,
+                 events_request,
+                 LTTV_PRIO_STATE+5);
+  lttv_hooks_add(event,
+                 before_execmode_hook,
+                 events_request,
+                 LTTV_PRIO_STATE-5);
+  lttv_hooks_add(event,
+                 after_execmode_hook,
+                 events_request,
+                 LTTV_PRIO_STATE+5);
+  lttv_hooks_add(event,
+                 before_process_hook,
+                 events_request,
+                 LTTV_PRIO_STATE-5);
+  lttv_hooks_add(event,
+                 after_process_hook,
+                 events_request,
+                 LTTV_PRIO_STATE+5);
+#endif //0
+
+}
+
+static void set_last_start(gpointer key, gpointer value, gpointer user_data)
+{
+  ProcessInfo *process_info = (ProcessInfo*)key;
+  HashedProcessData *hashed_process_data = (HashedProcessData*)value;
+  guint x = (guint)user_data;
+
+  hashed_process_data->x.over = x;
+  hashed_process_data->x.over_used = FALSE;
+  hashed_process_data->x.over_marked = FALSE;
+  hashed_process_data->x.middle = x;
+  hashed_process_data->x.middle_used = FALSE;
+  hashed_process_data->x.middle_marked = FALSE;
+  hashed_process_data->x.under = x;
+  hashed_process_data->x.under_used = FALSE;
+  hashed_process_data->x.under_marked = FALSE;
+  hashed_process_data->next_good_time = ltt_time_zero;
+
+  return;
+}
+
+void drawing_data_request_begin(EventsRequest *events_request, LttvTracesetState *tss)
+{
+  g_debug("Begin of data request");
+  ControlFlowData *cfd = events_request->viewer_data;
+  LttvTracesetContext *tsc = LTTV_TRACESET_CONTEXT(tss);
+  TimeWindow time_window = 
+    lttvwindow_get_time_window(cfd->tab);
+
+  guint width = cfd->drawing->width;
+  guint x=0;
+
+  cfd->drawing->last_start = events_request->start_time;
+
+  convert_time_to_pixels(
+          time_window,
+          events_request->start_time,
+          width,
+          &x);
+
+  g_hash_table_foreach(cfd->process_list->process_hash, set_last_start,
+                            (gpointer)x);
+
+}
+
+void drawing_chunk_begin(EventsRequest *events_request, LttvTracesetState *tss)
+{
+  g_debug("Begin of chunk");
+  ControlFlowData *cfd = events_request->viewer_data;
+  LttvTracesetContext *tsc = &tss->parent.parent;
+  //LttTime current_time = lttv_traceset_context_get_current_tfc(tsc)->timestamp;
+  guint i;
+  LttvTraceset *traceset = tsc->ts;
+  guint nb_trace = lttv_traceset_number(traceset);
+  
+  if(!cfd->process_list->current_hash_data) {
+    cfd->process_list->current_hash_data = g_new(HashedProcessData**,nb_trace);
+    for(i = 0 ; i < nb_trace ; i++) {
+      guint num_cpu = ltt_trace_get_num_cpu(tss->parent.traces[i]->t);
+      cfd->process_list->current_hash_data[i] = g_new(HashedProcessData*,num_cpu);
+      memset(cfd->process_list->current_hash_data[i], 0,
+             sizeof(HashedProcessData*)*num_cpu);
+    }
+  }
+  //cfd->drawing->last_start = LTT_TIME_MIN(current_time,
+  //                                        events_request->end_time);
+}
+
+
+void drawing_request_expose(EventsRequest *events_request,
+                            LttvTracesetState *tss,
+                            LttTime end_time)
+{
+  gint x, width;
+  guint x_end;
+
+  ControlFlowData *cfd = events_request->viewer_data;
+  LttvTracesetContext *tsc = (LttvTracesetContext*)tss;
+  Drawing_t *drawing = cfd->drawing;
+  
+  TimeWindow time_window = 
+        lttvwindow_get_time_window(cfd->tab);
+
+  g_debug("request expose");
+  
+  convert_time_to_pixels(
+        time_window,
+        end_time,
+        drawing->width,
+        &x_end);
+  x = drawing->damage_begin;
+
+  width = x_end - x;
+
+  drawing->damage_begin = x+width;
+
+  // FIXME ?
+  gtk_widget_queue_draw_area ( drawing->drawing_area,
+                               x, 0,
+                               width, drawing->drawing_area->allocation.height);
+  /* Update directly when scrolling */
+  gdk_window_process_updates(drawing->drawing_area->window,
+      TRUE);
+}
+
+
+/* Callbacks */
+
+
+/* Create a new backing pixmap of the appropriate size */
+/* As the scaling will always change, it's of no use to copy old
+ * pixmap.
+ *
+ * Only change the size if width changes. The height is specified and changed
+ * when process ID are added or removed from the process list.
+ */
+static gboolean
+configure_event( GtkWidget *widget, GdkEventConfigure *event, 
+    gpointer user_data)
+{
+  Drawing_t *drawing = (Drawing_t*)user_data;
+
+
+  /* First, get the new time interval of the main window */
+  /* we assume (see documentation) that the main window
+   * has updated the time interval before this configure gets
+   * executed.
+   */
+  //lttvwindow_get_time_window(drawing->control_flow_data->mw,
+  //      &drawing->control_flow_data->time_window);
+  
+  /* New pixmap, size of the configure event */
+  //GdkPixmap *pixmap = gdk_pixmap_new(widget->window,
+  //      widget->allocation.width + SAFETY,
+  //      widget->allocation.height + SAFETY,
+  //      -1);
+  
+  if(widget->allocation.width != drawing->width) {
+    g_debug("drawing configure event");
+    g_debug("New alloc draw size : %i by %i",widget->allocation.width,
+                                    widget->allocation.height);
+  
+    drawing->width = widget->allocation.width;
+    
+    if(drawing->alloc_width < widget->allocation.width) {
+      //if(drawing->pixmap)
+      //  gdk_pixmap_unref(drawing->pixmap);
+
+      //drawing->pixmap = gdk_pixmap_new(widget->window,
+      //                                 drawing->width + SAFETY + EXTRA_ALLOC,
+      //                                 drawing->height + EXTRA_ALLOC,
+      //                                 -1);
+      drawing->alloc_width = drawing->width + SAFETY + EXTRA_ALLOC;
+      drawing->alloc_height = drawing->height + EXTRA_ALLOC;
+      update_pixmap_size(drawing->control_flow_data->process_list,
+                         drawing->alloc_width);
+      update_index_to_pixmap(drawing->control_flow_data->process_list);
+    }
+    //drawing->height = widget->allocation.height;
+
+    //ProcessList_get_height
+    // (GuiControlFlow_get_process_list(drawing->control_flow_data)),
+    
+
+    // Clear the image
+    //gdk_draw_rectangle (drawing->pixmap,
+    //      widget->style->black_gc,
+    //      TRUE,
+    //      0, 0,
+    //      drawing->width+SAFETY,
+    //      drawing->height);
+
+    //g_info("init data request");
+
+
+    /* Initial data request */
+    /* no, do initial data request in the expose event */
+    // Do not need to ask for data of 1 pixel : not synchronized with
+    // main window time at this moment.
+    //drawing_data_request(drawing, &drawing->pixmap, 0, 0,
+    //    widget->allocation.width,
+    //    widget->allocation.height);
+                          
+    //drawing->width = widget->allocation.width;
+    //drawing->height = widget->allocation.height;
+  
+    drawing->damage_begin = 0;
+    drawing->damage_end = widget->allocation.width;
+
+    if((widget->allocation.width != 1 &&
+        widget->allocation.height != 1)
+        && drawing->damage_begin < drawing->damage_end)
+    {
+
+      rectangle_pixmap (drawing->control_flow_data->process_list,
+        drawing->drawing_area->style->black_gc,
+        TRUE,
+        0, 0,
+        drawing->alloc_width, // do not overlap
+        -1);
+
+
+      drawing_data_request(drawing,
+                           drawing->damage_begin,
+                           0,
+                           drawing->damage_end - drawing->damage_begin,
+                           drawing->height);
+    }
+  }
+  return TRUE;
+}
+
+
+/* Redraw the screen from the backing pixmap */
+static gboolean
+expose_event( GtkWidget *widget, GdkEventExpose *event, gpointer user_data )
+{
+  Drawing_t *drawing = (Drawing_t*)user_data;
+
+  ControlFlowData *control_flow_data =
+      (ControlFlowData*)g_object_get_data(
+                G_OBJECT(widget),
+                "control_flow_data");
+#if 0
+  if(unlikely(drawing->gc == NULL)) {
+    drawing->gc = gdk_gc_new(drawing->drawing_area->window);
+    gdk_gc_copy(drawing->gc, drawing->drawing_area->style->black_gc);
+  }
+#endif //0
+  TimeWindow time_window = 
+      lttvwindow_get_time_window(control_flow_data->tab);
+  LttTime current_time = 
+      lttvwindow_get_current_time(control_flow_data->tab);
+
+  guint cursor_x=0;
+
+  LttTime window_end = time_window.end_time;
+
+  /* update the screen from the pixmap buffer */
+#if 0
+  gdk_draw_pixmap(widget->window,
+      widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
+      drawing->pixmap,
+      event->area.x, event->area.y,
+      event->area.x, event->area.y,
+      event->area.width, event->area.height);
+#endif //0
+  drawing->height = processlist_get_height(control_flow_data->process_list);
+#if 0
+  copy_pixmap_to_screen(control_flow_data->process_list,
+                        widget->window,
+                        widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
+                        event->area.x, event->area.y,
+                        event->area.width, event->area.height);
+#endif //0
+  copy_pixmap_to_screen(control_flow_data->process_list,
+                        widget->window,
+                        drawing->gc,
+                        event->area.x, event->area.y,
+                        event->area.width, event->area.height);
+                        
+  
+  /* Erase the dotted lines left.. */
+  if(widget->allocation.height > drawing->height)
+  {
+    gdk_draw_rectangle (widget->window,
+      drawing->drawing_area->style->black_gc,
+      TRUE,
+      event->area.x, drawing->height,
+      event->area.width,  // do not overlap
+      widget->allocation.height - drawing->height);
+  }
+  if(ltt_time_compare(time_window.start_time, current_time) <= 0 &&
+           ltt_time_compare(window_end, current_time) >= 0)
+  {
+    /* Draw the dotted lines */
+    convert_time_to_pixels(
+          time_window,
+          current_time,
+          drawing->width,
+          &cursor_x);
+
+#if 0
+    if(drawing->dotted_gc == NULL) {
+
+      drawing->dotted_gc = gdk_gc_new(drawing->drawing_area->window);
+      gdk_gc_copy(drawing->dotted_gc, widget->style->white_gc);
+   
+      gint8 dash_list[] = { 1, 2 };
+      gdk_gc_set_line_attributes(drawing->dotted_gc,
+                                 1,
+                                 GDK_LINE_ON_OFF_DASH,
+                                 GDK_CAP_BUTT,
+                                 GDK_JOIN_MITER);
+      gdk_gc_set_dashes(drawing->dotted_gc,
+                        0,
+                        dash_list,
+                        2);
+    }
+#endif //0
+    gint height_tot = MAX(widget->allocation.height, drawing->height);
+    gdk_draw_line(widget->window,
+                  drawing->dotted_gc,
+                  cursor_x, 0,
+                  cursor_x, height_tot);
+  }
+  return FALSE;
+}
+
+static gboolean
+after_expose_event( GtkWidget *widget, GdkEventExpose *event, gpointer user_data )
+{
+  //g_assert(0);
+  g_debug("AFTER EXPOSE");
+
+  return FALSE;
+
+
+}
+
+#if 0
+void
+tree_row_activated(GtkTreeModel *treemodel,
+                   GtkTreePath *arg1,
+                   GtkTreeViewColumn *arg2,
+                   gpointer user_data)
+{
+  ControlFlowData *cfd = (ControlFlowData*)user_data;
+  Drawing_t *drawing = cfd->drawing;
+  GtkTreeView *treeview = cfd->process_list->process_list_widget;
+  gint *path_indices;
+  gint height;
+  
+  path_indices =  gtk_tree_path_get_indices (arg1);
+
+  height = get_cell_height(cfd->process_list,
+        GTK_TREE_VIEW(treeview));
+  drawing->horizontal_sel = height * path_indices[0];
+  g_critical("new hor sel : %i", drawing->horizontal_sel);
+}
+#endif //0
+
+/* mouse click */
+static gboolean
+button_press_event( GtkWidget *widget, GdkEventButton *event, gpointer user_data )
+{
+  ControlFlowData *control_flow_data =
+      (ControlFlowData*)g_object_get_data(
+                G_OBJECT(widget),
+                "control_flow_data");
+  Drawing_t *drawing = control_flow_data->drawing;
+  TimeWindow time_window =
+               lttvwindow_get_time_window(control_flow_data->tab);
+
+  g_debug("click");
+  if(event->button == 1)
+  {
+    LttTime time;
+
+    /* left mouse button click */
+    g_debug("x click is : %f", event->x);
+
+    convert_pixels_to_time(drawing->width, (guint)event->x,
+        time_window,
+        &time);
+
+    lttvwindow_report_current_time(control_flow_data->tab, time);
+
+  }
+
+  return FALSE;
+}
+
+static gboolean
+scrollbar_size_allocate(GtkWidget *widget,
+                        GtkAllocation *allocation,
+                        gpointer user_data)
+{
+  Drawing_t *drawing = (Drawing_t*)user_data;
+
+  gtk_widget_set_size_request(drawing->padding, allocation->width, -1);
+  //gtk_widget_queue_resize(drawing->padding);
+  //gtk_widget_queue_resize(drawing->ruler);
+  gtk_container_check_resize(GTK_CONTAINER(drawing->ruler_hbox));
+  return 0;
+}
+
+
+
+Drawing_t *drawing_construct(ControlFlowData *control_flow_data)
+{
+  Drawing_t *drawing = g_new(Drawing_t, 1);
+  
+  drawing->control_flow_data = control_flow_data;
+
+  drawing->vbox = gtk_vbox_new(FALSE, 1);
+
+  
+  drawing->ruler_hbox = gtk_hbox_new(FALSE, 1);
+  drawing->ruler = gtk_drawing_area_new ();
+  //gtk_widget_set_size_request(drawing->ruler, -1, 27);
+  
+  drawing->padding = gtk_drawing_area_new ();
+  //gtk_widget_set_size_request(drawing->padding, -1, 27);
+  gtk_box_pack_start(GTK_BOX(drawing->ruler_hbox), drawing->ruler, 
+                     TRUE, TRUE, 0);
+  gtk_box_pack_end(GTK_BOX(drawing->ruler_hbox), drawing->padding, 
+                     FALSE, FALSE, 0);
+  
+
+
+  drawing->drawing_area = gtk_drawing_area_new ();
+  
+  drawing->gc = NULL;
+  
+  drawing->hbox = gtk_hbox_new(FALSE, 1);
+  drawing->viewport = gtk_viewport_new(NULL, control_flow_data->v_adjust);
+  drawing->scrollbar = gtk_vscrollbar_new(control_flow_data->v_adjust);
+  gtk_box_pack_start(GTK_BOX(drawing->hbox), drawing->viewport, 
+                     TRUE, TRUE, 0);
+  gtk_box_pack_end(GTK_BOX(drawing->hbox), drawing->scrollbar, 
+                     FALSE, FALSE, 0);
+  
+  //drawing->scrolled_window =
+  //    gtk_scrolled_window_new (NULL,
+  //    control_flow_data->v_adjust);
+  
+  //gtk_scrolled_window_set_policy(
+  //  GTK_SCROLLED_WINDOW(drawing->scrolled_window),
+  //  GTK_POLICY_NEVER,
+  //  GTK_POLICY_AUTOMATIC);
+
+  gtk_container_add(GTK_CONTAINER(drawing->viewport),
+                    drawing->drawing_area);
+  //gtk_scrolled_window_add_with_viewport(
+  //  GTK_SCROLLED_WINDOW(drawing->scrolled_window),
+  //  drawing->drawing_area);
+
+  gtk_box_pack_start(GTK_BOX(drawing->vbox), drawing->ruler_hbox, 
+                     FALSE, FALSE, 0);
+  gtk_box_pack_end(GTK_BOX(drawing->vbox), drawing->hbox,
+                   TRUE, TRUE, 0);
+  
+  drawing->pango_layout =
+    gtk_widget_create_pango_layout(drawing->drawing_area, NULL);
+
+  drawing->height = 1;
+  drawing->width = 1;
+  drawing->depth = 0;
+  drawing->alloc_height = 1;
+  drawing->alloc_width = 1;
+  
+  drawing->damage_begin = 0;
+  drawing->damage_end = 0;
+  drawing->horizontal_sel = -1;
+  
+  //gtk_widget_set_size_request(drawing->drawing_area->window, 50, 50);
+  g_object_set_data_full(
+      G_OBJECT(drawing->drawing_area),
+      "Link_drawing_Data",
+      drawing,
+      (GDestroyNotify)drawing_destroy);
+
+  g_object_set_data(
+      G_OBJECT(drawing->ruler),
+      "drawing",
+      drawing);
+
+
+  //gtk_widget_modify_bg( drawing->drawing_area,
+  //      GTK_STATE_NORMAL,
+  //      &CF_Colors[BLACK]);
+  
+  //gdk_window_get_geometry(drawing->drawing_area->window,
+  //    NULL, NULL,
+  //    &(drawing->width),
+  //    &(drawing->height),
+  //    -1);
+  
+  //drawing->pixmap = gdk_pixmap_new(
+  //    drawing->drawing_area->window,
+  //    drawing->width,
+  //    drawing->height,
+  //    drawing->depth);
+  
+  //drawing->pixmap = NULL;
+
+//  drawing->pixmap = gdk_pixmap_new(drawing->drawing_area->window,
+//        drawing->drawing_area->allocation.width,
+//        drawing->drawing_area->allocation.height,
+//        -1);
+
+  g_signal_connect (G_OBJECT(drawing->drawing_area),
+        "configure_event",
+        G_CALLBACK (configure_event),
+        (gpointer)drawing);
+  g_signal_connect (G_OBJECT(drawing->ruler),
+        "expose_event",
+        G_CALLBACK(expose_ruler),
+        (gpointer)drawing);
+
+  gtk_widget_add_events(drawing->ruler, GDK_POINTER_MOTION_MASK);
+
+  g_signal_connect (G_OBJECT(drawing->ruler),
+        "motion-notify-event",
+        G_CALLBACK(motion_notify_ruler),
+        (gpointer)drawing);
+
+
+  g_signal_connect (G_OBJECT(drawing->scrollbar),
+        "size-allocate",
+        G_CALLBACK(scrollbar_size_allocate),
+        (gpointer)drawing);
+
+
+
+  g_signal_connect (G_OBJECT(drawing->drawing_area),
+        "expose_event",
+        G_CALLBACK (expose_event),
+        (gpointer)drawing);
+
+  g_signal_connect_after (G_OBJECT(drawing->drawing_area),
+        "expose_event",
+        G_CALLBACK (after_expose_event),
+        (gpointer)drawing);
+
+  g_signal_connect (G_OBJECT(drawing->drawing_area),
+        "button-press-event",
+        G_CALLBACK (button_press_event),
+        (gpointer)drawing);
+  
+
+  gtk_widget_show(drawing->ruler);
+  gtk_widget_show(drawing->padding);
+  gtk_widget_show(drawing->ruler_hbox);
+
+  gtk_widget_show(drawing->drawing_area);
+  //gtk_widget_show(drawing->scrolled_window);
+  gtk_widget_show(drawing->viewport);
+  gtk_widget_show(drawing->scrollbar);
+  gtk_widget_show(drawing->hbox);
+
+  /* Allocate the colors */
+  GdkColormap* colormap = gdk_colormap_get_system();
+  gboolean success[NUM_COLORS];
+  gdk_colormap_alloc_colors(colormap, drawing_colors, NUM_COLORS, FALSE,
+                            TRUE, success);
+  
+  drawing->gc =
+    gdk_gc_new(GDK_DRAWABLE(main_window_get_widget(control_flow_data->tab)->window));
+  drawing->dotted_gc =
+    gdk_gc_new(GDK_DRAWABLE(main_window_get_widget(control_flow_data->tab)->window));
+
+  gdk_gc_copy(drawing->gc,
+      main_window_get_widget(control_flow_data->tab)->style->black_gc);
+  gdk_gc_copy(drawing->dotted_gc,
+      main_window_get_widget(control_flow_data->tab)->style->white_gc);
+  
+  gint8 dash_list[] = { 1, 2 };
+  gdk_gc_set_line_attributes(drawing->dotted_gc,
+                             1,
+                             GDK_LINE_ON_OFF_DASH,
+                             GDK_CAP_BUTT,
+                             GDK_JOIN_MITER);
+  gdk_gc_set_dashes(drawing->dotted_gc,
+                    0,
+                    dash_list,
+                    2);
+
+  drawing->ruler_gc_butt = 
+    gdk_gc_new(GDK_DRAWABLE(main_window_get_widget(control_flow_data->tab)->window));
+  gdk_gc_copy(drawing->ruler_gc_butt, 
+      main_window_get_widget(control_flow_data->tab)->style->black_gc);
+  drawing->ruler_gc_round = 
+    gdk_gc_new(GDK_DRAWABLE(main_window_get_widget(control_flow_data->tab)->window));
+  gdk_gc_copy(drawing->ruler_gc_round, 
+      main_window_get_widget(control_flow_data->tab)->style->black_gc);
+
+
+  gdk_gc_set_line_attributes(drawing->ruler_gc_butt,
+                               2,
+                               GDK_LINE_SOLID,
+                               GDK_CAP_BUTT,
+                               GDK_JOIN_MITER);
+
+  gdk_gc_set_line_attributes(drawing->ruler_gc_round,
+                             2,
+                             GDK_LINE_SOLID,
+                             GDK_CAP_ROUND,
+                             GDK_JOIN_ROUND);
+
+  
+  return drawing;
+}
+
+void drawing_destroy(Drawing_t *drawing)
+{
+  g_info("drawing_destroy %p", drawing);
+
+  /* Free the colors */
+  GdkColormap* colormap = gdk_colormap_get_system();
+
+  gdk_colormap_free_colors(colormap, drawing_colors, NUM_COLORS);
+  
+
+
+  // Do not unref here, Drawing_t destroyed by it's widget.
+  //g_object_unref( G_OBJECT(drawing->drawing_area));
+  if(drawing->gc != NULL)
+    gdk_gc_unref(drawing->gc);
+  
+  g_object_unref(drawing->pango_layout);
+  if(drawing->dotted_gc != NULL) gdk_gc_unref(drawing->dotted_gc);
+  if(drawing->ruler_gc_butt != NULL) gdk_gc_unref(drawing->ruler_gc_butt);
+  if(drawing->ruler_gc_round != NULL) gdk_gc_unref(drawing->ruler_gc_round);
+
+  g_free(drawing);
+  g_info("drawing_destroy end");
+}
+
+GtkWidget *drawing_get_drawing_area(Drawing_t *drawing)
+{
+  return drawing->drawing_area;
+}
+
+GtkWidget *drawing_get_widget(Drawing_t *drawing)
+{
+  return drawing->vbox;
+}
+
+void drawing_draw_line( Drawing_t *drawing,
+      GdkPixmap *pixmap,
+      guint x1, guint y1,
+      guint x2, guint y2,
+      GdkGC *GC)
+{
+  gdk_draw_line (pixmap,
+      GC,
+      x1, y1, x2, y2);
+}
+
+void drawing_clear(Drawing_t *drawing)
+{ 
+  //if (drawing->pixmap)
+  //  gdk_pixmap_unref(drawing->pixmap);
+  ControlFlowData *cfd = drawing->control_flow_data;
+
+  
+  rectangle_pixmap(cfd->process_list,
+      drawing->drawing_area->style->black_gc,
+      TRUE,
+      0, 0,
+      drawing->alloc_width,  // do not overlap
+      -1);
+  
+  //drawing->height = 1;
+  /* Allocate a new pixmap with new height */
+  //drawing->pixmap = gdk_pixmap_new(drawing->drawing_area->window,
+  //                                 drawing->width + SAFETY + EXTRA_ALLOC,
+  //                                 drawing->height + EXTRA_ALLOC,
+  //                                   -1);
+  //drawing->alloc_width = drawing->width + SAFETY + EXTRA_ALLOC;
+  //drawing->alloc_height = drawing->height + EXTRA_ALLOC;
+
+  //gtk_widget_set_size_request(drawing->drawing_area,
+  //                           -1,
+  //                           drawing->height);
+  //gtk_widget_queue_resize_no_redraw(drawing->drawing_area);
+  
+  /* ask for the buffer to be redrawn */
+  gtk_widget_queue_draw ( drawing->drawing_area);
+}
+
+#if 0
+/* Insert a square corresponding to a new process in the list */
+/* Applies to whole drawing->width */
+void drawing_insert_square(Drawing_t *drawing,
+        guint y,
+        guint height)
+{
+  //GdkRectangle update_rect;
+  gboolean reallocate = FALSE;
+  GdkPixmap *new_pixmap;
+
+  /* Allocate a new pixmap with new height */
+  if(drawing->alloc_height < drawing->height + height) {
+
+    new_pixmap = gdk_pixmap_new(drawing->drawing_area->window,
+                                     drawing->width + SAFETY + EXTRA_ALLOC,
+                                     drawing->height + height + EXTRA_ALLOC,
+                                     -1);
+    drawing->alloc_width = drawing->width + SAFETY + EXTRA_ALLOC;
+    drawing->alloc_height = drawing->height + height + EXTRA_ALLOC;
+    reallocate = TRUE;
+
+    /* Copy the high region */
+    gdk_draw_pixmap (new_pixmap,
+      drawing->drawing_area->style->black_gc,
+      drawing->pixmap,
+      0, 0,
+      0, 0,
+      drawing->width + SAFETY, y);
+
+  } else {
+    new_pixmap = drawing->pixmap;
+  }
+
+  //GdkPixmap *pixmap = gdk_pixmap_new(drawing->drawing_area->window,
+  //      drawing->width + SAFETY,
+  //      drawing->height + height,
+  //      -1);
+  
+  /* add an empty square */
+  gdk_draw_rectangle (new_pixmap,
+    drawing->drawing_area->style->black_gc,
+    TRUE,
+    0, y,
+    drawing->width + SAFETY,  // do not overlap
+    height);
+
+  /* copy the bottom of the region */
+  gdk_draw_pixmap (new_pixmap,
+    drawing->drawing_area->style->black_gc,
+    drawing->pixmap,
+    0, y,
+    0, y + height,
+    drawing->width+SAFETY, drawing->height - y);
+
+
+  if(reallocate && likely(drawing->pixmap)) {
+    gdk_pixmap_unref(drawing->pixmap);
+    drawing->pixmap = new_pixmap;
+  }
+  
+  if(unlikely(drawing->height==1)) drawing->height = height;
+  else drawing->height += height;
+  
+  gtk_widget_set_size_request(drawing->drawing_area,
+                             -1,
+                             drawing->height);
+  gtk_widget_queue_resize_no_redraw(drawing->drawing_area);
+  
+  /* ask for the buffer to be redrawn */
+  gtk_widget_queue_draw_area ( drawing->drawing_area,
+                               0, y,
+                               drawing->width, drawing->height-y);
+}
+
+
+/* Remove a square corresponding to a removed process in the list */
+void drawing_remove_square(Drawing_t *drawing,
+        guint y,
+        guint height)
+{
+  GdkPixmap *pixmap;
+
+  if(unlikely((guint)drawing->height == height)) {
+    //pixmap = gdk_pixmap_new(
+    //    drawing->drawing_area->window,
+    //    drawing->width + SAFETY,
+    //    1,
+    //    -1);
+    pixmap = drawing->pixmap;
+    drawing->height=1;
+  } else {
+    /* Allocate a new pixmap with new height */
+     //pixmap = gdk_pixmap_new(
+     //   drawing->drawing_area->window,
+     //   drawing->width + SAFETY,
+     //   drawing->height - height,
+     //   -1);
+     /* Keep the same preallocated pixmap */
+    pixmap = drawing->pixmap;
+   
+    /* Copy the high region */
+    gdk_draw_pixmap (pixmap,
+      drawing->drawing_area->style->black_gc,
+      drawing->pixmap,
+      0, 0,
+      0, 0,
+      drawing->width + SAFETY, y);
+
+    /* Copy up the bottom of the region */
+    gdk_draw_pixmap (pixmap,
+      drawing->drawing_area->style->black_gc,
+      drawing->pixmap,
+      0, y + height,
+      0, y,
+      drawing->width, drawing->height - y - height);
+
+    drawing->height-=height;
+  }
+
+  //if(likely(drawing->pixmap))
+  //  gdk_pixmap_unref(drawing->pixmap);
+
+  //drawing->pixmap = pixmap;
+  
+  gtk_widget_set_size_request(drawing->drawing_area,
+                             -1,
+                             drawing->height);
+  gtk_widget_queue_resize_no_redraw(drawing->drawing_area);
+  /* ask for the buffer to be redrawn */
+  gtk_widget_queue_draw_area ( drawing->drawing_area,
+                               0, y,
+                               drawing->width, MAX(drawing->height-y, 1));
+}
+#endif //0
+
+void drawing_update_ruler(Drawing_t *drawing, TimeWindow *time_window)
+{
+  GtkRequisition req;
+  GdkRectangle rect;
+  
+  req.width = drawing->ruler->allocation.width;
+  req.height = drawing->ruler->allocation.height;
+
+  rect.x = 0;
+  rect.y = 0;
+  rect.width = req.width;
+  rect.height = req.height;
+
+  gtk_widget_queue_draw(drawing->ruler);
+  //gtk_widget_draw( drawing->ruler, &rect);
+}
+
+/* Redraw the ruler */
+static gboolean
+expose_ruler( GtkWidget *widget, GdkEventExpose *event, gpointer user_data )
+{
+  Drawing_t *drawing = (Drawing_t*)user_data;
+  TimeWindow time_window = lttvwindow_get_time_window(drawing->control_flow_data->tab);
+  gchar text[255];
+  
+  PangoContext *context;
+  PangoLayout *layout;
+  PangoFontDescription *FontDesc;
+  PangoRectangle ink_rect;
+  gint global_width=0;
+  GdkColor foreground = { 0, 0, 0, 0 };
+  GdkColor background = { 0, 0xffff, 0xffff, 0xffff };
+
+  LttTime window_end = time_window.end_time;
+  LttTime half_width =
+    ltt_time_div(time_window.time_width,2.0);
+  LttTime window_middle =
+    ltt_time_add(half_width,
+                 time_window.start_time);
+  g_debug("ruler expose event");
+  gdk_draw_rectangle (drawing->ruler->window,
+          drawing->ruler->style->white_gc,
+          TRUE,
+          event->area.x, event->area.y,
+          event->area.width,
+          event->area.height);
+
+  gdk_draw_line (drawing->ruler->window,
+                  drawing->ruler_gc_butt,
+                  event->area.x, 1,
+                  event->area.x + event->area.width, 1);
+
+
+  snprintf(text, 255, "%lus\n%luns",
+    time_window.start_time.tv_sec,
+    time_window.start_time.tv_nsec);
+
+  layout = gtk_widget_create_pango_layout(drawing->drawing_area, NULL);
+
+  context = pango_layout_get_context(layout);
+  FontDesc = pango_context_get_font_description(context);
+
+  pango_font_description_set_size(FontDesc, 6*PANGO_SCALE);
+  pango_layout_context_changed(layout);
+
+  pango_layout_set_text(layout, text, -1);
+  pango_layout_get_pixel_extents(layout, &ink_rect, NULL);
+  global_width += ink_rect.width;
+
+  gdk_draw_layout_with_colors(drawing->ruler->window,
+      drawing->ruler_gc_butt,
+      0,
+      6,
+      layout, &foreground, &background);
+
+  gdk_draw_line (drawing->ruler->window,
+                   drawing->ruler_gc_round,
+                   1, 1,
+                   1, 7);
+
+
+  snprintf(text, 255, "%lus\n%luns", window_end.tv_sec,
+                                     window_end.tv_nsec);
+
+  pango_layout_set_text(layout, text, -1);
+  pango_layout_get_pixel_extents(layout, &ink_rect, NULL);
+  global_width += ink_rect.width;
+
+  if(global_width <= drawing->ruler->allocation.width)
+  {
+    gdk_draw_layout_with_colors(drawing->ruler->window,
+      drawing->ruler_gc_butt,
+      drawing->ruler->allocation.width - ink_rect.width,
+      6,
+      layout, &foreground, &background);
+
+    gdk_draw_line (drawing->ruler->window,
+                   drawing->ruler_gc_butt,
+                   drawing->ruler->allocation.width-1, 1,
+                   drawing->ruler->allocation.width-1, 7);
+  }
+
+
+  snprintf(text, 255, "%lus\n%luns", window_middle.tv_sec,
+                                     window_middle.tv_nsec);
+
+  pango_layout_set_text(layout, text, -1);
+  pango_layout_get_pixel_extents(layout, &ink_rect, NULL);
+  global_width += ink_rect.width;
+
+  if(global_width <= drawing->ruler->allocation.width)
+  {
+    gdk_draw_layout_with_colors(drawing->ruler->window,
+      drawing->ruler_gc_butt,
+      (drawing->ruler->allocation.width - ink_rect.width)/2,
+      6,
+      layout, &foreground, &background);
+
+    gdk_draw_line (drawing->ruler->window,
+                   drawing->ruler_gc_butt,
+                   drawing->ruler->allocation.width/2, 1,
+                   drawing->ruler->allocation.width/2, 7);
+
+
+
+
+  }
+
+  g_object_unref(layout);
+   
+  return FALSE;
+}
+
+
+/* notify mouse on ruler */
+static gboolean
+motion_notify_ruler(GtkWidget *widget, GdkEventMotion *event, gpointer user_data)
+{
+  //g_debug("motion");
+  //eventually follow mouse and show time here
+  return 0;
+}
diff --git a/ltt/branches/poly/lttv/modules/gui/resourceview/drawing.h b/ltt/branches/poly/lttv/modules/gui/resourceview/drawing.h
new file mode 100644 (file)
index 0000000..58f562a
--- /dev/null
@@ -0,0 +1,221 @@
+/* This file is part of the Linux Trace Toolkit viewer
+ * Copyright (C) 2003-2004 Mathieu Desnoyers
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License Version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, 
+ * MA 02111-1307, USA.
+ */
+
+
+#ifndef _DRAWING_H
+#define _DRAWING_H
+
+#include <glib.h>
+#include <gdk/gdk.h>
+#include <gtk/gtk.h>
+#include <ltt/ltt.h>
+#include <lttv/tracecontext.h>
+#include <lttv/state.h>
+#include <lttvwindow/lttvwindow.h>
+#include "cfv.h"
+#include "drawitem.h"
+
+
+#define SAFETY 50 // safety pixels at right and bottom of pixmap buffer
+
+typedef enum _draw_color {
+                COL_BLACK,
+                COL_WHITE,
+                COL_RUN_USER_MODE,/* green */
+                COL_RUN_SYSCALL,  /* pale blue */
+                COL_RUN_TRAP,     /* yellow */
+                COL_RUN_IRQ,      /* orange */
+                COL_RUN_SOFT_IRQ, /* red */
+                COL_WAIT,         /* dark red */
+                COL_WAIT_CPU,     /* dark yellow */
+                COL_ZOMBIE,       /* dark purple */
+                COL_WAIT_FORK,    /* dark green */
+                COL_EXIT,         /* "less dark" magenta */
+                COL_MODE_UNKNOWN, /* white */
+                COL_UNNAMED,      /* white */
+                NUM_COLORS } draw_color; 
+
+extern GdkColor drawing_colors[NUM_COLORS];
+
+/* This part of the viewer does :
+ * Draw horizontal lines, getting graphic context as arg.
+ * Copy region of the screen into another.
+ * Modify the boundaries to reflect a scale change. (resize)
+ * Refresh the physical screen with the pixmap
+ * A helper function is provided here to convert from time to process
+ * identifier to pixels and the contrary (will be useful for mouse selection).
+ * Insert an empty square in the drawing, moving the bottom part.
+ *
+ * Note: The last point is exactly why it would not be so easy to add the
+ * vertical line functionnality as in the original version of LTT. In order
+ * to do so, we should keep all processes in the list for the duration of
+ * all the trace instead of dynamically adding and removing them when we
+ * scroll. Another possibility is to redraw all the visible area when a new
+ * process is added to the list. The second solution seems more appropriate
+ * to me.
+ * 
+ *
+ * The pixmap used has the width of the physical window, but the height
+ * of the shown processes.
+ */
+
+#ifndef TYPE_DRAWING_T_DEFINED
+#define TYPE_DRAWING_T_DEFINED
+typedef struct _Drawing_t Drawing_t;
+#endif //TYPE_DRAWING_T_DEFINED
+
+#ifndef TYPE_CONTROLFLOWDATA_DEFINED
+#define TYPE_CONTROLFLOWDATA_DEFINED
+typedef struct _ControlFlowData ControlFlowData;
+#endif //TYPE_CONTROLFLOWDATA_DEFINED
+
+struct _Drawing_t {
+  GtkWidget *vbox;
+  GtkWidget *drawing_area;
+  //GtkWidget *scrolled_window;
+  GtkWidget *hbox;
+  GtkWidget *viewport;
+  GtkWidget *scrollbar;
+  
+  GtkWidget *ruler_hbox;
+  GtkWidget *ruler;
+  GtkWidget *padding;
+  //GdkPixmap *pixmap;
+  ControlFlowData *control_flow_data;
+  
+  PangoLayout *pango_layout;
+
+  gint      height, width, depth;
+  /* height and width of allocated buffer pixmap */
+  gint      alloc_height, alloc_width;
+  
+  /* X coordinate of damaged region */
+  gint      damage_begin, damage_end; /* damaged region to be exposed,
+                                         updated per chunk */
+  LttTime   last_start;               
+  GdkGC     *dotted_gc;
+  GdkGC     *gc;
+  GdkGC     *ruler_gc_butt;
+  GdkGC     *ruler_gc_round;
+
+  /* Position of the horizontal selector, -1 for none */
+  gint horizontal_sel;
+};
+
+Drawing_t *drawing_construct(ControlFlowData *control_flow_data);
+void drawing_destroy(Drawing_t *drawing);
+
+GtkWidget *drawing_get_widget(Drawing_t *drawing);
+GtkWidget *drawing_get_drawing_area(Drawing_t *drawing);
+
+
+void drawing_data_request(Drawing_t *drawing,
+      gint x, gint y,
+      gint width,
+      gint height);
+
+void drawing_draw_line( Drawing_t *drawing,
+      GdkPixmap *pixmap,
+      guint x1, guint y1,
+      guint x2, guint y2,
+      GdkGC *GC);
+
+//void drawing_copy( Drawing_t *drawing,
+//    guint xsrc, guint ysrc,
+//    guint xdest, guint ydest,
+//    guint width, guint height);
+
+/* Clear the drawing : make it 1xwidth. */
+void drawing_clear(Drawing_t *drawing);
+
+/* Insert a square corresponding to a new process in the list */
+void drawing_insert_square(Drawing_t *drawing,
+        guint y,
+        guint height);
+
+/* Remove a square corresponding to a removed process in the list */
+void drawing_remove_square(Drawing_t *drawing,
+        guint y,
+        guint height);
+
+void drawing_update_ruler(Drawing_t *drawing, TimeWindow *time_window);
+
+void drawing_request_expose(EventsRequest *events_request,
+                            LttvTracesetState *tss,
+                            LttTime end_time);
+
+void drawing_data_request_begin(EventsRequest *events_request,
+                                LttvTracesetState *tss);
+void drawing_chunk_begin(EventsRequest *events_request, LttvTracesetState *tss);
+
+
+
+void
+tree_row_activated(GtkTreeModel *treemodel,
+                   GtkTreePath *arg1,
+                   GtkTreeViewColumn *arg2,
+                   gpointer user_data);
+
+
+/* convert_pixels_to_time
+ *
+ * Convert from window pixel and time interval to an absolute time.
+ */
+static inline void convert_pixels_to_time(
+    gint width,
+    guint x,
+    TimeWindow time_window,
+    LttTime *time)
+{
+  double time_d;
+  
+  time_d = time_window.time_width_double;
+  time_d = time_d / (double)width * (double)x;
+  *time = ltt_time_from_double(time_d);
+  *time = ltt_time_add(time_window.start_time, *time);
+}
+
+
+static inline void convert_time_to_pixels(
+    TimeWindow time_window,
+    LttTime time,
+    int width,
+    guint *x)
+{
+  double time_d;
+#ifdef EXTRA_CHECK 
+  g_assert(ltt_time_compare(window_time_begin, time) <= 0 &&
+           ltt_time_compare(window_time_end, time) >= 0);
+#endif //EXTRA_CHECK
+  
+  time = ltt_time_sub(time, time_window.start_time);
+  
+  time_d = ltt_time_to_double(time);
+  
+  if(time_window.time_width_double == 0.0) {
+    g_assert(time_d == 0.0);
+    *x = 0;
+  } else {
+    *x = (guint)(time_d / time_window.time_width_double * (double)width);
+  }
+  
+}
+
+
+
+#endif // _DRAWING_H
diff --git a/ltt/branches/poly/lttv/modules/gui/resourceview/drawitem.c b/ltt/branches/poly/lttv/modules/gui/resourceview/drawitem.c
new file mode 100644 (file)
index 0000000..d97628b
--- /dev/null
@@ -0,0 +1,465 @@
+/* This file is part of the Linux Trace Toolkit viewer
+ * Copyright (C) 2003-2004 Mathieu Desnoyers
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License Version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, 
+ * MA 02111-1307, USA.
+ */
+
+
+
+/******************************************************************************
+ * drawitem.c
+ *
+ * This file contains methods responsible for drawing a generic type of data
+ * in a drawable. Doing this generically will permit user defined drawing
+ * behavior in a later time.
+ *
+ * This file provides an API which is meant to be reusable for all viewers that
+ * need to show information in line, icon, text, background or point form in
+ * a drawable area having time for x axis. The y axis, in the control flow
+ * viewer case, is corresponding to the different processes, but it can be
+ * reused integrally for cpu, and eventually locks, buffers, network
+ * interfaces... What will differ between the viewers is the precise
+ * information which interests us. We may think that the most useful
+ * information for control flow are some specific events, like schedule
+ * change, and processes'states. It may differ for a cpu viewer : the
+ * interesting information could be more the execution mode of each cpu.
+ * This API in meant to make viewer's writers life easier : it will become
+ * a simple choice of icons and line types for the precise information
+ * the viewer has to provide (agremented with keeping supplementary records
+ * and modifying slightly the DrawContext to suit the needs.)
+ *
+ * We keep each data type in attributes, keys to specific information
+ * being formed from the GQuark corresponding to the information received.
+ * (facilities / facility_name / events / eventname.)
+ * (cpus/cpu_name, process_states/ps_name,
+ * execution_modes/em_name, execution_submodes/es_name).
+ * The goal is then to provide a generic way to print information on the
+ * screen for all this different information.
+ *
+ * Information can be printed as
+ *
+ * - text (text + color + size + position (over or under line)
+ * - icon (icon filename, corresponding to a loaded icon, accessible through
+ *   a GQuark. Icons are loaded statically at the guiControlFlow level during
+ *   module initialization and can be added on the fly if not present in the
+ *   GQuark.) The habitual place for xpm icons is in
+ *   ${prefix}/share/LinuxTraceToolkit.) + position (over or under line)
+ * - line (color, width, style)
+ * - Arc (big points) (color, size)
+ * - background color (color)
+ *
+ * An item is a leaf of the attributes tree. It is, in that case, including
+ * all kind of events categories we can have. It then associates each category
+ * with one or more actions (drawing something) or nothing.
+ * 
+ * Each item has an array of hooks (hook list). Each hook represents an
+ * operation to perform. We seek the array each time we want to
+ * draw an item. We execute each operation in order. An operation type
+ * is associated with each hook to permit user listing and modification
+ * of these operations. The operation type is also used to find the
+ * corresponding priority for the sorting. Operation type and priorities
+ * are enum and a static int table.
+ *
+ * The array has to be sorted by priority each time we add a task in it.
+ * A priority is associated with each operation type. It permits
+ * to perform background color selection before line or text drawing. We also
+ * draw lines before text, so the text appears over the lines.
+ *
+ * Executing all the arrays of operations for a specific event (which
+ * implies information for state, event, cpu, execution mode and submode)
+ * has to be done in a same DrawContext. The goal there is to keep the offset
+ * of the text and icons over and under the middle line, so a specific
+ * event could be printed as (  R Si 0 for running, scheduled in, cpu 0  ),
+ * text being easy to replace with icons. The DrawContext is passed as
+ * call_data for the operation hooks.
+ *
+ * We use the lttv global attributes to keep track of the loaded icons.
+ * If we need an icon, we look for it in the icons / icon name pathname.
+ * If found, we use the pointer to it. If not, we load the pixmap in
+ * memory and set the pointer to the GdkPixmap in the attributes. The
+ * structure pointed to contains the pixmap and the mask bitmap.
+ * 
+ * Author : Mathieu Desnoyers, October 2003
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include <gtk/gtk.h>
+#include <gdk/gdk.h>
+#include <lttv/hook.h>
+#include <lttv/attribute.h>
+#include <lttv/iattribute.h>
+#include <string.h>
+
+#include <lttv/tracecontext.h>
+#include <lttv/state.h>
+#include <lttv/lttv.h>
+
+#include "drawing.h"
+#include "drawitem.h"
+
+
+#define MAX_PATH_LEN 256
+
+/* drawing hook functions */
+gboolean draw_text( void *hook_data, void *call_data)
+{
+  PropertiesText *properties = (PropertiesText*)hook_data;
+  DrawContext *draw_context = (DrawContext*)call_data;
+
+  PangoContext *context;
+  PangoLayout *layout;
+  PangoFontDescription *font_desc;// = pango_font_description_new();
+  PangoRectangle ink_rect;
+    
+  layout = draw_context->pango_layout;
+
+  context = pango_layout_get_context(layout);
+  font_desc = pango_context_get_font_description(context);
+
+  pango_font_description_set_size(font_desc, properties->size*PANGO_SCALE);
+  pango_layout_context_changed(layout);
+
+  pango_layout_set_text(layout, properties->text, -1);
+  pango_layout_get_pixel_extents(layout, &ink_rect, NULL);
+
+  gint x=0, y=0;
+  gint *offset=NULL;
+  gboolean enough_space = FALSE;
+  gint width = ink_rect.width;
+
+  switch(properties->position.x) {
+    case POS_START:
+      x = draw_context->drawinfo.start.x;
+      switch(properties->position.y) {
+        case OVER:
+          offset = &draw_context->drawinfo.start.offset.over;
+          x += draw_context->drawinfo.start.offset.over;
+          y = draw_context->drawinfo.y.over;
+          break;
+        case MIDDLE:
+          offset = &draw_context->drawinfo.start.offset.middle;
+          x += draw_context->drawinfo.start.offset.middle;
+          y = draw_context->drawinfo.y.middle;
+          break;
+        case UNDER:
+          offset = &draw_context->drawinfo.start.offset.under;
+          x += draw_context->drawinfo.start.offset.under;
+          y = draw_context->drawinfo.y.under;
+          break;
+      }
+      /* verify if there is enough space to draw */
+      if(unlikely(x + width <= draw_context->drawinfo.end.x)) {
+        enough_space = TRUE;
+        *offset += width;
+      }
+      break;
+    case POS_END:
+      x = draw_context->drawinfo.end.x;
+      switch(properties->position.y) {
+        case OVER:
+          offset = &draw_context->drawinfo.end.offset.over;
+          x += draw_context->drawinfo.end.offset.over;
+          y = draw_context->drawinfo.y.over;
+          break;
+        case MIDDLE:
+          offset = &draw_context->drawinfo.end.offset.middle;
+          x += draw_context->drawinfo.end.offset.middle;
+          y = draw_context->drawinfo.y.middle;
+          break;
+        case UNDER:
+          offset = &draw_context->drawinfo.end.offset.under;
+          x += draw_context->drawinfo.end.offset.under;
+          y = draw_context->drawinfo.y.under;
+          break;
+      }
+      /* verify if there is enough space to draw */
+      if(unlikely(x - width >= draw_context->drawinfo.start.x)) {
+        enough_space = TRUE;
+        *offset -= width;
+      }
+      break;
+  }
+
+  if(unlikely(enough_space))
+    gdk_draw_layout_with_colors(draw_context->drawable,
+              draw_context->gc,
+              x,
+              y,
+              layout, properties->foreground, properties->background);
+
+  return 0;
+}
+
+
+/* To speed up the process, search in already loaded icons list first. Only
+ * load it if not present.
+ */
+gboolean draw_icon( void *hook_data, void *call_data)
+{
+  PropertiesIcon *properties = (PropertiesIcon*)hook_data;
+  DrawContext *draw_context = (DrawContext*)call_data;
+
+  LttvIAttribute *attributes = LTTV_IATTRIBUTE(lttv_global_attributes());
+  LttvAttributeValue value;
+  gchar icon_name[MAX_PATH_LEN] = "icons/";
+  IconStruct *icon_info;
+
+  strcat(icon_name, properties->icon_name);
+  
+  g_assert(lttv_iattribute_find_by_path(attributes, icon_name,
+      LTTV_POINTER, &value));
+  if(unlikely(*(value.v_pointer) == NULL))
+  {
+    *(value.v_pointer) = icon_info = g_new(IconStruct,1);
+    
+    icon_info->pixmap = gdk_pixmap_create_from_xpm(draw_context->drawable,
+                          &icon_info->mask, NULL, properties->icon_name);
+  }
+  else
+  {
+    icon_info = *(value.v_pointer);
+  }
+  
+  gint x=0, y=0;
+  gint *offset=NULL;
+  gboolean enough_space = FALSE;
+  gint width = properties->width;
+  
+  switch(properties->position.x) {
+    case POS_START:
+      x = draw_context->drawinfo.start.x;
+      switch(properties->position.y) {
+        case OVER:
+          offset = &draw_context->drawinfo.start.offset.over;
+          x += draw_context->drawinfo.start.offset.over;
+          y = draw_context->drawinfo.y.over;
+          break;
+        case MIDDLE:
+          offset = &draw_context->drawinfo.start.offset.middle;
+          x += draw_context->drawinfo.start.offset.middle;
+          y = draw_context->drawinfo.y.middle;
+          break;
+        case UNDER:
+          offset = &draw_context->drawinfo.start.offset.under;
+          x += draw_context->drawinfo.start.offset.under;
+          y = draw_context->drawinfo.y.under;
+          break;
+      }
+      /* verify if there is enough space to draw */
+      if(unlikely(x + width <= draw_context->drawinfo.end.x)) {
+        enough_space = TRUE;
+        *offset += width;
+      }
+      break;
+    case POS_END:
+      x = draw_context->drawinfo.end.x;
+      switch(properties->position.y) {
+        case OVER:
+          offset = &draw_context->drawinfo.end.offset.over;
+          x += draw_context->drawinfo.end.offset.over;
+          y = draw_context->drawinfo.y.over;
+          break;
+        case MIDDLE:
+          offset = &draw_context->drawinfo.end.offset.middle;
+          x += draw_context->drawinfo.end.offset.middle;
+          y = draw_context->drawinfo.y.middle;
+          break;
+        case UNDER:
+          offset = &draw_context->drawinfo.end.offset.under;
+          x += draw_context->drawinfo.end.offset.under;
+          y = draw_context->drawinfo.y.under;
+          break;
+      }
+      /* verify if there is enough space to draw */
+      if(unlikely(x - width >= draw_context->drawinfo.start.x)) {
+        enough_space = TRUE;
+        *offset -= width;
+      }
+      break;
+  }
+
+  if(unlikely(enough_space)) {
+    gdk_gc_set_clip_mask(draw_context->gc, icon_info->mask);
+
+    gdk_gc_set_clip_origin(
+        draw_context->gc,
+        x,
+        y);
+    gdk_draw_drawable(draw_context->drawable, 
+        draw_context->gc,
+        icon_info->pixmap,
+        0, 0,
+        x,
+        y,
+        properties->width, properties->height);
+
+    gdk_gc_set_clip_origin(draw_context->gc, 0, 0);
+    gdk_gc_set_clip_mask(draw_context->gc, NULL);
+  }
+  return 0;
+}
+
+gboolean draw_line( void *hook_data, void *call_data)
+{
+  PropertiesLine *properties = (PropertiesLine*)hook_data;
+  DrawContext *draw_context = (DrawContext*)call_data;
+  
+  gdk_gc_set_foreground(draw_context->gc, &properties->color);
+  //gdk_gc_set_rgb_fg_color(draw_context->gc, &properties->color);
+  gdk_gc_set_line_attributes( draw_context->gc,
+                              properties->line_width,
+                              properties->style,
+                              GDK_CAP_BUTT,
+                              GDK_JOIN_MITER);
+  //g_critical("DRAWING LINE : x1: %i, y1: %i, x2:%i, y2:%i", 
+  //    draw_context->previous->middle->x,
+  //    draw_context->previous->middle->y,
+  //    draw_context->drawinfo.middle.x,
+  //    draw_context->drawinfo.middle.y);
+
+  gint x_begin=0, x_end=0, y=0;
+  
+  x_begin = draw_context->drawinfo.start.x;
+  x_end = draw_context->drawinfo.end.x;
+
+  switch(properties->y) {
+    case OVER:
+      y = draw_context->drawinfo.y.over;
+      break;
+    case MIDDLE:
+      y = draw_context->drawinfo.y.middle;
+      break;
+    case UNDER:
+      y = draw_context->drawinfo.y.under;
+      break;
+  }
+
+  drawing_draw_line(
+    NULL, draw_context->drawable,
+    x_begin,
+    y,
+    x_end,
+    y,
+    draw_context->gc);
+  
+  return 0;
+}
+
+gboolean draw_arc( void *hook_data, void *call_data)
+{
+  PropertiesArc *properties = (PropertiesArc*)hook_data;
+  DrawContext *draw_context = (DrawContext*)call_data;
+
+  gdk_gc_set_foreground(draw_context->gc, properties->color);
+  //gdk_gc_set_rgb_fg_color(draw_context->gc, properties->color);
+
+  gint x=0, y=0;
+  gint *offset=NULL;
+  gboolean enough_space = FALSE;
+  gint width = properties->size;
+  
+  switch(properties->position.x) {
+    case POS_START:
+      x = draw_context->drawinfo.start.x;
+      switch(properties->position.y) {
+        case OVER:
+          offset = &draw_context->drawinfo.start.offset.over;
+          x += draw_context->drawinfo.start.offset.over;
+          y = draw_context->drawinfo.y.over;
+          break;
+        case MIDDLE:
+          offset = &draw_context->drawinfo.start.offset.middle;
+          x += draw_context->drawinfo.start.offset.middle;
+          y = draw_context->drawinfo.y.middle;
+          break;
+        case UNDER:
+          offset = &draw_context->drawinfo.start.offset.under;
+          x += draw_context->drawinfo.start.offset.under;
+          y = draw_context->drawinfo.y.under;
+          break;
+      }
+      /* verify if there is enough space to draw */
+      if(unlikely(x + width <= draw_context->drawinfo.end.x)) {
+        enough_space = TRUE;
+        *offset += width;
+      }
+      break;
+    case POS_END:
+      x = draw_context->drawinfo.end.x;
+      switch(properties->position.y) {
+        case OVER:
+          offset = &draw_context->drawinfo.end.offset.over;
+          x += draw_context->drawinfo.end.offset.over;
+          y = draw_context->drawinfo.y.over;
+          break;
+        case MIDDLE:
+          offset = &draw_context->drawinfo.end.offset.middle;
+          x += draw_context->drawinfo.end.offset.middle;
+          y = draw_context->drawinfo.y.middle;
+          break;
+        case UNDER:
+          offset = &draw_context->drawinfo.end.offset.under;
+          x += draw_context->drawinfo.end.offset.under;
+          y = draw_context->drawinfo.y.under;
+          break;
+      }
+      /* verify if there is enough space to draw */
+      if(unlikely(x - width >= draw_context->drawinfo.start.x)) {
+        enough_space = TRUE;
+        *offset -= width;
+      }
+      break;
+  }
+
+  if(unlikely(enough_space))
+    gdk_draw_arc(draw_context->drawable, draw_context->gc,
+          properties->filled,
+          x,
+          y,
+          properties->size, properties->size, 0, 360*64);
+  
+  return 0;
+}
+
+gboolean draw_bg( void *hook_data, void *call_data)
+{
+  PropertiesBG *properties = (PropertiesBG*)hook_data;
+  DrawContext *draw_context = (DrawContext*)call_data;
+
+  gdk_gc_set_foreground(draw_context->gc, properties->color);
+  //gdk_gc_set_rgb_fg_color(draw_context->gc, properties->color);
+
+  //g_critical("DRAWING RECT : x: %i, y: %i, w:%i, h:%i, val1 :%i, val2:%i ", 
+  //    draw_context->previous->over->x,
+  //    draw_context->previous->over->y,
+  //    draw_context->drawinfo.over.x - draw_context->previous->over->x,
+  //    draw_context->previous->under->y-draw_context->previous->over->y,
+  //    draw_context->drawinfo.over.x,
+  //    draw_context->previous->over->x);
+  gdk_draw_rectangle(draw_context->drawable, draw_context->gc,
+          TRUE,
+          draw_context->drawinfo.start.x,
+          draw_context->drawinfo.y.over,
+          draw_context->drawinfo.end.x - draw_context->drawinfo.start.x,
+          draw_context->drawinfo.y.under - draw_context->drawinfo.y.over);
+
+  return 0;
+}
+
+
diff --git a/ltt/branches/poly/lttv/modules/gui/resourceview/drawitem.h b/ltt/branches/poly/lttv/modules/gui/resourceview/drawitem.h
new file mode 100644 (file)
index 0000000..28fdc18
--- /dev/null
@@ -0,0 +1,279 @@
+/* This file is part of the Linux Trace Toolkit viewer
+ * Copyright (C) 2003-2004 Mathieu Desnoyers
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License Version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, 
+ * MA 02111-1307, USA.
+ */
+
+
+#ifndef _DRAW_ITEM_H
+#define _DRAW_ITEM_H
+
+#include <lttv/state.h>
+
+typedef struct _DrawContext DrawContext;
+typedef struct _DrawInfo DrawInfo;
+typedef struct _ItemInfo ItemInfo;
+
+typedef struct _IconStruct IconStruct;
+
+typedef struct _DrawOperation DrawOperation;
+
+
+typedef struct _PropertiesText PropertiesText;
+typedef struct _PropertiesIcon PropertiesIcon;
+typedef struct _PropertiesLine PropertiesLine;
+typedef struct _PropertiesArc PropertiesArc;
+typedef struct _PropertiesBG PropertiesBG;
+
+typedef enum _DrawableItems DrawableItems;
+enum _DrawableItems {
+    ITEM_TEXT, ITEM_ICON, ITEM_LINE, ITEM_POINT, ITEM_BACKGROUND
+};
+
+typedef enum _RelPosX {
+  POS_START, POS_END
+} RelPosX;
+
+typedef enum _RelPosY {
+  OVER, MIDDLE, UNDER
+} RelPosY;
+
+
+/* The DrawContext keeps information about the current drawing position and
+ * the previous one, so we can use both to draw lines.
+ *
+ * over : position for drawing over the middle line.
+ * middle : middle line position.
+ * under : position for drawing under the middle line.
+ *
+ * the modify_* are used to take into account that we should go forward
+ * when we draw a text, an arc or an icon, while it's unneeded when we
+ * draw a line or background.
+ *
+ * The modify_* positions are altered by the draw item functions.
+ *
+ */
+
+
+struct _DrawContext {
+  GdkDrawable *drawable;
+  GdkGC   *gc;
+  PangoLayout *pango_layout;
+
+  struct {
+    struct {
+      gint x;
+      struct {
+        gint over;
+        gint middle;
+        gint under;
+      } offset;
+    } start;
+
+    struct {
+      gint x;
+      struct {
+        gint over;
+        gint middle;
+        gint under;
+      } offset;
+    } end;
+
+    struct {
+      gint over;
+      gint middle;
+      gint under;
+    } y;
+
+  } drawinfo;
+};
+
+
+
+
+/*
+ * Structure used to keep information about icons.
+ */
+struct _IconStruct {
+  GdkPixmap *pixmap;
+  GdkBitmap *mask;
+};
+
+
+/*
+ * The Item element is only used so the DrawOperation is modifiable by users.
+ * During drawing, only the Hook is needed.
+ */
+struct _DrawOperation {
+  DrawableItems item;
+  LttvHooks *hook;
+};
+#if 0
+/*
+ * We define here each items that can be drawn, together with their
+ * associated priority. Many item types can have the same priority,
+ * it's only used for quicksorting the operations when we add a new one
+ * to the array of operations to perform. Lower priorities are executed
+ * first. So, for example, we may want to give background color a value
+ * of 10 while a line would have 20, so the background color, which
+ * is in fact a rectangle, does not hide the line.
+ */
+
+static int Items_Priorities[] = {
+  50, /* ITEM_TEXT */
+  40, /* ITEM_ICON */
+  20, /* ITEM_LINE */
+  30, /* ITEM_POINT */
+  10  /* ITEM_BACKGROUND */
+};
+#endif //0
+
+/*
+ * Here are the different structures describing each item type that can be
+ * drawn. They contain the information necessary to draw the item : not the
+ * position (this is provided by the DrawContext), but the text, icon name,
+ * line width, color; all the properties of the specific items.
+ */
+
+struct _PropertiesText {
+  GdkColor  *foreground;
+  GdkColor  *background;
+  gint       size;
+  gchar     *text;
+  struct {
+    RelPosX    x;
+    RelPosY    y;
+  } position;
+};
+
+
+struct _PropertiesIcon {
+  gchar   *icon_name;
+  gint    width;
+  gint    height;
+  struct {
+    RelPosX    x;
+    RelPosY    y;
+  } position;
+};
+
+struct _PropertiesLine {
+  GdkColor  color;
+  gint    line_width;
+  GdkLineStyle  style;
+  RelPosY    y;
+};
+
+struct _PropertiesArc {
+  GdkColor  *color;
+  gint    size; /* We force circle by width = height */
+  gboolean  filled;
+  struct {
+    RelPosX    x;
+    RelPosY    y;
+  } position;
+};
+
+struct _PropertiesBG {
+  GdkColor  *color;
+};
+
+
+
+void draw_item( GdkDrawable *drawable,
+    gint x,
+    gint y,
+    LttvTraceState *ts,
+    LttvTracefileState *tfs,
+    LttvIAttribute *attributes);
+
+/*
+ * The tree of attributes used to store drawing operations goes like this :
+ *
+ * event_types/
+ *   "facility-event_type"
+ * cpus/
+ *   "cpu name"
+ * mode_types/
+ *   "execution mode"/
+ *     submodes/
+ *       "submode"
+ * process_states/
+ *   "state name"
+ * 
+ * So if, for example, we want to add a hook to get called each time we
+ * receive an event that is in state LTTV_STATE_SYSCALL, we put the
+ * pointer to the GArray of DrawOperation in
+ * process_states/ "name associated with LTTV_STATE_SYSCALL"
+ */
+
+
+#if 0
+/* 
+ * The add_operation has to do a quick sort by priority to keep the operations
+ * in the right order.
+ */
+void add_operation( LttvIAttribute *attributes,
+      gchar *pathname,
+      DrawOperation *operation);
+
+/* 
+ * The del_operation seeks the array present at pathname (if any) and
+ * removes the DrawOperation if present. It returns 0 on success, -1
+ * if it fails.
+ */
+gint del_operation( LttvIAttribute *attributes,
+      gchar *pathname,
+      DrawOperation *operation);
+
+/* 
+ * The clean_operations removes all operations present at a pathname.
+ * returns 0 on success, -1 if it fails.
+ */
+gint clean_operations(  LttvIAttribute *attributes,
+      gchar *pathname );
+
+
+/* 
+ * The list_operations gives a pointer to the operation array associated
+ * with the pathname. It will be NULL if no operation is present.
+ */
+void list_operations( LttvIAttribute *attributes,
+      gchar *pathname,
+      GArray **operation);
+
+
+
+/*
+ * exec_operation executes the operations if present in the attributes, or
+ * do nothing if not present.
+ */
+void exec_operations( LttvIAttribute *attributes,
+      gchar *pathname);
+#endif //0
+
+/*
+ * Here follow the prototypes of the hook functions used to draw the
+ * different items.
+ */
+
+gboolean draw_text( void *hook_data, void *call_data);
+gboolean draw_icon( void *hook_data, void *call_data);
+gboolean draw_line( void *hook_data, void *call_data);
+gboolean draw_arc( void *hook_data, void *call_data);
+gboolean draw_bg( void *hook_data, void *call_data);
+
+
+#endif // _DRAW_ITEM_H
diff --git a/ltt/branches/poly/lttv/modules/gui/resourceview/eventhooks.c b/ltt/branches/poly/lttv/modules/gui/resourceview/eventhooks.c
new file mode 100644 (file)
index 0000000..e87f7ed
--- /dev/null
@@ -0,0 +1,2763 @@
+/* This file is part of the Linux Trace Toolkit viewer
+ * Copyright (C) 2003-2004 Mathieu Desnoyers
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License Version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, 
+ * MA 02111-1307, USA.
+ */
+
+
+/*****************************************************************************
+ *                       Hooks to be called by the main window               *
+ *****************************************************************************/
+
+
+/* Event hooks are the drawing hooks called during traceset read. They draw the
+ * icons, text, lines and background color corresponding to the events read.
+ *
+ * Two hooks are used for drawing : before_schedchange and after_schedchange hooks. The
+ * before_schedchange is called before the state update that occurs with an event and
+ * the after_schedchange hook is called after this state update.
+ *
+ * The before_schedchange hooks fulfill the task of drawing the visible objects that
+ * corresponds to the data accumulated by the after_schedchange hook.
+ *
+ * The after_schedchange hook accumulates the data that need to be shown on the screen
+ * (items) into a queue. Then, the next before_schedchange hook will draw what that
+ * queue contains. That's the Right Way (TM) of drawing items on the screen,
+ * because we need to draw the background first (and then add icons, text, ...
+ * over it), but we only know the length of a background region once the state
+ * corresponding to it is over, which happens to be at the next before_schedchange
+ * hook.
+ *
+ * We also have a hook called at the end of a chunk to draw the information left
+ * undrawn in each process queue. We use the current time as end of
+ * line/background.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+//#define PANGO_ENABLE_BACKEND
+#include <gtk/gtk.h>
+#include <gdk/gdk.h>
+#include <glib.h>
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+
+//#include <pango/pango.h>
+
+#include <ltt/event.h>
+#include <ltt/time.h>
+#include <ltt/type.h>
+#include <ltt/trace.h>
+
+#include <lttv/lttv.h>
+#include <lttv/hook.h>
+#include <lttv/state.h>
+#include <lttvwindow/lttvwindow.h>
+#include <lttvwindow/lttvwindowtraces.h>
+#include <lttvwindow/support.h>
+
+
+#include "eventhooks.h"
+#include "cfv.h"
+#include "processlist.h"
+#include "drawing.h"
+
+
+#define MAX_PATH_LEN 256
+#define STATE_LINE_WIDTH 4
+#define COLLISION_POSITION(height) (((height - STATE_LINE_WIDTH)/2) -3)
+
+extern GSList *g_legend_list;
+
+
+/* Action to do when background computation completed.
+ *
+ * Wait for all the awaited computations to be over.
+ */
+
+static gint background_ready(void *hook_data, void *call_data)
+{
+  ControlFlowData *control_flow_data = (ControlFlowData *)hook_data;
+  LttvTrace *trace = (LttvTrace*)call_data;
+
+  control_flow_data->background_info_waiting--;
+  
+  if(control_flow_data->background_info_waiting == 0) {
+    g_message("control flow viewer : background computation data ready.");
+
+    drawing_clear(control_flow_data->drawing);
+    processlist_clear(control_flow_data->process_list);
+    gtk_widget_set_size_request(
+      control_flow_data->drawing->drawing_area,
+                -1, processlist_get_height(control_flow_data->process_list));
+    redraw_notify(control_flow_data, NULL);
+  }
+
+  return 0;
+}
+
+
+/* Request background computation. Verify if it is in progress or ready first.
+ * Only for each trace in the tab's traceset.
+ */
+static void request_background_data(ControlFlowData *control_flow_data)
+{
+  LttvTracesetContext * tsc =
+        lttvwindow_get_traceset_context(control_flow_data->tab);
+  gint num_traces = lttv_traceset_number(tsc->ts);
+  gint i;
+  LttvTrace *trace;
+  LttvTraceState *tstate;
+
+  LttvHooks *background_ready_hook = 
+    lttv_hooks_new();
+  lttv_hooks_add(background_ready_hook, background_ready, control_flow_data,
+      LTTV_PRIO_DEFAULT);
+  control_flow_data->background_info_waiting = 0;
+  
+  for(i=0;i<num_traces;i++) {
+    trace = lttv_traceset_get(tsc->ts, i);
+    tstate = LTTV_TRACE_STATE(tsc->traces[i]);
+
+    if(lttvwindowtraces_get_ready(g_quark_from_string("state"),trace)==FALSE
+        && !tstate->has_precomputed_states) {
+
+      if(lttvwindowtraces_get_in_progress(g_quark_from_string("state"),
+                                          trace) == FALSE) {
+        /* We first remove requests that could have been done for the same
+         * information. Happens when two viewers ask for it before servicing
+         * starts.
+         */
+        if(!lttvwindowtraces_background_request_find(trace, "state"))
+          lttvwindowtraces_background_request_queue(
+              main_window_get_widget(control_flow_data->tab), trace, "state");
+        lttvwindowtraces_background_notify_queue(control_flow_data,
+                                                 trace,
+                                                 ltt_time_infinite,
+                                                 NULL,
+                                                 background_ready_hook);
+        control_flow_data->background_info_waiting++;
+      } else { /* in progress */
+      
+        lttvwindowtraces_background_notify_current(control_flow_data,
+                                                   trace,
+                                                   ltt_time_infinite,
+                                                   NULL,
+                                                   background_ready_hook);
+        control_flow_data->background_info_waiting++;
+      }
+    } else {
+      /* Data ready. By its nature, this viewer doesn't need to have
+       * its data ready hook called there, because a background
+       * request is always linked with a redraw.
+       */
+    }
+    
+  }
+
+  lttv_hooks_destroy(background_ready_hook);
+}
+
+
+
+
+/**
+ * Event Viewer's constructor hook
+ *
+ * This constructor is given as a parameter to the menuitem and toolbar button
+ * registration. It creates the list.
+ * @param tab A pointer to the parent tab.
+ * @return The widget created.
+ */
+GtkWidget *
+h_guicontrolflow(LttvPlugin *plugin)
+{
+  LttvPluginTab *ptab = LTTV_PLUGIN_TAB(plugin);
+  Tab *tab = ptab->tab;
+  g_info("h_guicontrolflow, %p", tab);
+  ControlFlowData *control_flow_data = guicontrolflow(ptab);
+  
+  control_flow_data->tab = tab;
+  
+  // Unreg done in the GuiControlFlow_Destructor
+  lttvwindow_register_traceset_notify(tab,
+        traceset_notify,
+        control_flow_data);
+    
+  lttvwindow_register_time_window_notify(tab,
+                                         update_time_window_hook,
+                                         control_flow_data);
+  lttvwindow_register_current_time_notify(tab,
+                                          update_current_time_hook,
+                                          control_flow_data);
+  lttvwindow_register_redraw_notify(tab,
+                                    redraw_notify,
+                                    control_flow_data);
+  lttvwindow_register_continue_notify(tab,
+                                      continue_notify,
+                                      control_flow_data);
+  request_background_data(control_flow_data);
+  
+
+  return guicontrolflow_get_widget(control_flow_data) ;
+  
+}
+
+void legend_destructor(GtkWindow *legend)
+{
+  g_legend_list = g_slist_remove(g_legend_list, legend);
+}
+
+/* Create a popup legend */
+GtkWidget *
+h_legend(LttvPlugin *plugin)
+{
+  LttvPluginTab *ptab = LTTV_PLUGIN_TAB(plugin);
+  Tab *tab = ptab->tab;
+  g_info("h_legend, %p", tab);
+
+  GtkWindow *legend = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL));
+  g_legend_list = g_slist_append(
+      g_legend_list,
+      legend);
+  g_object_set_data_full(
+      G_OBJECT(legend),
+      "legend",
+      legend,
+      (GDestroyNotify)legend_destructor);
+  
+  gtk_window_set_title(legend, "Control Flow View Legend");
+
+  GtkWidget *pixmap = create_pixmap(GTK_WIDGET(legend), "lttv-color-list.png");
+  
+ // GtkImage *image = GTK_IMAGE(gtk_image_new_from_pixmap(
+ //                               GDK_PIXMAP(pixmap), NULL));
+  
+  gtk_container_add(GTK_CONTAINER(legend), GTK_WIDGET(pixmap));
+
+  gtk_widget_show(GTK_WIDGET(pixmap));
+  gtk_widget_show(GTK_WIDGET(legend));
+  
+
+  return NULL; /* This is a popup window */
+}
+
+
+int event_selected_hook(void *hook_data, void *call_data)
+{
+  ControlFlowData *control_flow_data = (ControlFlowData*) hook_data;
+  guint *event_number = (guint*) call_data;
+
+  g_debug("DEBUG : event selected by main window : %u", *event_number);
+  
+  return 0;
+}
+
+/* Function that selects the color of status&exemode line */
+static inline PropertiesLine prepare_s_e_line(LttvProcessState *process)
+{
+  PropertiesLine prop_line;
+  prop_line.line_width = STATE_LINE_WIDTH;
+  prop_line.style = GDK_LINE_SOLID;
+  prop_line.y = MIDDLE;
+  //GdkColormap *colormap = gdk_colormap_get_system();
+  
+  if(process->state->s == LTTV_STATE_RUN) {
+    if(process->state->t == LTTV_STATE_USER_MODE)
+      prop_line.color = drawing_colors[COL_RUN_USER_MODE];
+    else if(process->state->t == LTTV_STATE_SYSCALL)
+      prop_line.color = drawing_colors[COL_RUN_SYSCALL];
+    else if(process->state->t == LTTV_STATE_TRAP)
+      prop_line.color = drawing_colors[COL_RUN_TRAP];
+    else if(process->state->t == LTTV_STATE_IRQ)
+      prop_line.color = drawing_colors[COL_RUN_IRQ];
+    else if(process->state->t == LTTV_STATE_SOFT_IRQ)
+      prop_line.color = drawing_colors[COL_RUN_SOFT_IRQ];
+    else if(process->state->t == LTTV_STATE_MODE_UNKNOWN)
+      prop_line.color = drawing_colors[COL_MODE_UNKNOWN];
+    else
+      g_assert(FALSE);   /* RUNNING MODE UNKNOWN */
+  } else if(process->state->s == LTTV_STATE_WAIT) {
+    /* We don't show if we wait while in user mode, trap, irq or syscall */
+    prop_line.color = drawing_colors[COL_WAIT];
+  } else if(process->state->s == LTTV_STATE_WAIT_CPU) {
+    /* We don't show if we wait for CPU while in user mode, trap, irq
+     * or syscall */
+    prop_line.color = drawing_colors[COL_WAIT_CPU];
+  } else if(process->state->s == LTTV_STATE_ZOMBIE) {
+    prop_line.color = drawing_colors[COL_ZOMBIE];
+  } else if(process->state->s == LTTV_STATE_WAIT_FORK) {
+    prop_line.color = drawing_colors[COL_WAIT_FORK];
+  } else if(process->state->s == LTTV_STATE_EXIT) {
+    prop_line.color = drawing_colors[COL_EXIT];
+  } else if(process->state->s == LTTV_STATE_UNNAMED) {
+    prop_line.color = drawing_colors[COL_UNNAMED];
+  } else {
+               g_critical("unknown state : %s", g_quark_to_string(process->state->s));
+    g_assert(FALSE);   /* UNKNOWN STATE */
+       }
+  
+  return prop_line;
+
+}
+
+
+/* before_schedchange_hook
+ * 
+ * This function basically draw lines and icons. Two types of lines are drawn :
+ * one small (3 pixels?) representing the state of the process and the second
+ * type is thicker (10 pixels?) representing on which CPU a process is running
+ * (and this only in running state).
+ *
+ * Extremums of the lines :
+ * x_min : time of the last event context for this process kept in memory.
+ * x_max : time of the current event.
+ * y : middle of the process in the process list. The process is found in the
+ * list, therefore is it's position in pixels.
+ *
+ * The choice of lines'color is defined by the context of the last event for this
+ * process.
+ */
+
+
+int before_schedchange_hook(void *hook_data, void *call_data)
+{
+  LttvTraceHookByFacility *thf = (LttvTraceHookByFacility*)hook_data;
+  EventsRequest *events_request = (EventsRequest*)thf->hook_data;
+  ControlFlowData *control_flow_data = events_request->viewer_data;
+
+  LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
+
+  LttvTracefileState *tfs = (LttvTracefileState *)call_data;
+  LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
+
+  LttEvent *e;
+  e = ltt_tracefile_get_event(tfc->tf);
+  gint target_pid_saved = tfc->target_pid;
+
+  LttTime evtime = ltt_event_time(e);
+  LttvFilter *filter = control_flow_data->filter;
+
+  /* we are in a schedchange, before the state update. We must draw the
+   * items corresponding to the state before it changes : now is the right
+   * time to do it.
+   */
+
+  guint pid_out;
+  guint pid_in;
+  {
+    pid_out = ltt_event_get_long_unsigned(e, thf->f1);
+    pid_in = ltt_event_get_long_unsigned(e, thf->f2);
+  }
+  
+  tfc->target_pid = pid_out;
+  if(!filter || !filter->head ||
+    lttv_filter_tree_parse(filter->head,e,tfc->tf,
+          tfc->t_context->t,tfc,NULL,NULL)) { 
+    /* For the pid_out */
+    /* First, check if the current process is in the state computation
+     * process list. If it is there, that means we must add it right now and
+     * draw items from the beginning of the read for it. If it is not
+     * present, it's a new process and it was not present : it will
+     * be added after the state update.  */
+    guint cpu = tfs->cpu;
+    guint trace_num = ts->parent.index;
+    LttvProcessState *process = ts->running_process[cpu];
+    /* unknown state, bad current pid */
+    if(process->pid != pid_out)
+      process = lttv_state_find_process(ts,
+          tfs->cpu, pid_out);
+    
+    if(process != NULL) {
+      /* Well, the process_out existed : we must get it in the process hash
+       * or add it, and draw its items.
+       */
+       /* Add process to process list (if not present) */
+      guint pl_height = 0;
+      HashedProcessData *hashed_process_data = NULL;
+      ProcessList *process_list = control_flow_data->process_list;
+      LttTime birth = process->creation_time;
+      
+      hashed_process_data = processlist_get_process_data(process_list,
+              pid_out,
+              process->cpu,
+              &birth,
+              trace_num);
+      if(hashed_process_data == NULL)
+      {
+        g_assert(pid_out == 0 || pid_out != process->ppid);
+        /* Process not present */
+        ProcessInfo *process_info;
+        Drawing_t *drawing = control_flow_data->drawing;
+        processlist_add(process_list,
+            drawing,
+            pid_out,
+            process->tgid,
+            process->cpu,
+            process->ppid,
+            &birth,
+            trace_num,
+            process->name,
+            process->brand,
+            &pl_height,
+            &process_info,
+            &hashed_process_data);
+        gtk_widget_set_size_request(drawing->drawing_area,
+                                    -1,
+                                    pl_height);
+        gtk_widget_queue_draw(drawing->drawing_area);
+
+      }
+  
+      /* Now, the process is in the state hash and our own process hash.
+       * We definitely can draw the items related to the ending state.
+       */
+      
+      if(ltt_time_compare(hashed_process_data->next_good_time,
+                          evtime) > 0)
+      {
+        if(hashed_process_data->x.middle_marked == FALSE) {
+    
+          TimeWindow time_window = 
+            lttvwindow_get_time_window(control_flow_data->tab);
+#ifdef EXTRA_CHECK
+          if(ltt_time_compare(evtime, time_window.start_time) == -1
+                || ltt_time_compare(evtime, time_window.end_time) == 1)
+                    return;
+#endif //EXTRA_CHECK
+          Drawing_t *drawing = control_flow_data->drawing;
+          guint width = drawing->width;
+          guint x;
+          convert_time_to_pixels(
+                    time_window,
+                    evtime,
+                    width,
+                    &x);
+
+          /* Draw collision indicator */
+          gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
+          gdk_draw_point(hashed_process_data->pixmap,
+                         drawing->gc,
+                         x,
+                         COLLISION_POSITION(hashed_process_data->height));
+          hashed_process_data->x.middle_marked = TRUE;
+        }
+      } else {
+        TimeWindow time_window = 
+          lttvwindow_get_time_window(control_flow_data->tab);
+#ifdef EXTRA_CHECK
+        if(ltt_time_compare(evtime, time_window.start_time) == -1
+              || ltt_time_compare(evtime, time_window.end_time) == 1)
+                  return;
+#endif //EXTRA_CHECK
+        Drawing_t *drawing = control_flow_data->drawing;
+        guint width = drawing->width;
+        guint x;
+        convert_time_to_pixels(
+                  time_window,
+                  evtime,
+                  width,
+                  &x);
+
+
+        /* Jump over draw if we are at the same x position */
+        if(x == hashed_process_data->x.middle &&
+             hashed_process_data->x.middle_used)
+        {
+          if(hashed_process_data->x.middle_marked == FALSE) {
+            /* Draw collision indicator */
+            gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
+            gdk_draw_point(hashed_process_data->pixmap,
+                           drawing->gc,
+                           x,
+                           COLLISION_POSITION(hashed_process_data->height));
+            hashed_process_data->x.middle_marked = TRUE;
+          }
+          /* jump */
+        } else {
+          DrawContext draw_context;
+
+          /* Now create the drawing context that will be used to draw
+           * items related to the last state. */
+          draw_context.drawable = hashed_process_data->pixmap;
+          draw_context.gc = drawing->gc;
+          draw_context.pango_layout = drawing->pango_layout;
+          draw_context.drawinfo.start.x = hashed_process_data->x.middle;
+          draw_context.drawinfo.end.x = x;
+
+          draw_context.drawinfo.y.over = 1;
+          draw_context.drawinfo.y.middle = (hashed_process_data->height/2);
+          draw_context.drawinfo.y.under = hashed_process_data->height;
+
+          draw_context.drawinfo.start.offset.over = 0;
+          draw_context.drawinfo.start.offset.middle = 0;
+          draw_context.drawinfo.start.offset.under = 0;
+          draw_context.drawinfo.end.offset.over = 0;
+          draw_context.drawinfo.end.offset.middle = 0;
+          draw_context.drawinfo.end.offset.under = 0;
+
+          {
+            /* Draw the line */
+            PropertiesLine prop_line = prepare_s_e_line(process);
+            draw_line((void*)&prop_line, (void*)&draw_context);
+
+          }
+          /* become the last x position */
+          hashed_process_data->x.middle = x;
+          hashed_process_data->x.middle_used = TRUE;
+          hashed_process_data->x.middle_marked = FALSE;
+
+          /* Calculate the next good time */
+          convert_pixels_to_time(width, x+1, time_window,
+                                 &hashed_process_data->next_good_time);
+        }
+      }
+    }
+  }
+
+  tfc->target_pid = pid_in;
+  if(!filter || !filter->head ||
+    lttv_filter_tree_parse(filter->head,e,tfc->tf,
+          tfc->t_context->t,tfc,NULL,NULL)) { 
+    /* For the pid_in */
+    /* First, check if the current process is in the state computation
+     * process list. If it is there, that means we must add it right now and
+     * draw items from the beginning of the read for it. If it is not
+     * present, it's a new process and it was not present : it will
+     * be added after the state update.  */
+    LttvProcessState *process;
+    process = lttv_state_find_process(ts,
+        tfs->cpu, pid_in);
+    guint trace_num = ts->parent.index;
+    
+    if(process != NULL) {
+      /* Well, the process existed : we must get it in the process hash
+       * or add it, and draw its items.
+       */
+       /* Add process to process list (if not present) */
+      guint pl_height = 0;
+      HashedProcessData *hashed_process_data = NULL;
+      ProcessList *process_list = control_flow_data->process_list;
+      LttTime birth = process->creation_time;
+      
+      hashed_process_data = processlist_get_process_data(process_list,
+              pid_in,
+              tfs->cpu,
+              &birth,
+              trace_num);
+      if(hashed_process_data == NULL)
+      {
+        g_assert(pid_in == 0 || pid_in != process->ppid);
+        /* Process not present */
+        ProcessInfo *process_info;
+        Drawing_t *drawing = control_flow_data->drawing;
+        processlist_add(process_list,
+            drawing,
+            pid_in,
+            process->tgid,
+            tfs->cpu,
+            process->ppid,
+            &birth,
+            trace_num,
+            process->name,
+            process->brand,
+            &pl_height,
+            &process_info,
+            &hashed_process_data);
+        gtk_widget_set_size_request(drawing->drawing_area,
+                                    -1,
+                                    pl_height);
+        gtk_widget_queue_draw(drawing->drawing_area);
+
+      }
+      //We could set the current process and hash here, but will be done
+      //by after schedchange hook
+    
+      /* Now, the process is in the state hash and our own process hash.
+       * We definitely can draw the items related to the ending state.
+       */
+      
+      if(ltt_time_compare(hashed_process_data->next_good_time,
+                          evtime) > 0)
+      {
+        if(hashed_process_data->x.middle_marked == FALSE) {
+
+          TimeWindow time_window = 
+            lttvwindow_get_time_window(control_flow_data->tab);
+#ifdef EXTRA_CHECK
+          if(ltt_time_compare(evtime, time_window.start_time) == -1
+                || ltt_time_compare(evtime, time_window.end_time) == 1)
+                    return;
+#endif //EXTRA_CHECK
+          Drawing_t *drawing = control_flow_data->drawing;
+          guint width = drawing->width;
+          guint x;
+          convert_time_to_pixels(
+                    time_window,
+                    evtime,
+                    width,
+                    &x);
+
+          /* Draw collision indicator */
+          gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
+          gdk_draw_point(hashed_process_data->pixmap,
+                         drawing->gc,
+                         x,
+                         COLLISION_POSITION(hashed_process_data->height));
+          hashed_process_data->x.middle_marked = TRUE;
+        }
+      } else {
+        TimeWindow time_window = 
+          lttvwindow_get_time_window(control_flow_data->tab);
+#ifdef EXTRA_CHECK
+        if(ltt_time_compare(evtime, time_window.start_time) == -1
+              || ltt_time_compare(evtime, time_window.end_time) == 1)
+                  return;
+#endif //EXTRA_CHECK
+        Drawing_t *drawing = control_flow_data->drawing;
+        guint width = drawing->width;
+        guint x;
+
+        convert_time_to_pixels(
+                  time_window,
+                  evtime,
+                  width,
+                  &x);
+
+
+        /* Jump over draw if we are at the same x position */
+        if(x == hashed_process_data->x.middle &&
+            hashed_process_data->x.middle_used)
+        {
+          if(hashed_process_data->x.middle_marked == FALSE) {
+            /* Draw collision indicator */
+            gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
+            gdk_draw_point(hashed_process_data->pixmap,
+                           drawing->gc,
+                           x,
+                           COLLISION_POSITION(hashed_process_data->height));
+            hashed_process_data->x.middle_marked = TRUE;
+          }
+          /* jump */
+        } else {
+          DrawContext draw_context;
+
+          /* Now create the drawing context that will be used to draw
+           * items related to the last state. */
+          draw_context.drawable = hashed_process_data->pixmap;
+          draw_context.gc = drawing->gc;
+          draw_context.pango_layout = drawing->pango_layout;
+          draw_context.drawinfo.start.x = hashed_process_data->x.middle;
+          draw_context.drawinfo.end.x = x;
+
+          draw_context.drawinfo.y.over = 1;
+          draw_context.drawinfo.y.middle = (hashed_process_data->height/2);
+          draw_context.drawinfo.y.under = hashed_process_data->height;
+
+          draw_context.drawinfo.start.offset.over = 0;
+          draw_context.drawinfo.start.offset.middle = 0;
+          draw_context.drawinfo.start.offset.under = 0;
+          draw_context.drawinfo.end.offset.over = 0;
+          draw_context.drawinfo.end.offset.middle = 0;
+          draw_context.drawinfo.end.offset.under = 0;
+
+          {
+            /* Draw the line */
+            PropertiesLine prop_line = prepare_s_e_line(process);
+            draw_line((void*)&prop_line, (void*)&draw_context);
+          }
+
+          
+          /* become the last x position */
+          hashed_process_data->x.middle = x;
+          hashed_process_data->x.middle_used = TRUE;
+          hashed_process_data->x.middle_marked = FALSE;
+
+          /* Calculate the next good time */
+          convert_pixels_to_time(width, x+1, time_window,
+                                 &hashed_process_data->next_good_time);
+        }
+      }
+    } else
+      g_warning("Cannot find pin_in in schedchange %u", pid_in);
+  }
+  tfc->target_pid = target_pid_saved;
+  return 0;
+
+
+
+
+  /* Text dump */
+#ifdef DONTSHOW
+  GString *string = g_string_new("");;
+  gboolean field_names = TRUE, state = TRUE;
+
+  lttv_event_to_string(e, tfc->tf, string, TRUE, field_names, tfs);
+  g_string_append_printf(string,"\n");  
+
+  if(state) {
+    g_string_append_printf(string, " %s",
+        g_quark_to_string(tfs->process->state->s));
+  }
+
+  g_info("%s",string->str);
+
+  g_string_free(string, TRUE);
+  
+  /* End of text dump */
+#endif //DONTSHOW
+
+}
+
+/* after_schedchange_hook
+ * 
+ * The draw after hook is called by the reading API to have a
+ * particular event drawn on the screen.
+ * @param hook_data ControlFlowData structure of the viewer. 
+ * @param call_data Event context.
+ *
+ * This function adds items to be drawn in a queue for each process.
+ * 
+ */
+int after_schedchange_hook(void *hook_data, void *call_data)
+{
+  LttvTraceHookByFacility *thf = (LttvTraceHookByFacility*)hook_data;
+  EventsRequest *events_request = (EventsRequest*)thf->hook_data;
+  ControlFlowData *control_flow_data = events_request->viewer_data;
+
+  LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
+
+  LttvTracefileState *tfs = (LttvTracefileState *)call_data;
+
+  LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
+
+  LttEvent *e;
+  e = ltt_tracefile_get_event(tfc->tf);
+
+  LttvFilter *filter = control_flow_data->filter;
+  if(filter != NULL && filter->head != NULL)
+    if(!lttv_filter_tree_parse(filter->head,e,tfc->tf,
+          tfc->t_context->t,tfc,NULL,NULL))
+      return FALSE;
+
+  LttTime evtime = ltt_event_time(e);
+
+  /* Add process to process list (if not present) */
+  LttvProcessState *process_in;
+  LttTime birth;
+  guint pl_height = 0;
+  HashedProcessData *hashed_process_data_in = NULL;
+
+  ProcessList *process_list = control_flow_data->process_list;
+  
+  guint pid_in;
+  {
+    guint pid_out;
+    pid_out = ltt_event_get_long_unsigned(e, thf->f1);
+    pid_in = ltt_event_get_long_unsigned(e, thf->f2);
+  }
+
+
+  /* Find process pid_in in the list... */
+  //process_in = lttv_state_find_process(ts, ANY_CPU, pid_in);
+  //process_in = tfs->process;
+  guint cpu = tfs->cpu;
+  guint trace_num = ts->parent.index;
+  process_in = ts->running_process[cpu];
+  /* It should exist, because we are after the state update. */
+#ifdef EXTRA_CHECK
+  g_assert(process_in != NULL);
+#endif //EXTRA_CHECK
+  birth = process_in->creation_time;
+
+  hashed_process_data_in = processlist_get_process_data(process_list,
+          pid_in,
+          process_in->cpu,
+          &birth,
+          trace_num);
+  if(hashed_process_data_in == NULL)
+  {
+    g_assert(pid_in == 0 || pid_in != process_in->ppid);
+    ProcessInfo *process_info;
+    Drawing_t *drawing = control_flow_data->drawing;
+    /* Process not present */
+    processlist_add(process_list,
+        drawing,
+        pid_in,
+        process_in->tgid,
+        process_in->cpu,
+        process_in->ppid,
+        &birth,
+        trace_num,
+        process_in->name,
+        process_in->brand,
+        &pl_height,
+        &process_info,
+        &hashed_process_data_in);
+        gtk_widget_set_size_request(drawing->drawing_area,
+                                    -1,
+                                    pl_height);
+        gtk_widget_queue_draw(drawing->drawing_area);
+  }
+  /* Set the current process */
+  process_list->current_hash_data[trace_num][process_in->cpu] =
+                                             hashed_process_data_in;
+
+  if(ltt_time_compare(hashed_process_data_in->next_good_time,
+                          evtime) <= 0)
+  {
+    TimeWindow time_window = 
+    lttvwindow_get_time_window(control_flow_data->tab);
+
+#ifdef EXTRA_CHECK
+    if(ltt_time_compare(evtime, time_window.start_time) == -1
+        || ltt_time_compare(evtime, time_window.end_time) == 1)
+            return;
+#endif //EXTRA_CHECK
+    Drawing_t *drawing = control_flow_data->drawing;
+    guint width = drawing->width;
+    guint new_x;
+    
+    convert_time_to_pixels(
+        time_window,
+        evtime,
+        width,
+        &new_x);
+
+    if(hashed_process_data_in->x.middle != new_x) {
+      hashed_process_data_in->x.middle = new_x;
+      hashed_process_data_in->x.middle_used = FALSE;
+      hashed_process_data_in->x.middle_marked = FALSE;
+    }
+  }
+  return 0;
+}
+
+
+
+
+/* before_execmode_hook
+ * 
+ * This function basically draw lines and icons. Two types of lines are drawn :
+ * one small (3 pixels?) representing the state of the process and the second
+ * type is thicker (10 pixels?) representing on which CPU a process is running
+ * (and this only in running state).
+ *
+ * Extremums of the lines :
+ * x_min : time of the last event context for this process kept in memory.
+ * x_max : time of the current event.
+ * y : middle of the process in the process list. The process is found in the
+ * list, therefore is it's position in pixels.
+ *
+ * The choice of lines'color is defined by the context of the last event for this
+ * process.
+ */
+
+
+int before_execmode_hook(void *hook_data, void *call_data)
+{
+  LttvTraceHookByFacility *thf = (LttvTraceHookByFacility*)hook_data;
+  EventsRequest *events_request = (EventsRequest*)thf->hook_data;
+  ControlFlowData *control_flow_data = events_request->viewer_data;
+
+  LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
+
+  LttvTracefileState *tfs = (LttvTracefileState *)call_data;
+
+  LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
+
+  LttEvent *e;
+  e = ltt_tracefile_get_event(tfc->tf);
+
+  LttvFilter *filter = control_flow_data->filter;
+  if(filter != NULL && filter->head != NULL)
+    if(!lttv_filter_tree_parse(filter->head,e,tfc->tf,
+          tfc->t_context->t,tfc,NULL,NULL))
+      return FALSE;
+
+  LttTime evtime = ltt_event_time(e);
+
+  /* we are in a execmode, before the state update. We must draw the
+   * items corresponding to the state before it changes : now is the right
+   * time to do it.
+   */
+  /* For the pid */
+  //LttvProcessState *process = tfs->process;
+  guint cpu = tfs->cpu;
+  guint trace_num = ts->parent.index;
+  LttvProcessState *process = ts->running_process[cpu];
+  g_assert(process != NULL);
+
+  guint pid = process->pid;
+
+  /* Well, the process_out existed : we must get it in the process hash
+   * or add it, and draw its items.
+   */
+   /* Add process to process list (if not present) */
+  guint pl_height = 0;
+  HashedProcessData *hashed_process_data = NULL;
+  ProcessList *process_list = control_flow_data->process_list;
+  LttTime birth = process->creation_time;
+  if(likely(process_list->current_hash_data[trace_num][cpu] != NULL)) {
+    hashed_process_data = process_list->current_hash_data[trace_num][cpu];
+  } else {
+    hashed_process_data = processlist_get_process_data(process_list,
+            pid,
+            process->cpu,
+            &birth,
+            trace_num);
+    if(unlikely(hashed_process_data == NULL))
+    {
+      g_assert(pid == 0 || pid != process->ppid);
+      ProcessInfo *process_info;
+      /* Process not present */
+      Drawing_t *drawing = control_flow_data->drawing;
+      processlist_add(process_list,
+          drawing,
+          pid,
+          process->tgid,
+          process->cpu,
+          process->ppid,
+          &birth,
+          trace_num,
+          process->name,
+          process->brand,
+          &pl_height,
+          &process_info,
+          &hashed_process_data);
+        gtk_widget_set_size_request(drawing->drawing_area,
+                                    -1,
+                                    pl_height);
+        gtk_widget_queue_draw(drawing->drawing_area);
+    }
+    /* Set the current process */
+    process_list->current_hash_data[trace_num][process->cpu] =
+                                               hashed_process_data;
+  }
+
+  /* Now, the process is in the state hash and our own process hash.
+   * We definitely can draw the items related to the ending state.
+   */
+
+  if(likely(ltt_time_compare(hashed_process_data->next_good_time,
+                      evtime) > 0))
+  {
+    if(unlikely(hashed_process_data->x.middle_marked == FALSE)) {
+      TimeWindow time_window = 
+        lttvwindow_get_time_window(control_flow_data->tab);
+
+#ifdef EXTRA_CHECK
+      if(ltt_time_compare(evtime, time_window.start_time) == -1
+            || ltt_time_compare(evtime, time_window.end_time) == 1)
+                return;
+#endif //EXTRA_CHECK
+      Drawing_t *drawing = control_flow_data->drawing;
+      guint width = drawing->width;
+      guint x;
+      convert_time_to_pixels(
+                time_window,
+                evtime,
+                width,
+                &x);
+
+      /* Draw collision indicator */
+      gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
+      gdk_draw_point(hashed_process_data->pixmap,
+                     drawing->gc,
+                     x,
+                     COLLISION_POSITION(hashed_process_data->height));
+      hashed_process_data->x.middle_marked = TRUE;
+    }
+  } else {
+    TimeWindow time_window = 
+      lttvwindow_get_time_window(control_flow_data->tab);
+
+#ifdef EXTRA_CHECK
+    if(ltt_time_compare(evtime, time_window.start_time) == -1
+          || ltt_time_compare(evtime, time_window.end_time) == 1)
+              return;
+#endif //EXTRA_CHECK
+    Drawing_t *drawing = control_flow_data->drawing;
+    guint width = drawing->width;
+    guint x;
+
+    convert_time_to_pixels(
+        time_window,
+        evtime,
+        width,
+        &x);
+
+
+    /* Jump over draw if we are at the same x position */
+    if(unlikely(x == hashed_process_data->x.middle &&
+             hashed_process_data->x.middle_used))
+    {
+      if(unlikely(hashed_process_data->x.middle_marked == FALSE)) {
+        /* Draw collision indicator */
+        gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
+        gdk_draw_point(hashed_process_data->pixmap,
+                       drawing->gc,
+                       x,
+                       COLLISION_POSITION(hashed_process_data->height));
+        hashed_process_data->x.middle_marked = TRUE;
+      }
+      /* jump */
+    } else {
+
+      DrawContext draw_context;
+      /* Now create the drawing context that will be used to draw
+       * items related to the last state. */
+      draw_context.drawable = hashed_process_data->pixmap;
+      draw_context.gc = drawing->gc;
+      draw_context.pango_layout = drawing->pango_layout;
+      draw_context.drawinfo.start.x = hashed_process_data->x.middle;
+      draw_context.drawinfo.end.x = x;
+
+      draw_context.drawinfo.y.over = 1;
+      draw_context.drawinfo.y.middle = (hashed_process_data->height/2);
+      draw_context.drawinfo.y.under = hashed_process_data->height;
+
+      draw_context.drawinfo.start.offset.over = 0;
+      draw_context.drawinfo.start.offset.middle = 0;
+      draw_context.drawinfo.start.offset.under = 0;
+      draw_context.drawinfo.end.offset.over = 0;
+      draw_context.drawinfo.end.offset.middle = 0;
+      draw_context.drawinfo.end.offset.under = 0;
+
+      {
+        /* Draw the line */
+        PropertiesLine prop_line = prepare_s_e_line(process);
+        draw_line((void*)&prop_line, (void*)&draw_context);
+
+      }
+      /* become the last x position */
+      hashed_process_data->x.middle = x;
+      hashed_process_data->x.middle_used = TRUE;
+      hashed_process_data->x.middle_marked = FALSE;
+
+      /* Calculate the next good time */
+      convert_pixels_to_time(width, x+1, time_window,
+                             &hashed_process_data->next_good_time);
+    }
+  }
+  
+  return 0;
+}
+
+/* before_process_exit_hook
+ * 
+ * Draw lines for process event.
+ *
+ * @param hook_data ControlFlowData structure of the viewer. 
+ * @param call_data Event context.
+ *
+ * This function adds items to be drawn in a queue for each process.
+ * 
+ */
+
+
+int before_process_exit_hook(void *hook_data, void *call_data)
+{
+  LttvTraceHookByFacility *thf = (LttvTraceHookByFacility*)hook_data;
+  EventsRequest *events_request = (EventsRequest*)thf->hook_data;
+
+  ControlFlowData *control_flow_data = events_request->viewer_data;
+
+  LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
+
+  LttvTracefileState *tfs = (LttvTracefileState *)call_data;
+
+  LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
+
+  LttEvent *e;
+  e = ltt_tracefile_get_event(tfc->tf);
+
+  LttvFilter *filter = control_flow_data->filter;
+  if(filter != NULL && filter->head != NULL)
+    if(!lttv_filter_tree_parse(filter->head,e,tfc->tf,
+          tfc->t_context->t,tfc,NULL,NULL))
+      return FALSE;
+
+  LttTime evtime = ltt_event_time(e);
+
+  /* Add process to process list (if not present) */
+  //LttvProcessState *process = tfs->process;
+  guint cpu = tfs->cpu;
+  guint trace_num = ts->parent.index;
+  LttvProcessState *process = ts->running_process[cpu];
+  guint pid = process->pid;
+  LttTime birth;
+  guint pl_height = 0;
+  HashedProcessData *hashed_process_data = NULL;
+
+  ProcessList *process_list = control_flow_data->process_list;
+  
+  g_assert(process != NULL);
+
+  birth = process->creation_time;
+
+  if(likely(process_list->current_hash_data[trace_num][cpu] != NULL)) {
+    hashed_process_data = process_list->current_hash_data[trace_num][cpu];
+  } else {
+    hashed_process_data = processlist_get_process_data(process_list,
+          pid,
+          process->cpu,
+          &birth,
+          trace_num);
+    if(unlikely(hashed_process_data == NULL))
+    {
+      g_assert(pid == 0 || pid != process->ppid);
+      /* Process not present */
+      Drawing_t *drawing = control_flow_data->drawing;
+      ProcessInfo *process_info;
+      processlist_add(process_list,
+          drawing,
+          pid,
+          process->tgid,
+          process->cpu,
+          process->ppid,
+          &birth,
+          trace_num,
+          process->name,
+          process->brand,
+          &pl_height,
+          &process_info,
+          &hashed_process_data);
+      gtk_widget_set_size_request(drawing->drawing_area,
+                                  -1,
+                                  pl_height);
+      gtk_widget_queue_draw(drawing->drawing_area);
+    }
+  }
+
+  /* Now, the process is in the state hash and our own process hash.
+   * We definitely can draw the items related to the ending state.
+   */
+  
+  if(likely(ltt_time_compare(hashed_process_data->next_good_time,
+                      evtime) > 0))
+  {
+    if(unlikely(hashed_process_data->x.middle_marked == FALSE)) {
+      TimeWindow time_window = 
+        lttvwindow_get_time_window(control_flow_data->tab);
+
+#ifdef EXTRA_CHECK
+      if(ltt_time_compare(evtime, time_window.start_time) == -1
+            || ltt_time_compare(evtime, time_window.end_time) == 1)
+                return;
+#endif //EXTRA_CHECK
+      Drawing_t *drawing = control_flow_data->drawing;
+      guint width = drawing->width;
+      guint x;
+      convert_time_to_pixels(
+                time_window,
+                evtime,
+                width,
+                &x);
+
+      /* Draw collision indicator */
+      gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
+      gdk_draw_point(hashed_process_data->pixmap,
+                     drawing->gc,
+                     x,
+                     COLLISION_POSITION(hashed_process_data->height));
+      hashed_process_data->x.middle_marked = TRUE;
+    }
+  } else {
+    TimeWindow time_window = 
+      lttvwindow_get_time_window(control_flow_data->tab);
+
+#ifdef EXTRA_CHECK
+    if(ltt_time_compare(evtime, time_window.start_time) == -1
+          || ltt_time_compare(evtime, time_window.end_time) == 1)
+              return;
+#endif //EXTRA_CHECK
+    Drawing_t *drawing = control_flow_data->drawing;
+    guint width = drawing->width;
+    guint x;
+
+    convert_time_to_pixels(
+        time_window,
+        evtime,
+        width,
+        &x);
+
+
+    /* Jump over draw if we are at the same x position */
+    if(unlikely(x == hashed_process_data->x.middle &&
+           hashed_process_data->x.middle_used))
+    { 
+      if(unlikely(hashed_process_data->x.middle_marked == FALSE)) {
+        /* Draw collision indicator */
+        gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
+        gdk_draw_point(hashed_process_data->pixmap,
+                       drawing->gc,
+                       x,
+                       COLLISION_POSITION(hashed_process_data->height));
+        hashed_process_data->x.middle_marked = TRUE;
+      }
+      /* jump */
+    } else {
+      DrawContext draw_context;
+
+      /* Now create the drawing context that will be used to draw
+       * items related to the last state. */
+      draw_context.drawable = hashed_process_data->pixmap;
+      draw_context.gc = drawing->gc;
+      draw_context.pango_layout = drawing->pango_layout;
+      draw_context.drawinfo.start.x = hashed_process_data->x.middle;
+      draw_context.drawinfo.end.x = x;
+
+      draw_context.drawinfo.y.over = 1;
+      draw_context.drawinfo.y.middle = (hashed_process_data->height/2);
+      draw_context.drawinfo.y.under = hashed_process_data->height;
+
+      draw_context.drawinfo.start.offset.over = 0;
+      draw_context.drawinfo.start.offset.middle = 0;
+      draw_context.drawinfo.start.offset.under = 0;
+      draw_context.drawinfo.end.offset.over = 0;
+      draw_context.drawinfo.end.offset.middle = 0;
+      draw_context.drawinfo.end.offset.under = 0;
+
+      {
+        /* Draw the line */
+        PropertiesLine prop_line = prepare_s_e_line(process);
+        draw_line((void*)&prop_line, (void*)&draw_context);
+
+      }
+      /* become the last x position */
+      hashed_process_data->x.middle = x;
+      hashed_process_data->x.middle_used = TRUE;
+      hashed_process_data->x.middle_marked = FALSE;
+
+      /* Calculate the next good time */
+      convert_pixels_to_time(width, x+1, time_window,
+                             &hashed_process_data->next_good_time);
+    }
+  }
+  
+  return 0;
+
+}
+
+
+
+/* before_process_release_hook
+ * 
+ * Draw lines for process event.
+ *
+ * @param hook_data ControlFlowData structure of the viewer. 
+ * @param call_data Event context.
+ *
+ * This function adds items to be drawn in a queue for each process.
+ * 
+ */
+
+
+int before_process_release_hook(void *hook_data, void *call_data)
+{
+  LttvTraceHookByFacility *thf = (LttvTraceHookByFacility*)hook_data;
+  EventsRequest *events_request = (EventsRequest*)thf->hook_data;
+
+  ControlFlowData *control_flow_data = events_request->viewer_data;
+
+  LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
+
+  LttvTracefileState *tfs = (LttvTracefileState *)call_data;
+
+  LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
+
+  LttEvent *e;
+  e = ltt_tracefile_get_event(tfc->tf);
+
+  LttvFilter *filter = control_flow_data->filter;
+  if(filter != NULL && filter->head != NULL)
+    if(!lttv_filter_tree_parse(filter->head,e,tfc->tf,
+          tfc->t_context->t,tfc,NULL,NULL))
+      return FALSE;
+
+  LttTime evtime = ltt_event_time(e);
+
+  guint trace_num = ts->parent.index;
+
+  guint pid;
+  {
+    pid = ltt_event_get_long_unsigned(e, thf->f1);
+  }
+
+  /* Add process to process list (if not present) */
+  /* Don't care about the process if it's not in the state hash already :
+   * that means a process that has never done anything in the trace and
+   * unknown suddently gets destroyed : no state meaningful to show. */
+  LttvProcessState *process = lttv_state_find_process(ts, ANY_CPU, pid);
+
+  if(process != NULL) {
+    LttTime birth;
+    guint pl_height = 0;
+    HashedProcessData *hashed_process_data = NULL;
+
+    ProcessList *process_list = control_flow_data->process_list;
+    
+    birth = process->creation_time;
+
+    /* Cannot use current process : this event happens on another process,
+     * action done by the parent. */
+    hashed_process_data = processlist_get_process_data(process_list,
+          pid,
+          process->cpu,
+          &birth,
+          trace_num);
+    if(unlikely(hashed_process_data == NULL))
+    {
+      g_assert(pid == 0 || pid != process->ppid);
+      /* Process not present */
+      Drawing_t *drawing = control_flow_data->drawing;
+      ProcessInfo *process_info;
+      processlist_add(process_list,
+          drawing,
+          pid,
+          process->tgid,
+          process->cpu,
+          process->ppid,
+          &birth,
+          trace_num,
+          process->name,
+          process->brand,
+          &pl_height,
+          &process_info,
+          &hashed_process_data);
+      gtk_widget_set_size_request(drawing->drawing_area,
+                                  -1,
+                                  pl_height);
+      gtk_widget_queue_draw(drawing->drawing_area);
+    }
+
+    /* Now, the process is in the state hash and our own process hash.
+     * We definitely can draw the items related to the ending state.
+     */
+    
+    if(likely(ltt_time_compare(hashed_process_data->next_good_time,
+                        evtime) > 0))
+    {
+      if(unlikely(hashed_process_data->x.middle_marked == FALSE)) {
+        TimeWindow time_window = 
+          lttvwindow_get_time_window(control_flow_data->tab);
+
+#ifdef EXTRA_CHECK
+        if(ltt_time_compare(evtime, time_window.start_time) == -1
+              || ltt_time_compare(evtime, time_window.end_time) == 1)
+                  return;
+#endif //EXTRA_CHECK
+        Drawing_t *drawing = control_flow_data->drawing;
+        guint width = drawing->width;
+        guint x;
+        convert_time_to_pixels(
+                  time_window,
+                  evtime,
+                  width,
+                  &x);
+
+        /* Draw collision indicator */
+        gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
+        gdk_draw_point(hashed_process_data->pixmap,
+                       drawing->gc,
+                       x,
+                       COLLISION_POSITION(hashed_process_data->height));
+        hashed_process_data->x.middle_marked = TRUE;
+      }
+    } else {
+      TimeWindow time_window = 
+        lttvwindow_get_time_window(control_flow_data->tab);
+
+#ifdef EXTRA_CHECK
+      if(ltt_time_compare(evtime, time_window.start_time) == -1
+            || ltt_time_compare(evtime, time_window.end_time) == 1)
+                return;
+#endif //EXTRA_CHECK
+      Drawing_t *drawing = control_flow_data->drawing;
+      guint width = drawing->width;
+      guint x;
+
+      convert_time_to_pixels(
+          time_window,
+          evtime,
+          width,
+          &x);
+
+
+      /* Jump over draw if we are at the same x position */
+      if(unlikely(x == hashed_process_data->x.middle &&
+             hashed_process_data->x.middle_used))
+      { 
+        if(unlikely(hashed_process_data->x.middle_marked == FALSE)) {
+          /* Draw collision indicator */
+          gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
+          gdk_draw_point(hashed_process_data->pixmap,
+                         drawing->gc,
+                         x,
+                         COLLISION_POSITION(hashed_process_data->height));
+          hashed_process_data->x.middle_marked = TRUE;
+        }
+        /* jump */
+      } else {
+        DrawContext draw_context;
+
+        /* Now create the drawing context that will be used to draw
+         * items related to the last state. */
+        draw_context.drawable = hashed_process_data->pixmap;
+        draw_context.gc = drawing->gc;
+        draw_context.pango_layout = drawing->pango_layout;
+        draw_context.drawinfo.start.x = hashed_process_data->x.middle;
+        draw_context.drawinfo.end.x = x;
+
+        draw_context.drawinfo.y.over = 1;
+        draw_context.drawinfo.y.middle = (hashed_process_data->height/2);
+        draw_context.drawinfo.y.under = hashed_process_data->height;
+
+        draw_context.drawinfo.start.offset.over = 0;
+        draw_context.drawinfo.start.offset.middle = 0;
+        draw_context.drawinfo.start.offset.under = 0;
+        draw_context.drawinfo.end.offset.over = 0;
+        draw_context.drawinfo.end.offset.middle = 0;
+        draw_context.drawinfo.end.offset.under = 0;
+
+        {
+          /* Draw the line */
+          PropertiesLine prop_line = prepare_s_e_line(process);
+          draw_line((void*)&prop_line, (void*)&draw_context);
+
+        }
+        /* become the last x position */
+        hashed_process_data->x.middle = x;
+        hashed_process_data->x.middle_used = TRUE;
+        hashed_process_data->x.middle_marked = FALSE;
+
+        /* Calculate the next good time */
+        convert_pixels_to_time(width, x+1, time_window,
+                               &hashed_process_data->next_good_time);
+      }
+    }
+  }
+
+  return 0;
+}
+
+
+
+
+
+/* after_process_fork_hook
+ * 
+ * Create the processlist entry for the child process. Put the last
+ * position in x at the current time value.
+ *
+ * @param hook_data ControlFlowData structure of the viewer. 
+ * @param call_data Event context.
+ *
+ * This function adds items to be drawn in a queue for each process.
+ * 
+ */
+int after_process_fork_hook(void *hook_data, void *call_data)
+{
+  LttvTraceHookByFacility *thf = (LttvTraceHookByFacility*)hook_data;
+  EventsRequest *events_request = (EventsRequest*)thf->hook_data;
+  ControlFlowData *control_flow_data = events_request->viewer_data;
+
+  LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
+
+  LttvTracefileState *tfs = (LttvTracefileState *)call_data;
+
+  LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
+
+  LttEvent *e;
+  e = ltt_tracefile_get_event(tfc->tf);
+
+  LttvFilter *filter = control_flow_data->filter;
+  if(filter != NULL && filter->head != NULL)
+    if(!lttv_filter_tree_parse(filter->head,e,tfc->tf,
+          tfc->t_context->t,tfc,NULL,NULL))
+      return FALSE;
+
+  LttTime evtime = ltt_event_time(e);
+
+  guint child_pid;
+  {
+    child_pid = ltt_event_get_long_unsigned(e, thf->f2);
+  }
+
+  /* Add process to process list (if not present) */
+  LttvProcessState *process_child;
+  LttTime birth;
+  guint pl_height = 0;
+  HashedProcessData *hashed_process_data_child = NULL;
+
+  ProcessList *process_list = control_flow_data->process_list;
+
+  /* Find child in the list... */
+  process_child = lttv_state_find_process(ts, ANY_CPU, child_pid);
+  /* It should exist, because we are after the state update. */
+  g_assert(process_child != NULL);
+
+  birth = process_child->creation_time;
+  guint trace_num = ts->parent.index;
+
+  /* Cannot use current process, because this action is done by the parent
+   * on its child. */
+  hashed_process_data_child = processlist_get_process_data(process_list,
+          child_pid,
+          process_child->cpu,
+          &birth,
+          trace_num);
+  if(likely(hashed_process_data_child == NULL))
+  {
+    g_assert(child_pid == 0 || child_pid != process_child->ppid);
+    /* Process not present */
+    Drawing_t *drawing = control_flow_data->drawing;
+    ProcessInfo *process_info;
+    processlist_add(process_list,
+        drawing,
+        child_pid,
+        process_child->tgid,
+        process_child->cpu,
+        process_child->ppid,
+        &birth,
+        trace_num,
+        process_child->name,
+        process_child->brand,
+        &pl_height,
+        &process_info,
+        &hashed_process_data_child);
+      gtk_widget_set_size_request(drawing->drawing_area,
+                                  -1,
+                                  pl_height);
+      gtk_widget_queue_draw(drawing->drawing_area);
+  } else {
+          processlist_set_ppid(process_list, process_child->ppid,
+                               hashed_process_data_child);
+          processlist_set_tgid(process_list, process_child->tgid,
+                               hashed_process_data_child);
+  }
+
+
+  if(likely(ltt_time_compare(hashed_process_data_child->next_good_time,
+                        evtime) <= 0))
+  {
+    TimeWindow time_window = 
+      lttvwindow_get_time_window(control_flow_data->tab);
+
+#ifdef EXTRA_CHECK
+    if(ltt_time_compare(evtime, time_window.start_time) == -1
+          || ltt_time_compare(evtime, time_window.end_time) == 1)
+              return;
+#endif //EXTRA_CHECK
+    Drawing_t *drawing = control_flow_data->drawing;
+    guint width = drawing->width;
+    guint new_x;
+    convert_time_to_pixels(
+        time_window,
+        evtime,
+        width,
+        &new_x);
+
+    if(likely(hashed_process_data_child->x.over != new_x)) {
+      hashed_process_data_child->x.over = new_x;
+      hashed_process_data_child->x.over_used = FALSE;
+      hashed_process_data_child->x.over_marked = FALSE;
+    }
+    if(likely(hashed_process_data_child->x.middle != new_x)) {
+      hashed_process_data_child->x.middle = new_x;
+      hashed_process_data_child->x.middle_used = FALSE;
+      hashed_process_data_child->x.middle_marked = FALSE;
+    }
+    if(likely(hashed_process_data_child->x.under != new_x)) {
+      hashed_process_data_child->x.under = new_x;
+      hashed_process_data_child->x.under_used = FALSE;
+      hashed_process_data_child->x.under_marked = FALSE;
+    }
+  }
+  return 0;
+}
+
+
+
+/* after_process_exit_hook
+ * 
+ * Create the processlist entry for the child process. Put the last
+ * position in x at the current time value.
+ *
+ * @param hook_data ControlFlowData structure of the viewer. 
+ * @param call_data Event context.
+ *
+ * This function adds items to be drawn in a queue for each process.
+ * 
+ */
+int after_process_exit_hook(void *hook_data, void *call_data)
+{
+  LttvTraceHookByFacility *thf = (LttvTraceHookByFacility*)hook_data;
+  EventsRequest *events_request = (EventsRequest*)thf->hook_data;
+  ControlFlowData *control_flow_data = events_request->viewer_data;
+
+  LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
+
+  LttvTracefileState *tfs = (LttvTracefileState *)call_data;
+
+  LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
+
+  LttEvent *e;
+  e = ltt_tracefile_get_event(tfc->tf);
+
+  LttvFilter *filter = control_flow_data->filter;
+  if(filter != NULL && filter->head != NULL)
+    if(!lttv_filter_tree_parse(filter->head,e,tfc->tf,
+          tfc->t_context->t,tfc,NULL,NULL))
+      return FALSE;
+
+  LttTime evtime = ltt_event_time(e);
+
+  /* Add process to process list (if not present) */
+  //LttvProcessState *process = tfs->process;
+  guint cpu = tfs->cpu;
+  guint trace_num = ts->parent.index;
+  LttvProcessState *process = ts->running_process[cpu];
+
+  /* It should exist, because we are after the state update. */
+  g_assert(process != NULL);
+
+  guint pid = process->pid;
+  LttTime birth;
+  guint pl_height = 0;
+  HashedProcessData *hashed_process_data = NULL;
+
+  ProcessList *process_list = control_flow_data->process_list;
+
+  birth = process->creation_time;
+
+  if(likely(process_list->current_hash_data[trace_num][cpu] != NULL) ){
+    hashed_process_data = process_list->current_hash_data[trace_num][cpu];
+  } else {
+    hashed_process_data = processlist_get_process_data(process_list,
+            pid,
+            process->cpu,
+            &birth,
+            trace_num);
+    if(unlikely(hashed_process_data == NULL))
+    {
+      g_assert(pid == 0 || pid != process->ppid);
+      /* Process not present */
+      Drawing_t *drawing = control_flow_data->drawing;
+      ProcessInfo *process_info;
+      processlist_add(process_list,
+          drawing,
+          pid,
+          process->tgid,
+          process->cpu,
+          process->ppid,
+          &birth,
+          trace_num,
+          process->name,
+          process->brand,
+          &pl_height,
+          &process_info,
+          &hashed_process_data);
+      gtk_widget_set_size_request(drawing->drawing_area,
+                                  -1,
+                                  pl_height);
+      gtk_widget_queue_draw(drawing->drawing_area);
+    }
+
+    /* Set the current process */
+    process_list->current_hash_data[trace_num][process->cpu] =
+                                             hashed_process_data;
+  }
+
+  if(unlikely(ltt_time_compare(hashed_process_data->next_good_time,
+                        evtime) <= 0))
+  {
+    TimeWindow time_window = 
+      lttvwindow_get_time_window(control_flow_data->tab);
+
+#ifdef EXTRA_CHECK
+    if(ltt_time_compare(evtime, time_window.start_time) == -1
+          || ltt_time_compare(evtime, time_window.end_time) == 1)
+              return;
+#endif //EXTRA_CHECK
+    Drawing_t *drawing = control_flow_data->drawing;
+    guint width = drawing->width;
+    guint new_x;
+    convert_time_to_pixels(
+        time_window,
+        evtime,
+        width,
+        &new_x);
+    if(unlikely(hashed_process_data->x.middle != new_x)) {
+      hashed_process_data->x.middle = new_x;
+      hashed_process_data->x.middle_used = FALSE;
+      hashed_process_data->x.middle_marked = FALSE;
+    }
+  }
+
+  return 0;
+}
+
+
+/* Get the filename of the process to print */
+int after_fs_exec_hook(void *hook_data, void *call_data)
+{
+  LttvTraceHookByFacility *thf = (LttvTraceHookByFacility*)hook_data;
+  EventsRequest *events_request = (EventsRequest*)thf->hook_data;
+  ControlFlowData *control_flow_data = events_request->viewer_data;
+
+  LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
+
+  LttvTracefileState *tfs = (LttvTracefileState *)call_data;
+
+  LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
+
+  LttEvent *e;
+  e = ltt_tracefile_get_event(tfc->tf);
+
+  LttvFilter *filter = control_flow_data->filter;
+  if(filter != NULL && filter->head != NULL)
+    if(!lttv_filter_tree_parse(filter->head,e,tfc->tf,
+          tfc->t_context->t,tfc,NULL,NULL))
+      return FALSE;
+
+  guint cpu = tfs->cpu;
+  guint trace_num = ts->parent.index;
+  LttvProcessState *process = ts->running_process[cpu];
+  g_assert(process != NULL);
+
+  guint pid = process->pid;
+
+  /* Well, the process_out existed : we must get it in the process hash
+   * or add it, and draw its items.
+   */
+   /* Add process to process list (if not present) */
+  guint pl_height = 0;
+  HashedProcessData *hashed_process_data = NULL;
+  ProcessList *process_list = control_flow_data->process_list;
+  LttTime birth = process->creation_time;
+  if(likely(process_list->current_hash_data[trace_num][cpu] != NULL)) {
+    hashed_process_data = process_list->current_hash_data[trace_num][cpu];
+  } else {
+    hashed_process_data = processlist_get_process_data(process_list,
+            pid,
+            process->cpu,
+            &birth,
+            trace_num);
+    if(unlikely(hashed_process_data == NULL))
+    {
+      g_assert(pid == 0 || pid != process->ppid);
+      ProcessInfo *process_info;
+      /* Process not present */
+      Drawing_t *drawing = control_flow_data->drawing;
+      processlist_add(process_list,
+          drawing,
+          pid,
+          process->tgid,
+          process->cpu,
+          process->ppid,
+          &birth,
+          trace_num,
+          process->name,
+          process->brand,
+          &pl_height,
+          &process_info,
+          &hashed_process_data);
+        gtk_widget_set_size_request(drawing->drawing_area,
+                                    -1,
+                                    pl_height);
+        gtk_widget_queue_draw(drawing->drawing_area);
+    }
+    /* Set the current process */
+    process_list->current_hash_data[trace_num][process->cpu] =
+                                               hashed_process_data;
+  }
+
+  processlist_set_name(process_list, process->name, hashed_process_data);
+
+  return 0;
+
+}
+
+/* Get the filename of the process to print */
+int after_user_generic_thread_brand_hook(void *hook_data, void *call_data)
+{
+  LttvTraceHookByFacility *thf = (LttvTraceHookByFacility*)hook_data;
+  EventsRequest *events_request = (EventsRequest*)thf->hook_data;
+  ControlFlowData *control_flow_data = events_request->viewer_data;
+
+  LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
+
+  LttvTracefileState *tfs = (LttvTracefileState *)call_data;
+
+  LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
+
+  LttEvent *e;
+  e = ltt_tracefile_get_event(tfc->tf);
+
+  LttvFilter *filter = control_flow_data->filter;
+  if(filter != NULL && filter->head != NULL)
+    if(!lttv_filter_tree_parse(filter->head,e,tfc->tf,
+          tfc->t_context->t,tfc,NULL,NULL))
+      return FALSE;
+
+  guint cpu = tfs->cpu;
+  guint trace_num = ts->parent.index;
+  LttvProcessState *process = ts->running_process[cpu];
+  g_assert(process != NULL);
+
+  guint pid = process->pid;
+
+  /* Well, the process_out existed : we must get it in the process hash
+   * or add it, and draw its items.
+   */
+   /* Add process to process list (if not present) */
+  guint pl_height = 0;
+  HashedProcessData *hashed_process_data = NULL;
+  ProcessList *process_list = control_flow_data->process_list;
+  LttTime birth = process->creation_time;
+  if(likely(process_list->current_hash_data[trace_num][cpu] != NULL)) {
+    hashed_process_data = process_list->current_hash_data[trace_num][cpu];
+  } else {
+    hashed_process_data = processlist_get_process_data(process_list,
+            pid,
+            process->cpu,
+            &birth,
+            trace_num);
+    if(unlikely(hashed_process_data == NULL))
+    {
+      g_assert(pid == 0 || pid != process->ppid);
+      ProcessInfo *process_info;
+      /* Process not present */
+      Drawing_t *drawing = control_flow_data->drawing;
+      processlist_add(process_list,
+          drawing,
+          pid,
+          process->tgid,
+          process->cpu,
+          process->ppid,
+          &birth,
+          trace_num,
+          process->name,
+         process->brand,
+          &pl_height,
+          &process_info,
+          &hashed_process_data);
+        gtk_widget_set_size_request(drawing->drawing_area,
+                                    -1,
+                                    pl_height);
+        gtk_widget_queue_draw(drawing->drawing_area);
+    }
+    /* Set the current process */
+    process_list->current_hash_data[trace_num][process->cpu] =
+                                               hashed_process_data;
+  }
+
+  processlist_set_brand(process_list, process->brand, hashed_process_data);
+
+  return 0;
+
+}
+
+
+/* after_event_enum_process_hook
+ * 
+ * Create the processlist entry for the child process. Put the last
+ * position in x at the current time value.
+ *
+ * @param hook_data ControlFlowData structure of the viewer. 
+ * @param call_data Event context.
+ *
+ * This function adds items to be drawn in a queue for each process.
+ * 
+ */
+int after_event_enum_process_hook(void *hook_data, void *call_data)
+{
+  LttvTraceHookByFacility *thf = (LttvTraceHookByFacility*)hook_data;
+  EventsRequest *events_request = (EventsRequest*)thf->hook_data;
+  ControlFlowData *control_flow_data = events_request->viewer_data;
+
+  LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
+
+  LttvTracefileState *tfs = (LttvTracefileState *)call_data;
+
+  LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
+
+  guint first_cpu, nb_cpus, cpu;
+
+  LttEvent *e;
+  e = ltt_tracefile_get_event(tfc->tf);
+
+  LttvFilter *filter = control_flow_data->filter;
+  if(filter != NULL && filter->head != NULL)
+    if(!lttv_filter_tree_parse(filter->head,e,tfc->tf,
+          tfc->t_context->t,tfc,NULL,NULL))
+      return FALSE;
+
+  LttTime evtime = ltt_event_time(e);
+
+  /* Add process to process list (if not present) */
+  LttvProcessState *process_in;
+  LttTime birth;
+  guint pl_height = 0;
+  HashedProcessData *hashed_process_data_in = NULL;
+
+  ProcessList *process_list = control_flow_data->process_list;
+  guint trace_num = ts->parent.index;
+  
+  guint pid_in;
+  {
+    pid_in = ltt_event_get_long_unsigned(e, thf->f1);
+  }
+  
+  if(pid_in == 0) {
+    first_cpu = 0;
+    nb_cpus = ltt_trace_get_num_cpu(ts->parent.t);
+  } else {
+    first_cpu = ANY_CPU;
+    nb_cpus = ANY_CPU+1;
+  }
+
+  for(cpu = first_cpu; cpu < nb_cpus; cpu++) {
+    /* Find process pid_in in the list... */
+    process_in = lttv_state_find_process(ts, cpu, pid_in);
+    //process_in = tfs->process;
+    //guint cpu = tfs->cpu;
+    //guint trace_num = ts->parent.index;
+    //process_in = ts->running_process[cpu];
+    /* It should exist, because we are after the state update. */
+  #ifdef EXTRA_CHECK
+    //g_assert(process_in != NULL);
+  #endif //EXTRA_CHECK
+    birth = process_in->creation_time;
+
+    hashed_process_data_in = processlist_get_process_data(process_list,
+            pid_in,
+            process_in->cpu,
+            &birth,
+            trace_num);
+    if(hashed_process_data_in == NULL)
+    {
+      if(pid_in != 0 && pid_in == process_in->ppid)
+        g_critical("TEST %u , %u", pid_in, process_in->ppid);
+      g_assert(pid_in == 0 || pid_in != process_in->ppid);
+      ProcessInfo *process_info;
+      Drawing_t *drawing = control_flow_data->drawing;
+      /* Process not present */
+      processlist_add(process_list,
+          drawing,
+          pid_in,
+          process_in->tgid,
+          process_in->cpu,
+          process_in->ppid,
+          &birth,
+          trace_num,
+          process_in->name,
+          process_in->brand,
+          &pl_height,
+          &process_info,
+          &hashed_process_data_in);
+          gtk_widget_set_size_request(drawing->drawing_area,
+                                      -1,
+                                      pl_height);
+          gtk_widget_queue_draw(drawing->drawing_area);
+    } else {
+      processlist_set_name(process_list, process_in->name,
+                           hashed_process_data_in);
+      processlist_set_ppid(process_list, process_in->ppid,
+                           hashed_process_data_in);
+      processlist_set_tgid(process_list, process_in->tgid,
+                           hashed_process_data_in);
+    }
+  }
+  return 0;
+}
+
+
+gint update_time_window_hook(void *hook_data, void *call_data)
+{
+  ControlFlowData *control_flow_data = (ControlFlowData*) hook_data;
+  Drawing_t *drawing = control_flow_data->drawing;
+  ProcessList *process_list = control_flow_data->process_list;
+
+  const TimeWindowNotifyData *time_window_nofify_data = 
+                          ((const TimeWindowNotifyData *)call_data);
+
+  TimeWindow *old_time_window = 
+    time_window_nofify_data->old_time_window;
+  TimeWindow *new_time_window = 
+    time_window_nofify_data->new_time_window;
+  
+  /* Update the ruler */
+  drawing_update_ruler(control_flow_data->drawing,
+                       new_time_window);
+
+
+  /* Two cases : zoom in/out or scrolling */
+  
+  /* In order to make sure we can reuse the old drawing, the scale must
+   * be the same and the new time interval being partly located in the
+   * currently shown time interval. (reuse is only for scrolling)
+   */
+
+  g_info("Old time window HOOK : %lu, %lu to %lu, %lu",
+      old_time_window->start_time.tv_sec,
+      old_time_window->start_time.tv_nsec,
+      old_time_window->time_width.tv_sec,
+      old_time_window->time_width.tv_nsec);
+
+  g_info("New time window HOOK : %lu, %lu to %lu, %lu",
+      new_time_window->start_time.tv_sec,
+      new_time_window->start_time.tv_nsec,
+      new_time_window->time_width.tv_sec,
+      new_time_window->time_width.tv_nsec);
+
+  if( new_time_window->time_width.tv_sec == old_time_window->time_width.tv_sec
+  && new_time_window->time_width.tv_nsec == old_time_window->time_width.tv_nsec)
+  {
+    /* Same scale (scrolling) */
+    g_info("scrolling");
+    LttTime *ns = &new_time_window->start_time;
+    LttTime *nw = &new_time_window->time_width;
+    LttTime *os = &old_time_window->start_time;
+    LttTime *ow = &old_time_window->time_width;
+    LttTime old_end = old_time_window->end_time;
+    LttTime new_end = new_time_window->end_time;
+    //if(ns<os+w<ns+w)
+    //if(ns<os+w && os+w<ns+w)
+    //if(ns<old_end && os<ns)
+    if(ltt_time_compare(*ns, old_end) == -1
+        && ltt_time_compare(*os, *ns) == -1)
+    {
+      g_info("scrolling near right");
+      /* Scroll right, keep right part of the screen */
+      guint x = 0;
+      guint width = control_flow_data->drawing->width;
+      convert_time_to_pixels(
+          *old_time_window,
+          *ns,
+          width,
+          &x);
+
+      /* Copy old data to new location */
+      copy_pixmap_region(process_list,
+                  NULL,
+                  control_flow_data->drawing->drawing_area->style->black_gc,
+                  NULL,
+                  x, 0,
+                  0, 0,
+                  control_flow_data->drawing->width-x+SAFETY, -1);
+
+      if(drawing->damage_begin == drawing->damage_end)
+        drawing->damage_begin = control_flow_data->drawing->width-x;
+      else
+        drawing->damage_begin = 0;
+
+      drawing->damage_end = control_flow_data->drawing->width;
+
+      /* Clear the data request background, but not SAFETY */
+      rectangle_pixmap(process_list,
+          control_flow_data->drawing->drawing_area->style->black_gc,
+          TRUE,
+          drawing->damage_begin+SAFETY, 0,
+          drawing->damage_end - drawing->damage_begin,  // do not overlap
+          -1);
+      gtk_widget_queue_draw(drawing->drawing_area);
+      //gtk_widget_queue_draw_area (drawing->drawing_area,
+      //                          0,0,
+      //                          control_flow_data->drawing->width,
+      //                          control_flow_data->drawing->height);
+
+      /* Get new data for the rest. */
+      drawing_data_request(control_flow_data->drawing,
+          drawing->damage_begin, 0,
+          drawing->damage_end - drawing->damage_begin,
+          control_flow_data->drawing->height);
+    } else { 
+      //if(ns<os<ns+w)
+      //if(ns<os && os<ns+w)
+      //if(ns<os && os<new_end)
+      if(ltt_time_compare(*ns,*os) == -1
+          && ltt_time_compare(*os,new_end) == -1)
+      {
+        g_info("scrolling near left");
+        /* Scroll left, keep left part of the screen */
+        guint x = 0;
+        guint width = control_flow_data->drawing->width;
+        convert_time_to_pixels(
+            *new_time_window,
+            *os,
+            width,
+            &x);
+        
+        /* Copy old data to new location */
+        copy_pixmap_region  (process_list,
+            NULL,
+            control_flow_data->drawing->drawing_area->style->black_gc,
+            NULL,
+            0, 0,
+            x, 0,
+            -1, -1);
+  
+        if(drawing->damage_begin == drawing->damage_end)
+          drawing->damage_end = x;
+        else
+          drawing->damage_end = 
+            control_flow_data->drawing->width;
+
+        drawing->damage_begin = 0;
+        
+        rectangle_pixmap (process_list,
+          control_flow_data->drawing->drawing_area->style->black_gc,
+          TRUE,
+          drawing->damage_begin, 0,
+          drawing->damage_end - drawing->damage_begin,  // do not overlap
+          -1);
+
+        gtk_widget_queue_draw(drawing->drawing_area);
+        //gtk_widget_queue_draw_area (drawing->drawing_area,
+        //                        0,0,
+        //                        control_flow_data->drawing->width,
+        //                        control_flow_data->drawing->height);
+
+
+        /* Get new data for the rest. */
+        drawing_data_request(control_flow_data->drawing,
+            drawing->damage_begin, 0,
+            drawing->damage_end - drawing->damage_begin,
+            control_flow_data->drawing->height);
+    
+      } else {
+        if(ltt_time_compare(*ns,*os) == 0)
+        {
+          g_info("not scrolling");
+        } else {
+          g_info("scrolling far");
+          /* Cannot reuse any part of the screen : far jump */
+          
+          
+          rectangle_pixmap (process_list,
+            control_flow_data->drawing->drawing_area->style->black_gc,
+            TRUE,
+            0, 0,
+            control_flow_data->drawing->width+SAFETY, // do not overlap
+            -1);
+
+          //gtk_widget_queue_draw_area (drawing->drawing_area,
+          //                      0,0,
+          //                      control_flow_data->drawing->width,
+          //                      control_flow_data->drawing->height);
+          gtk_widget_queue_draw(drawing->drawing_area);
+
+          drawing->damage_begin = 0;
+          drawing->damage_end = control_flow_data->drawing->width;
+
+          drawing_data_request(control_flow_data->drawing,
+              0, 0,
+              control_flow_data->drawing->width,
+              control_flow_data->drawing->height);
+      
+        }
+      }
+    }
+  } else {
+    /* Different scale (zoom) */
+    g_info("zoom");
+
+    rectangle_pixmap (process_list,
+          control_flow_data->drawing->drawing_area->style->black_gc,
+          TRUE,
+          0, 0,
+          control_flow_data->drawing->width+SAFETY, // do not overlap
+          -1);
+
+    //gtk_widget_queue_draw_area (drawing->drawing_area,
+    //                            0,0,
+    //                            control_flow_data->drawing->width,
+    //                            control_flow_data->drawing->height);
+    gtk_widget_queue_draw(drawing->drawing_area);
+  
+    drawing->damage_begin = 0;
+    drawing->damage_end = control_flow_data->drawing->width;
+
+    drawing_data_request(control_flow_data->drawing,
+        0, 0,
+        control_flow_data->drawing->width,
+        control_flow_data->drawing->height);
+  }
+
+  /* Update directly when scrolling */
+  gdk_window_process_updates(control_flow_data->drawing->drawing_area->window,
+      TRUE);
+
+  return 0;
+}
+
+gint traceset_notify(void *hook_data, void *call_data)
+{
+  ControlFlowData *control_flow_data = (ControlFlowData*) hook_data;
+  Drawing_t *drawing = control_flow_data->drawing;
+
+  if(unlikely(drawing->gc == NULL)) {
+    return FALSE;
+  }
+  if(drawing->dotted_gc == NULL) {
+    return FALSE;
+  }
+
+  drawing_clear(control_flow_data->drawing);
+  processlist_clear(control_flow_data->process_list);
+  gtk_widget_set_size_request(
+      control_flow_data->drawing->drawing_area,
+                -1, processlist_get_height(control_flow_data->process_list));
+  redraw_notify(control_flow_data, NULL);
+
+  request_background_data(control_flow_data);
+  return FALSE;
+}
+
+gint redraw_notify(void *hook_data, void *call_data)
+{
+  ControlFlowData *control_flow_data = (ControlFlowData*) hook_data;
+  Drawing_t *drawing = control_flow_data->drawing;
+  GtkWidget *widget = drawing->drawing_area;
+
+  drawing->damage_begin = 0;
+  drawing->damage_end = drawing->width;
+
+  /* fun feature, to be separated someday... */
+  drawing_clear(control_flow_data->drawing);
+  processlist_clear(control_flow_data->process_list);
+  gtk_widget_set_size_request(
+      control_flow_data->drawing->drawing_area,
+                -1, processlist_get_height(control_flow_data->process_list));
+  // Clear the images
+  rectangle_pixmap (control_flow_data->process_list,
+        widget->style->black_gc,
+        TRUE,
+        0, 0,
+        drawing->alloc_width,
+        -1);
+
+  gtk_widget_queue_draw(drawing->drawing_area);
+  
+  if(drawing->damage_begin < drawing->damage_end)
+  {
+    drawing_data_request(drawing,
+                         drawing->damage_begin,
+                         0,
+                         drawing->damage_end-drawing->damage_begin,
+                         drawing->height);
+  }
+
+  //gtk_widget_queue_draw_area(drawing->drawing_area,
+  //                           0,0,
+  //                           drawing->width,
+  //                           drawing->height);
+  return FALSE;
+
+}
+
+
+gint continue_notify(void *hook_data, void *call_data)
+{
+  ControlFlowData *control_flow_data = (ControlFlowData*) hook_data;
+  Drawing_t *drawing = control_flow_data->drawing;
+
+  //g_assert(widget->allocation.width == drawing->damage_end);
+
+  if(drawing->damage_begin < drawing->damage_end)
+  {
+    drawing_data_request(drawing,
+                         drawing->damage_begin,
+                         0,
+                         drawing->damage_end-drawing->damage_begin,
+                         drawing->height);
+  }
+
+  return FALSE;
+}
+
+
+gint update_current_time_hook(void *hook_data, void *call_data)
+{
+  ControlFlowData *control_flow_data = (ControlFlowData*)hook_data;
+  Drawing_t *drawing = control_flow_data->drawing;
+
+  LttTime current_time = *((LttTime*)call_data);
+  
+  TimeWindow time_window =
+            lttvwindow_get_time_window(control_flow_data->tab);
+  
+  LttTime time_begin = time_window.start_time;
+  LttTime width = time_window.time_width;
+  LttTime half_width;
+  {
+    guint64 time_ll = ltt_time_to_uint64(width);
+    time_ll = time_ll >> 1; /* divide by two */
+    half_width = ltt_time_from_uint64(time_ll);
+  }
+  LttTime time_end = ltt_time_add(time_begin, width);
+
+  LttvTracesetContext * tsc =
+        lttvwindow_get_traceset_context(control_flow_data->tab);
+  
+  LttTime trace_start = tsc->time_span.start_time;
+  LttTime trace_end = tsc->time_span.end_time;
+  
+  g_info("New current time HOOK : %lu, %lu", current_time.tv_sec,
+              current_time.tv_nsec);
+
+
+  
+  /* If current time is inside time interval, just move the highlight
+   * bar */
+
+  /* Else, we have to change the time interval. We have to tell it
+   * to the main window. */
+  /* The time interval change will take care of placing the current
+   * time at the center of the visible area, or nearest possible if we are
+   * at one end of the trace. */
+  
+  
+  if(ltt_time_compare(current_time, time_begin) < 0)
+  {
+    TimeWindow new_time_window;
+
+    if(ltt_time_compare(current_time,
+          ltt_time_add(trace_start,half_width)) < 0)
+      time_begin = trace_start;
+    else
+      time_begin = ltt_time_sub(current_time,half_width);
+  
+    new_time_window.start_time = time_begin;
+    new_time_window.time_width = width;
+    new_time_window.time_width_double = ltt_time_to_double(width);
+    new_time_window.end_time = ltt_time_add(time_begin, width);
+
+    lttvwindow_report_time_window(control_flow_data->tab, new_time_window);
+  }
+  else if(ltt_time_compare(current_time, time_end) > 0)
+  {
+    TimeWindow new_time_window;
+
+    if(ltt_time_compare(current_time, ltt_time_sub(trace_end, half_width)) > 0)
+      time_begin = ltt_time_sub(trace_end,width);
+    else
+      time_begin = ltt_time_sub(current_time,half_width);
+  
+    new_time_window.start_time = time_begin;
+    new_time_window.time_width = width;
+    new_time_window.time_width_double = ltt_time_to_double(width);
+    new_time_window.end_time = ltt_time_add(time_begin, width);
+
+    lttvwindow_report_time_window(control_flow_data->tab, new_time_window);
+    
+  }
+  gtk_widget_queue_draw(control_flow_data->drawing->drawing_area);
+  
+  /* Update directly when scrolling */
+  gdk_window_process_updates(control_flow_data->drawing->drawing_area->window,
+      TRUE);
+                             
+  return 0;
+}
+
+typedef struct _ClosureData {
+  EventsRequest *events_request;
+  LttvTracesetState *tss;
+  LttTime end_time;
+  guint x_end;
+} ClosureData;
+  
+
+void draw_closure(gpointer key, gpointer value, gpointer user_data)
+{
+  ProcessInfo *process_info = (ProcessInfo*)key;
+  HashedProcessData *hashed_process_data = (HashedProcessData*)value;
+  ClosureData *closure_data = (ClosureData*)user_data;
+    
+  EventsRequest *events_request = closure_data->events_request;
+  ControlFlowData *control_flow_data = events_request->viewer_data;
+
+  LttvTracesetState *tss = closure_data->tss;
+  LttvTracesetContext *tsc = (LttvTracesetContext*)tss;
+
+  LttTime evtime = closure_data->end_time;
+
+  gboolean dodraw = TRUE;
+
+  { 
+    /* For the process */
+    /* First, check if the current process is in the state computation
+     * process list. If it is there, that means we must add it right now and
+     * draw items from the beginning of the read for it. If it is not
+     * present, it's a new process and it was not present : it will
+     * be added after the state update.  */
+#ifdef EXTRA_CHECK
+    g_assert(lttv_traceset_number(tsc->ts) > 0);
+#endif //EXTRA_CHECK
+    LttvTraceContext *tc = tsc->traces[process_info->trace_num];
+    LttvTraceState *ts = (LttvTraceState*)tc;
+
+#if 0
+    //FIXME : optimize data structures.
+    LttvTracefileState *tfs;
+    LttvTracefileContext *tfc;
+    guint i;
+    for(i=0;i<tc->tracefiles->len;i++) {
+      tfc = g_array_index(tc->tracefiles, LttvTracefileContext*, i);
+      if(ltt_tracefile_name(tfc->tf) == LTT_NAME_CPU
+          && tfs->cpu == process_info->cpu)
+        break;
+
+    }
+    g_assert(i<tc->tracefiles->len);
+    tfs = LTTV_TRACEFILE_STATE(tfc);
+#endif //0
+ //   LttvTracefileState *tfs =
+ //    (LttvTracefileState*)tsc->traces[process_info->trace_num]->
+ //                        tracefiles[process_info->cpu];
+    LttvProcessState *process;
+    process = lttv_state_find_process(ts, process_info->cpu,
+                                      process_info->pid);
+
+    if(unlikely(process != NULL)) {
+      
+       LttvFilter *filter = control_flow_data->filter;
+       if(filter != NULL && filter->head != NULL)
+         if(!lttv_filter_tree_parse(filter->head,NULL,NULL,
+             tc->t,NULL,process,tc))
+           dodraw = FALSE;
+
+      /* Only draw for processes that are currently in the trace states */
+
+      ProcessList *process_list = control_flow_data->process_list;
+#ifdef EXTRA_CHECK
+      /* Should be alike when background info is ready */
+      if(control_flow_data->background_info_waiting==0)
+        g_assert(ltt_time_compare(process->creation_time,
+                                  process_info->birth) == 0);
+#endif //EXTRA_CHECK
+    
+      /* Now, the process is in the state hash and our own process hash.
+       * We definitely can draw the items related to the ending state.
+       */
+      
+      if(unlikely(ltt_time_compare(hashed_process_data->next_good_time,
+                            evtime) <= 0))
+      {
+        TimeWindow time_window = 
+          lttvwindow_get_time_window(control_flow_data->tab);
+
+#ifdef EXTRA_CHECK
+        if(ltt_time_compare(evtime, time_window.start_time) == -1
+              || ltt_time_compare(evtime, time_window.end_time) == 1)
+                  return;
+#endif //EXTRA_CHECK
+        Drawing_t *drawing = control_flow_data->drawing;
+        guint width = drawing->width;
+
+        guint x = closure_data->x_end;
+
+        DrawContext draw_context;
+
+        /* Now create the drawing context that will be used to draw
+         * items related to the last state. */
+        draw_context.drawable = hashed_process_data->pixmap;
+        draw_context.gc = drawing->gc;
+        draw_context.pango_layout = drawing->pango_layout;
+        draw_context.drawinfo.end.x = x;
+
+        draw_context.drawinfo.y.over = 1;
+        draw_context.drawinfo.y.middle = (hashed_process_data->height/2);
+        draw_context.drawinfo.y.under = hashed_process_data->height;
+
+        draw_context.drawinfo.start.offset.over = 0;
+        draw_context.drawinfo.start.offset.middle = 0;
+        draw_context.drawinfo.start.offset.under = 0;
+        draw_context.drawinfo.end.offset.over = 0;
+        draw_context.drawinfo.end.offset.middle = 0;
+        draw_context.drawinfo.end.offset.under = 0;
+#if 0
+        /* Jump over draw if we are at the same x position */
+        if(x == hashed_process_data->x.over)
+        {
+          /* jump */
+        } else {
+          draw_context.drawinfo.start.x = hashed_process_data->x.over;
+          /* Draw the line */
+          PropertiesLine prop_line = prepare_execmode_line(process);
+          draw_line((void*)&prop_line, (void*)&draw_context);
+
+          hashed_process_data->x.over = x;
+        }
+#endif //0
+
+        if(unlikely(x == hashed_process_data->x.middle &&
+            hashed_process_data->x.middle_used)) {
+#if 0 /* do not mark closure : not missing information */
+          if(hashed_process_data->x.middle_marked == FALSE) {
+            /* Draw collision indicator */
+            gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
+            gdk_draw_point(drawing->pixmap,
+                           drawing->gc,
+                           x,
+                           y+(height/2)-3);
+            hashed_process_data->x.middle_marked = TRUE;
+          }
+#endif //0
+          /* Jump */
+        } else {
+          draw_context.drawinfo.start.x = hashed_process_data->x.middle;
+          /* Draw the line */
+          if(dodraw) {
+                  PropertiesLine prop_line = prepare_s_e_line(process);
+                  draw_line((void*)&prop_line, (void*)&draw_context);
+          }
+
+           /* become the last x position */
+          if(likely(x != hashed_process_data->x.middle)) {
+            hashed_process_data->x.middle = x;
+            /* but don't use the pixel */
+            hashed_process_data->x.middle_used = FALSE;
+
+            /* Calculate the next good time */
+            convert_pixels_to_time(width, x+1, time_window,
+                                  &hashed_process_data->next_good_time);
+          }
+        }
+      }
+    }
+  }
+  return;
+}
+
+int before_chunk(void *hook_data, void *call_data)
+{
+  EventsRequest *events_request = (EventsRequest*)hook_data;
+  LttvTracesetState *tss = (LttvTracesetState*)call_data;
+  ControlFlowData *cfd = (ControlFlowData*)events_request->viewer_data;
+#if 0  
+  /* Desactivate sort */
+  gtk_tree_sortable_set_sort_column_id(
+      GTK_TREE_SORTABLE(cfd->process_list->list_store),
+      TRACE_COLUMN,
+      GTK_SORT_ASCENDING);
+#endif //0
+  drawing_chunk_begin(events_request, tss);
+
+  return 0;
+}
+
+int before_request(void *hook_data, void *call_data)
+{
+  EventsRequest *events_request = (EventsRequest*)hook_data;
+  LttvTracesetState *tss = (LttvTracesetState*)call_data;
+  drawing_data_request_begin(events_request, tss);
+
+  return 0;
+}
+
+
+/*
+ * after request is necessary in addition of after chunk in order to draw 
+ * lines until the end of the screen. after chunk just draws lines until
+ * the last event.
+ * 
+ * for each process
+ *    draw closing line
+ *    expose
+ */
+int after_request(void *hook_data, void *call_data)
+{
+  EventsRequest *events_request = (EventsRequest*)hook_data;
+  ControlFlowData *control_flow_data = events_request->viewer_data;
+  LttvTracesetState *tss = (LttvTracesetState*)call_data;
+  
+  ProcessList *process_list = control_flow_data->process_list;
+  LttTime end_time = events_request->end_time;
+
+  ClosureData closure_data;
+  closure_data.events_request = (EventsRequest*)hook_data;
+  closure_data.tss = tss;
+  closure_data.end_time = end_time;
+
+  TimeWindow time_window = 
+          lttvwindow_get_time_window(control_flow_data->tab);
+  guint width = control_flow_data->drawing->width;
+  convert_time_to_pixels(
+            time_window,
+            end_time,
+            width,
+            &closure_data.x_end);
+
+
+  /* Draw last items */
+  g_hash_table_foreach(process_list->process_hash, draw_closure,
+                        (void*)&closure_data);
+  
+
+  /* Request expose */
+  drawing_request_expose(events_request, tss, end_time);
+  return 0;
+}
+
+/*
+ * for each process
+ *    draw closing line
+ * expose
+ */
+int after_chunk(void *hook_data, void *call_data)
+{
+  EventsRequest *events_request = (EventsRequest*)hook_data;
+  ControlFlowData *control_flow_data = events_request->viewer_data;
+  LttvTracesetState *tss = (LttvTracesetState*)call_data;
+  LttvTracesetContext *tsc = (LttvTracesetContext*)call_data;
+  LttvTracefileContext *tfc = lttv_traceset_context_get_current_tfc(tsc);
+  LttTime end_time;
+  
+  ProcessList *process_list = control_flow_data->process_list;
+  guint i;
+  LttvTraceset *traceset = tsc->ts;
+  guint nb_trace = lttv_traceset_number(traceset);
+
+  /* Only execute when called for the first trace's events request */
+  if(!process_list->current_hash_data) return;
+
+  for(i = 0 ; i < nb_trace ; i++) {
+    g_free(process_list->current_hash_data[i]);
+  }
+  g_free(process_list->current_hash_data);
+  process_list->current_hash_data = NULL;
+
+  if(tfc != NULL)
+    end_time = LTT_TIME_MIN(tfc->timestamp, events_request->end_time);
+  else /* end of traceset, or position now out of request : end */
+    end_time = events_request->end_time;
+  
+  ClosureData closure_data;
+  closure_data.events_request = (EventsRequest*)hook_data;
+  closure_data.tss = tss;
+  closure_data.end_time = end_time;
+
+  TimeWindow time_window = 
+          lttvwindow_get_time_window(control_flow_data->tab);
+  guint width = control_flow_data->drawing->width;
+  convert_time_to_pixels(
+            time_window,
+            end_time,
+            width,
+            &closure_data.x_end);
+
+  /* Draw last items */
+  g_hash_table_foreach(process_list->process_hash, draw_closure,
+                        (void*)&closure_data);
+#if 0
+  /* Reactivate sort */
+  gtk_tree_sortable_set_sort_column_id(
+      GTK_TREE_SORTABLE(control_flow_data->process_list->list_store),
+      GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
+      GTK_SORT_ASCENDING);
+
+  update_index_to_pixmap(control_flow_data->process_list);
+  /* Request a full expose : drawing scrambled */
+  gtk_widget_queue_draw(control_flow_data->drawing->drawing_area);
+#endif //0
+  /* Request expose (updates damages zone also) */
+  drawing_request_expose(events_request, tss, end_time);
+
+  return 0;
+}
+
+/* after_statedump_end
+ * 
+ * @param hook_data ControlFlowData structure of the viewer. 
+ * @param call_data Event context.
+ *
+ * This function adds items to be drawn in a queue for each process.
+ * 
+ */
+int before_statedump_end(void *hook_data, void *call_data)
+{
+  LttvTraceHookByFacility *thf = (LttvTraceHookByFacility*)hook_data;
+  EventsRequest *events_request = (EventsRequest*)thf->hook_data;
+  ControlFlowData *control_flow_data = events_request->viewer_data;
+
+  LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
+
+  LttvTracefileState *tfs = (LttvTracefileState *)call_data;
+
+  LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
+
+  LttvTracesetState *tss = (LttvTracesetState*)tfc->t_context->ts_context;
+  ProcessList *process_list = control_flow_data->process_list;
+
+  LttEvent *e;
+  e = ltt_tracefile_get_event(tfc->tf);
+
+  LttvFilter *filter = control_flow_data->filter;
+  if(filter != NULL && filter->head != NULL)
+    if(!lttv_filter_tree_parse(filter->head,e,tfc->tf,
+          tfc->t_context->t,tfc,NULL,NULL))
+      return FALSE;
+
+  LttTime evtime = ltt_event_time(e);
+
+  ClosureData closure_data;
+  closure_data.events_request = events_request;
+  closure_data.tss = tss;
+  closure_data.end_time = evtime;
+
+  TimeWindow time_window = 
+          lttvwindow_get_time_window(control_flow_data->tab);
+  guint width = control_flow_data->drawing->width;
+  convert_time_to_pixels(
+            time_window,
+            evtime,
+            width,
+            &closure_data.x_end);
+
+  /* Draw last items */
+  g_hash_table_foreach(process_list->process_hash, draw_closure,
+                        (void*)&closure_data);
+#if 0
+  /* Reactivate sort */
+  gtk_tree_sortable_set_sort_column_id(
+      GTK_TREE_SORTABLE(control_flow_data->process_list->list_store),
+      GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
+      GTK_SORT_ASCENDING);
+
+  update_index_to_pixmap(control_flow_data->process_list);
+  /* Request a full expose : drawing scrambled */
+  gtk_widget_queue_draw(control_flow_data->drawing->drawing_area);
+#endif //0
+  /* Request expose (updates damages zone also) */
+  drawing_request_expose(events_request, tss, evtime);
+
+  return 0;
+}
diff --git a/ltt/branches/poly/lttv/modules/gui/resourceview/eventhooks.h b/ltt/branches/poly/lttv/modules/gui/resourceview/eventhooks.h
new file mode 100644 (file)
index 0000000..8837612
--- /dev/null
@@ -0,0 +1,123 @@
+/* This file is part of the Linux Trace Toolkit viewer
+ * Copyright (C) 2003-2004 Mathieu Desnoyers
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License Version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, 
+ * MA 02111-1307, USA.
+ */
+
+
+/* eventhooks.h defines the hooks that are given to processTrace as parameter.
+ * These hooks call the drawing API to draw the information on the screen,
+ * using information from Context, but mostly state (running, waiting...).
+ */
+
+
+#ifndef _EVENT_HOOKS_H
+#define _EVENT_HOOKS_H
+
+#include <gtk/gtk.h>
+#include <lttvwindow/mainwindow.h>
+#include <ltt/time.h>
+
+#include "processlist.h"
+#include "drawing.h"
+#include "cfv.h"
+
+
+/* Structure used to store and use information relative to one events refresh
+ * request. Typically filled in by the expose event callback, then passed to the
+ * library call, then used by the drawing hooks. Then, once all the events are
+ * sent, it is freed by the hook called after the reading.
+ */
+//typedef struct _EventRequest
+//{
+//  ControlFlowData *control_flow_data;
+//  LttTime time_begin, time_end;
+//  gint  x_begin, x_end;
+  /* Fill the Events_Context during the initial expose, before calling for
+   * events.
+   */
+  //GArray Events_Context; //FIXME
+//} EventRequest ;
+
+
+
+
+
+void send_test_data(ProcessList *process_list, Drawing_t *drawing);
+
+GtkWidget *h_guicontrolflow(LttvPlugin *plugin);
+
+GtkWidget *h_legend(LttvPlugin *plugin);
+
+int event_selected_hook(void *hook_data, void *call_data);
+
+/*
+ * The draw event hook is called by the reading API to have a
+ * particular event drawn on the screen.
+ * @param hook_data ControlFlowData structure of the viewer. 
+ * @param call_data Event context with state.
+ *
+ * This function basically draw lines and icons. Two types of lines are drawn :
+ * one small (3 pixels?) representing the state of the process and the second
+ * type is thicker (10 pixels?) representing on which CPU a process is running
+ * (and this only in running state).
+ *
+ * Extremums of the lines :
+ * x_min : time of the last event context for this process kept in memory.
+ * x_max : time of the current event.
+ * y : middle of the process in the process list. The process is found in the
+ * list, therefore is it's position in pixels.
+ *
+ * The choice of lines'color is defined by the context of the last event for this
+ * process.
+ */
+int before_schedchange_hook(void *hook_data, void *call_data);
+int after_schedchange_hook(void *hook_data, void *call_data);
+int before_execmode_hook(void *hook_data, void *call_data);
+int after_execmode_hook(void *hook_data, void *call_data);
+
+
+int before_process_exit_hook(void *hook_data, void *call_data);
+int before_process_release_hook(void *hook_data, void *call_data);
+int after_process_exit_hook(void *hook_data, void *call_data);
+int after_process_fork_hook(void *hook_data, void *call_data);
+int after_fs_exec_hook(void *hook_data, void *call_data);
+int after_user_generic_thread_brand_hook(void *hook_data, void *call_data);
+int after_event_enum_process_hook(void *hook_data, void *call_data);
+
+#if 0
+int before_process_hook(void *hook_data, void *call_data);
+int after_process_hook(void *hook_data, void *call_data);
+#endif //0
+
+void draw_closure(gpointer key, gpointer value, gpointer user_data);
+
+int  before_chunk(void *hook_data, void *call_data);
+int  after_chunk(void *hook_data, void *call_data);
+int  before_request(void *hook_data, void *call_data);
+int  after_request(void *hook_data, void *call_data);
+int  before_statedump_end(void *hook_data, void *call_data);
+
+
+
+gint update_time_window_hook(void *hook_data, void *call_data);
+gint update_current_time_hook(void *hook_data, void *call_data);
+gint traceset_notify(void *hook_data, void *call_data);
+gint redraw_notify(void *hook_data, void *call_data);
+gint continue_notify(void *hook_data, void *call_data);
+
+void legend_destructor(GtkWindow *legend);
+
+#endif // _EVENT_HOOKS_H
diff --git a/ltt/branches/poly/lttv/modules/gui/resourceview/hGuiControlFlowInsert.xpm b/ltt/branches/poly/lttv/modules/gui/resourceview/hGuiControlFlowInsert.xpm
new file mode 100644 (file)
index 0000000..db4b727
--- /dev/null
@@ -0,0 +1,28 @@
+/* XPM */
+static char * hGuiControlFlowInsert_xpm[] = {
+"22 22 3 1",
+"      c None",
+".     c #0DF904",
+"+     c #F90404",
+"                      ",
+"          .           ",
+"          ..          ",
+"          ...         ",
+"          ....        ",
+"          ...         ",
+"          ..          ",
+"          .           ",
+"                      ",
+"++++++++++............",
+"++++++++++............",
+"                      ",
+"          ++++++      ",
+"          ++++++      ",
+"          ++++++      ",
+"          ++++++      ",
+"          ++++++      ",
+"          ++++++      ",
+"                      ",
+"..........++++++++++++",
+"..........++++++++++++",
+"                      "};
diff --git a/ltt/branches/poly/lttv/modules/gui/resourceview/hLegendInsert.xpm b/ltt/branches/poly/lttv/modules/gui/resourceview/hLegendInsert.xpm
new file mode 100644 (file)
index 0000000..a6ff0f3
--- /dev/null
@@ -0,0 +1,45 @@
+/* XPM */
+static char * hLegendInsert_xpm[] = {
+"22 22 20 1",
+"      c None",
+".     c #0DF904",
+"+     c #000000",
+"@     c #000500",
+"#     c #000B00",
+"$     c #034001",
+"%     c #000200",
+"&     c #0CF403",
+"*     c #0BD603",
+"=     c #034901",
+"-     c #F90404",
+";     c #0AC503",
+">     c #000F00",
+",     c #034601",
+"'     c #0CF503",
+")     c #D60303",
+"!     c #001000",
+"~     c #044E01",
+"{     c #0CF203",
+"]     c #E40303",
+"                      ",
+"          .           ",
+"          ..          ",
+"        ++@#$         ",
+"       ++++++%        ",
+"       +  &*=++       ",
+"          .. ++       ",
+"          .  ++       ",
+"            ++        ",
+"----------;>+,'.......",
+"---------)!+~{........",
+"         +++          ",
+"         ++]----      ",
+"         ++-----      ",
+"         ++-----      ",
+"          ------      ",
+"         ++-----      ",
+"         ++-----      ",
+"                      ",
+"..........------------",
+"..........------------",
+"                      "};
diff --git a/ltt/branches/poly/lttv/modules/gui/resourceview/lttv_plugin_cfv.c b/ltt/branches/poly/lttv/modules/gui/resourceview/lttv_plugin_cfv.c
new file mode 100644 (file)
index 0000000..d8b005a
--- /dev/null
@@ -0,0 +1,84 @@
+/* This file is part of the Linux Trace Toolkit viewer
+ * Copyright (C) 2006 Mathieu Desnoyers
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License Version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, 
+ * MA 02111-1307, USA.
+ */
+
+
+#include "lttv_plugin_cfv.h"
+#include <lttvwindow/lttvwindow.h>
+#include "drawing.h"
+
+/* 
+ * forward definitions
+ */
+
+/*
+ * Implementation
+ */
+
+static void cfv_update_filter(LttvPlugin *parent, LttvFilter *filter)
+{
+  LttvPluginCFV *self = LTTV_PLUGIN_CFV(parent);
+  g_message("In CFV update filter.");
+  lttv_filter_destroy(self->cfd->filter);
+  self->cfd->filter = filter;
+  redraw_notify(self->cfd, NULL);
+}
+
+
+static void
+lttv_plugin_cfv_class_init (LttvPluginCFVClass *klass)
+{
+  LttvPluginClass *parent_klass;
+  parent_klass = &klass->parent;
+  parent_klass->update_filter = cfv_update_filter;
+  g_type_class_add_private (klass, sizeof (ControlFlowData));
+}
+
+
+static void
+lttv_plugin_cfv_init (GTypeInstance *instance, gpointer g_class)
+{
+  LttvPluginCFV *self = LTTV_PLUGIN_CFV (instance);
+  self->cfd = G_TYPE_INSTANCE_GET_PRIVATE (self,
+      LTTV_TYPE_PLUGIN_CFV, ControlFlowData);
+}
+
+
+GType
+lttv_plugin_cfv_get_type (void)
+{
+  static GType type = 0;
+  if (type == 0) {
+    static const GTypeInfo info = {
+      sizeof (LttvPluginCFVClass),
+      NULL,   /* base_init */
+      NULL,   /* base_finalize */
+      lttv_plugin_cfv_class_init,   /* class_init */
+      NULL,   /* class_finalize */
+      NULL,   /* class_data */
+      sizeof (LttvPluginCFV),
+      0,      /* n_preallocs */
+      lttv_plugin_cfv_init    /* instance_init */
+      };
+      type = g_type_register_static (G_TYPE_OBJECT,
+                                     "LttvPluginCFVType",
+                                     &info, 0);
+    }
+    return type;
+}
+
+
diff --git a/ltt/branches/poly/lttv/modules/gui/resourceview/lttv_plugin_cfv.h b/ltt/branches/poly/lttv/modules/gui/resourceview/lttv_plugin_cfv.h
new file mode 100644 (file)
index 0000000..45445da
--- /dev/null
@@ -0,0 +1,63 @@
+/* This file is part of the Linux Trace Toolkit viewer
+ * Copyright (C) 2006 Mathieu Desnoyers
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License Version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, 
+ * MA 02111-1307, USA.
+ */
+
+#ifndef LTTV_PLUGIN_CFV_H
+#define LTTV_PLUGIN_CFV_H
+
+#include <lttvwindow/lttv_plugin.h>
+#include <lttvwindow/mainwindow-private.h>
+#include "cfv.h"
+
+/*
+ * Type macros.
+ */
+
+#define LTTV_TYPE_PLUGIN_CFV             (lttv_plugin_cfv_get_type ())
+#define LTTV_PLUGIN_CFV(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), LTTV_TYPE_PLUGIN_CFV, LttvPluginCFV))
+#define LTTV_PLUGIN_CFV_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), LTTV_TYPE_PLUGIN_CFV, LttvPluginCFVClass))
+#define LTTV_IS_PLUGIN_CFV(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), LTTV_TYPE_PLUGIN_CFV))
+#define LTTV_IS_PLUGIN_CFV_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), LTTV_TYPE_PLUGIN_CFV))
+#define LTTV_PLUGIN_CFV_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), LTTV_TYPE_PLUGIN_CFV, LttvPluginCFVClass))
+
+typedef struct _LttvPluginCFV LttvPluginCFV;
+typedef struct _LttvPluginCFVClass LttvPluginCFVClass;
+
+struct _LttvPluginCFV {
+  LttvPlugin parent;
+
+  /* instance members */
+  ControlFlowData *cfd;
+
+  /* private */
+};
+
+struct _LttvPluginCFVClass {
+  LttvPluginClass parent;
+
+  /* class members */
+};
+
+/* used by LTTV_PLUGIN_TAB_TYPE */
+GType lttv_plugin_cfv_get_type (void);
+
+/*
+ * Method definitions.
+ */
+
+
+#endif
diff --git a/ltt/branches/poly/lttv/modules/gui/resourceview/module.c b/ltt/branches/poly/lttv/modules/gui/resourceview/module.c
new file mode 100644 (file)
index 0000000..8165cce
--- /dev/null
@@ -0,0 +1,95 @@
+/* This file is part of the Linux Trace Toolkit viewer
+ * Copyright (C) 2007 Pierre-Marc Fournier
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License Version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, 
+ * MA 02111-1307, USA.
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include <lttv/lttv.h>
+#include <lttv/module.h>
+#include <lttvwindow/lttvwindow.h>
+
+#include "cfv.h"
+#include "lttv_plugin_cfv.h"
+#include "eventhooks.h"
+
+#include "hGuiControlFlowInsert.xpm"
+#include "hLegendInsert.xpm"
+
+GQuark LTT_NAME_CPU;
+
+/** Array containing instanced objects. Used when module is unloaded */
+GSList *g_control_flow_data_list = NULL ;
+
+GSList *g_legend_list = NULL ;
+
+/*****************************************************************************
+ *                 Functions for module loading/unloading                    *
+ *****************************************************************************/
+/**
+ * plugin's init function
+ *
+ * This function initializes the Control Flow Viewer functionnality through the
+ * gtkTraceSet API.
+ */
+static void init() {
+
+  g_info("Resource usage viewer init()");
+
+  /* Register the toolbar insert button and menu entry*/
+  lttvwindow_register_constructor("resourceview",
+                                  "/",
+                                  "Insert Resource Viewer",
+                                  hGuiControlFlowInsert_xpm,
+                                  "Insert Resource Viewer",
+                                  h_guicontrolflow);
+  
+
+  LTT_NAME_CPU = g_quark_from_string("/cpu");
+}
+
+void destroy_walk(gpointer data, gpointer user_data)
+{
+  g_info("Walk destroy Resource Viewer");
+  guicontrolflow_destructor_full((LttvPluginCFV*)data);
+}
+
+
+/**
+ * plugin's destroy function
+ *
+ * This function releases the memory reserved by the module and unregisters
+ * everything that has been registered in the gtkTraceSet API.
+ */
+static void destroy() {
+  g_info("GUI resource viewer destroy()");
+
+  g_slist_foreach(g_control_flow_data_list, destroy_walk, NULL );
+  
+  g_slist_free(g_control_flow_data_list);
+
+  /* Unregister the toolbar insert button and menu entry */
+  lttvwindow_unregister_constructor(h_guicontrolflow);
+}
+
+
+LTTV_MODULE("resourceview", "Resource viewer", \
+    "Graphical module to view usage of resources", \
+    init, destroy, "lttvwindow")
diff --git a/ltt/branches/poly/lttv/modules/gui/resourceview/processlist.c b/ltt/branches/poly/lttv/modules/gui/resourceview/processlist.c
new file mode 100644 (file)
index 0000000..04be3d2
--- /dev/null
@@ -0,0 +1,781 @@
+/* This file is part of the Linux Trace Toolkit viewer
+ * Copyright (C) 2003-2004 Mathieu Desnoyers
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License Version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, 
+ * MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <gtk/gtk.h>
+#include <gdk/gdk.h>
+#include <glib.h>
+#include <string.h>
+#include <stdlib.h>
+#include <math.h>
+
+#include "processlist.h"
+#include "drawing.h"
+#include "drawitem.h"
+
+#define g_info(format...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, format)
+#define g_debug(format...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, format)
+
+/* Preallocated Size of the index_to_pixmap array */
+#define ALLOCATE_PROCESSES 1000
+
+/*****************************************************************************
+ *                       Methods to synchronize process list                 *
+ *****************************************************************************/
+
+
+gint process_sort_func  ( GtkTreeModel *model,
+        GtkTreeIter *it_a,
+        GtkTreeIter *it_b,
+        gpointer user_data)
+{
+  gchar *a_name;
+  gchar *a_brand;
+  guint a_pid, a_tgid, a_ppid, a_cpu;
+  gulong a_birth_s, a_birth_ns;
+  guint a_trace;
+
+  gchar *b_name;
+  gchar *b_brand;
+  guint b_pid, b_tgid, b_ppid, b_cpu;
+  gulong b_birth_s, b_birth_ns;
+  guint b_trace;
+
+  gtk_tree_model_get(model,
+           it_a,
+           PROCESS_COLUMN, &a_name,
+           BRAND_COLUMN, &a_brand,
+           PID_COLUMN, &a_pid,
+           TGID_COLUMN, &a_tgid,
+           PPID_COLUMN, &a_ppid,
+           CPU_COLUMN, &a_cpu,
+           BIRTH_S_COLUMN, &a_birth_s,
+           BIRTH_NS_COLUMN, &a_birth_ns,
+           TRACE_COLUMN, &a_trace,
+           -1);
+
+  gtk_tree_model_get(model,
+           it_b,
+           PROCESS_COLUMN, &b_name,
+           BRAND_COLUMN, &b_brand,
+           PID_COLUMN, &b_pid,
+           TGID_COLUMN, &b_tgid,
+           PPID_COLUMN, &b_ppid,
+           CPU_COLUMN, &b_cpu,
+           BIRTH_S_COLUMN, &b_birth_s,
+           BIRTH_NS_COLUMN, &b_birth_ns,
+           TRACE_COLUMN, &b_trace,
+           -1);
+
+  
+  /* Order by PID */
+  if(a_pid == 0 &&  b_pid == 0) {
+    /* If 0, order by CPU */
+    if(a_cpu > b_cpu) return 1;
+    if(a_cpu < b_cpu) return -1;
+
+  } else { /* if not 0, order by pid */
+
+    if(a_pid > b_pid) return 1;
+    if(a_pid < b_pid) return -1;
+  }
+
+  /* Order by birth second */
+
+  if(a_birth_s > b_birth_s) return 1;
+  if(a_birth_s < b_birth_s) return -1;
+  
+
+  /* Order by birth nanosecond */
+  if(a_birth_ns > b_birth_ns) return 1;
+  if(a_birth_ns < b_birth_ns) return -1;
+  
+  /* Order by trace_num */
+  if(a_trace > b_trace) return 1;
+  if(a_trace < b_trace) return -1;
+
+  return 0;
+
+}
+
+static guint process_list_hash_fct(gconstpointer key)
+{
+  guint pid = ((const ProcessInfo*)key)->pid;
+  return ((pid>>8 ^ pid>>4 ^ pid>>2 ^ pid) ^ ((const ProcessInfo*)key)->cpu);
+}
+
+/* If hash is good, should be different */
+static gboolean process_list_equ_fct(gconstpointer a, gconstpointer b)
+{
+  const ProcessInfo *pa = (const ProcessInfo*)a;
+  const ProcessInfo *pb = (const ProcessInfo*)b;
+  
+  gboolean ret = TRUE;
+
+  if(likely(pa->pid != pb->pid))
+    ret = FALSE;
+  if(likely((pa->pid == 0 && (pa->cpu != pb->cpu))))
+    ret = FALSE;
+  if(unlikely(ltt_time_compare(pa->birth, pb->birth) != 0))
+    ret = FALSE;
+  if(unlikely(pa->trace_num != pb->trace_num))
+    ret = FALSE;
+
+  return ret;
+}
+
+void destroy_hash_key(gpointer key);
+
+void destroy_hash_data(gpointer data);
+
+
+gboolean scroll_event(GtkWidget *widget, GdkEventScroll *event, gpointer data)
+{
+  ControlFlowData *control_flow_data = 
+      (ControlFlowData*)g_object_get_data(
+                G_OBJECT(widget),
+                "control_flow_data");
+  Drawing_t *drawing = control_flow_data->drawing;
+       unsigned int cell_height =
+               get_cell_height(GTK_TREE_VIEW(control_flow_data->process_list->process_list_widget));
+
+  switch(event->direction) {
+    case GDK_SCROLL_UP:
+      gtk_adjustment_set_value(control_flow_data->v_adjust,
+        gtk_adjustment_get_value(control_flow_data->v_adjust) - cell_height);
+      break;
+    case GDK_SCROLL_DOWN:
+      gtk_adjustment_set_value(control_flow_data->v_adjust,
+        gtk_adjustment_get_value(control_flow_data->v_adjust) + cell_height);
+      break;
+    default:
+      g_error("should only scroll up and down.");
+  }
+       return TRUE;
+}
+
+
+static void update_index_to_pixmap_each(ProcessInfo *key,
+                                        HashedProcessData *value,
+                                        ProcessList *process_list)
+{
+  guint array_index = processlist_get_index_from_data(process_list, value);
+  
+  g_assert(array_index < process_list->index_to_pixmap->len);
+
+  GdkPixmap **pixmap = 
+    (GdkPixmap**)&g_ptr_array_index(process_list->index_to_pixmap, array_index);
+
+  *pixmap = value->pixmap;
+}
+
+
+void update_index_to_pixmap(ProcessList *process_list)
+{
+  g_ptr_array_set_size(process_list->index_to_pixmap,
+                       g_hash_table_size(process_list->process_hash));
+  g_hash_table_foreach(process_list->process_hash, 
+                       (GHFunc)update_index_to_pixmap_each,
+                       process_list);
+}
+
+
+static void update_pixmap_size_each(ProcessInfo *key,
+                                    HashedProcessData *value,
+                                    guint width)
+{
+  GdkPixmap *old_pixmap = value->pixmap;
+
+  value->pixmap = 
+        gdk_pixmap_new(old_pixmap,
+                       width,
+                       value->height,
+                       -1);
+
+  gdk_pixmap_unref(old_pixmap);
+}
+
+
+void update_pixmap_size(ProcessList *process_list, guint width)
+{
+  g_hash_table_foreach(process_list->process_hash, 
+                       (GHFunc)update_pixmap_size_each,
+                       (gpointer)width);
+}
+
+
+typedef struct _CopyPixmap {
+  GdkDrawable *dest;
+  GdkGC *gc;
+  GdkDrawable *src;
+  gint xsrc, ysrc, xdest, ydest, width, height;
+} CopyPixmap;
+
+static void copy_pixmap_region_each(ProcessInfo *key,
+                                    HashedProcessData *value,
+                                    CopyPixmap *cp)
+{
+  GdkPixmap *src = cp->src;
+  GdkPixmap *dest = cp->dest;
+  
+  if(dest == NULL)
+    dest = value->pixmap;
+  if(src == NULL)
+    src = value->pixmap;
+
+  gdk_draw_drawable (dest,
+      cp->gc,
+      src,
+      cp->xsrc, cp->ysrc,
+      cp->xdest, cp->ydest,
+      cp->width, cp->height);
+}
+
+
+
+
+void copy_pixmap_region(ProcessList *process_list, GdkDrawable *dest,
+    GdkGC *gc, GdkDrawable *src,
+    gint xsrc, gint ysrc,
+    gint xdest, gint ydest, gint width, gint height)
+{
+  CopyPixmap cp = { dest, gc, src, xsrc, ysrc, xdest, ydest, width, height };
+  
+  g_hash_table_foreach(process_list->process_hash, 
+                       (GHFunc)copy_pixmap_region_each,
+                       &cp);
+}
+
+
+
+typedef struct _RectanglePixmap {
+  gboolean filled;
+  gint x, y, width, height;
+  GdkGC *gc;
+} RectanglePixmap;
+
+static void rectangle_pixmap_each(ProcessInfo *key,
+                                  HashedProcessData *value,
+                                  RectanglePixmap *rp)
+{
+  if(rp->height == -1)
+    rp->height = value->height;
+      
+  gdk_draw_rectangle (value->pixmap,
+      rp->gc,
+      rp->filled,
+      rp->x, rp->y,
+      rp->width, rp->height);
+}
+
+
+
+
+void rectangle_pixmap(ProcessList *process_list, GdkGC *gc,
+    gboolean filled, gint x, gint y, gint width, gint height)
+{
+  RectanglePixmap rp = { filled, x, y, width, height, gc };
+  
+  g_hash_table_foreach(process_list->process_hash, 
+                       (GHFunc)rectangle_pixmap_each,
+                       &rp);
+}
+
+
+/* Renders each pixmaps into on big drawable */
+void copy_pixmap_to_screen(ProcessList *process_list,
+    GdkDrawable *dest,
+    GdkGC *gc,
+    gint x, gint y,
+    gint width, gint height)
+{
+  if(process_list->index_to_pixmap->len == 0) return;
+  guint cell_height = process_list->cell_height;
+
+  /* Get indexes */
+  gint begin = floor(y/(double)cell_height);
+  gint end = MIN(ceil((y+height)/(double)cell_height),
+                 process_list->index_to_pixmap->len);
+  gint i;
+
+  for(i=begin; i<end; i++) {
+    g_assert(i<process_list->index_to_pixmap->len);
+    /* Render the pixmap to the screen */
+    GdkPixmap *pixmap = 
+      //(GdkPixmap*)g_ptr_array_index(process_list->index_to_pixmap, i);
+      GDK_PIXMAP(g_ptr_array_index(process_list->index_to_pixmap, i));
+
+    gdk_draw_drawable (dest,
+        gc,
+        pixmap,
+        x, 0,
+        x, i*cell_height,
+        width, cell_height);
+
+  }
+  
+  
+}
+
+
+
+
+
+
+
+
+
+ProcessList *processlist_construct(void)
+{
+  GtkTreeViewColumn *column;
+  GtkCellRenderer *renderer;
+  
+  ProcessList* process_list = g_new(ProcessList,1);
+  
+  process_list->number_of_process = 0;
+
+  process_list->current_hash_data = NULL;
+
+  /* Create the Process list */
+  process_list->list_store = gtk_list_store_new (  N_COLUMNS,
+              G_TYPE_STRING,
+              G_TYPE_STRING,
+              G_TYPE_UINT,
+              G_TYPE_UINT,
+              G_TYPE_UINT,
+              G_TYPE_UINT,
+              G_TYPE_ULONG,
+              G_TYPE_ULONG,
+              G_TYPE_UINT);
+
+
+  process_list->process_list_widget = 
+    gtk_tree_view_new_with_model
+    (GTK_TREE_MODEL (process_list->list_store));
+
+  g_object_unref (G_OBJECT (process_list->list_store));
+
+  gtk_tree_sortable_set_default_sort_func(
+      GTK_TREE_SORTABLE(process_list->list_store),
+      process_sort_func,
+      NULL,
+      NULL);
+
+  gtk_tree_sortable_set_sort_column_id(
+      GTK_TREE_SORTABLE(process_list->list_store),
+      GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
+      GTK_SORT_ASCENDING);
+
+
+  process_list->process_hash = g_hash_table_new_full(
+      process_list_hash_fct, process_list_equ_fct,
+      destroy_hash_key, destroy_hash_data
+      );
+  
+  
+  gtk_tree_view_set_headers_visible(
+    GTK_TREE_VIEW(process_list->process_list_widget), TRUE);
+
+  /* Create a column, associating the "text" attribute of the
+   * cell_renderer to the first column of the model */
+  /* Columns alignment : 0.0 : Left    0.5 : Center   1.0 : Right */
+  renderer = gtk_cell_renderer_text_new ();
+  process_list->renderer = renderer;
+
+       gint vertical_separator;
+       gtk_widget_style_get (GTK_WIDGET (process_list->process_list_widget),
+                       "vertical-separator", &vertical_separator,
+                       NULL);
+  gtk_cell_renderer_get_size(renderer,
+      GTK_WIDGET(process_list->process_list_widget),
+      NULL,
+      NULL,
+      NULL,
+      NULL,
+      &process_list->cell_height);
+       
+#if GTK_CHECK_VERSION(2,4,15)
+  guint ypad;
+  g_object_get(G_OBJECT(renderer), "ypad", &ypad, NULL);
+
+  process_list->cell_height += ypad;
+#endif
+  process_list->cell_height += vertical_separator;
+       
+
+  column = gtk_tree_view_column_new_with_attributes ( "Process",
+                renderer,
+                "text",
+                PROCESS_COLUMN,
+                NULL);
+  gtk_tree_view_column_set_alignment (column, 0.0);
+  gtk_tree_view_column_set_fixed_width (column, 45);
+  gtk_tree_view_append_column (
+    GTK_TREE_VIEW (process_list->process_list_widget), column);
+  
+  process_list->button = column->button;
+  column = gtk_tree_view_column_new_with_attributes ( "Brand",
+                renderer,
+                "text",
+                BRAND_COLUMN,
+                NULL);
+  gtk_tree_view_column_set_alignment (column, 0.0);
+  gtk_tree_view_column_set_fixed_width (column, 45);
+  gtk_tree_view_append_column (
+    GTK_TREE_VIEW (process_list->process_list_widget), column);
+
+  column = gtk_tree_view_column_new_with_attributes ( "PID",
+                renderer,
+                "text",
+                PID_COLUMN,
+                NULL);
+  gtk_tree_view_append_column (
+    GTK_TREE_VIEW (process_list->process_list_widget), column);
+
+  column = gtk_tree_view_column_new_with_attributes ( "TGID",
+                renderer,
+                "text",
+                TGID_COLUMN,
+                NULL);
+  gtk_tree_view_append_column (
+    GTK_TREE_VIEW (process_list->process_list_widget), column);
+
+  column = gtk_tree_view_column_new_with_attributes ( "PPID",
+                renderer,
+                "text",
+                PPID_COLUMN,
+                NULL);
+  gtk_tree_view_append_column (
+    GTK_TREE_VIEW (process_list->process_list_widget), column);
+  
+  column = gtk_tree_view_column_new_with_attributes ( "CPU",
+                renderer,
+                "text",
+                CPU_COLUMN,
+                NULL);
+  gtk_tree_view_append_column (
+    GTK_TREE_VIEW (process_list->process_list_widget), column);
+
+  column = gtk_tree_view_column_new_with_attributes ( "Birth sec",
+                renderer,
+                "text",
+                BIRTH_S_COLUMN,
+                NULL);
+  gtk_tree_view_append_column (
+    GTK_TREE_VIEW (process_list->process_list_widget), column);
+
+  //gtk_tree_view_column_set_visible(column, 0);
+  //
+  column = gtk_tree_view_column_new_with_attributes ( "Birth nsec",
+                renderer,
+                "text",
+                BIRTH_NS_COLUMN,
+                NULL);
+  gtk_tree_view_append_column (
+    GTK_TREE_VIEW (process_list->process_list_widget), column);
+
+  column = gtk_tree_view_column_new_with_attributes ( "TRACE",
+                renderer,
+                "text",
+                TRACE_COLUMN,
+                NULL);
+  gtk_tree_view_append_column (
+    GTK_TREE_VIEW (process_list->process_list_widget), column);
+
+
+  //gtk_tree_view_column_set_visible(column, 0);
+  
+  g_object_set_data_full(
+      G_OBJECT(process_list->process_list_widget),
+      "process_list_Data",
+      process_list,
+      (GDestroyNotify)processlist_destroy);
+
+  process_list->index_to_pixmap = g_ptr_array_sized_new(ALLOCATE_PROCESSES);
+  
+  return process_list;
+}
+
+void processlist_destroy(ProcessList *process_list)
+{
+  g_debug("processlist_destroy %p", process_list);
+  g_hash_table_destroy(process_list->process_hash);
+  process_list->process_hash = NULL;
+  g_ptr_array_free(process_list->index_to_pixmap, TRUE);
+
+  g_free(process_list);
+  g_debug("processlist_destroy end");
+}
+
+static gboolean remove_hash_item(ProcessInfo *process_info,
+                                 HashedProcessData *hashed_process_data,
+                                 ProcessList *process_list)
+{
+  GtkTreeIter iter;
+
+  iter = hashed_process_data->y_iter;
+
+  gtk_list_store_remove (process_list->list_store, &iter);
+  gdk_pixmap_unref(hashed_process_data->pixmap);
+
+  if(likely(process_list->current_hash_data != NULL)) {
+    if(likely(hashed_process_data ==
+                process_list->current_hash_data[process_info->trace_num][process_info->cpu]))
+      process_list->current_hash_data[process_info->trace_num][process_info->cpu] = NULL;
+  }
+  return TRUE; /* remove the element from the hash table */
+}
+
+void processlist_clear(ProcessList *process_list)
+{
+  g_info("processlist_clear %p", process_list);
+
+  g_hash_table_foreach_remove(process_list->process_hash,
+                              (GHRFunc)remove_hash_item,
+                              (gpointer)process_list);
+  process_list->number_of_process = 0;
+  update_index_to_pixmap(process_list);
+}
+
+
+GtkWidget *processlist_get_widget(ProcessList *process_list)
+{
+  return process_list->process_list_widget;
+}
+
+
+void destroy_hash_key(gpointer key)
+{
+  g_free(key);
+}
+
+void destroy_hash_data(gpointer data)
+{
+  g_free(data);
+}
+
+
+void processlist_set_name(ProcessList *process_list,
+    GQuark name,
+    HashedProcessData *hashed_process_data)
+{
+  gtk_list_store_set (  process_list->list_store, &hashed_process_data->y_iter,
+        PROCESS_COLUMN, g_quark_to_string(name),
+        -1);
+}
+
+void processlist_set_brand(ProcessList *process_list,
+    GQuark brand,
+    HashedProcessData *hashed_process_data)
+{
+  gtk_list_store_set (  process_list->list_store, &hashed_process_data->y_iter,
+        BRAND_COLUMN, g_quark_to_string(brand),
+        -1);
+}
+
+void processlist_set_tgid(ProcessList *process_list,
+    guint tgid,
+    HashedProcessData *hashed_process_data)
+{
+  gtk_list_store_set (  process_list->list_store, &hashed_process_data->y_iter,
+        TGID_COLUMN, tgid,
+        -1);
+}
+
+void processlist_set_ppid(ProcessList *process_list,
+    guint ppid,
+    HashedProcessData *hashed_process_data)
+{
+  gtk_list_store_set (  process_list->list_store, &hashed_process_data->y_iter,
+        PPID_COLUMN, ppid,
+        -1);
+}
+
+
+int processlist_add(  ProcessList *process_list,
+      Drawing_t *drawing,
+      guint pid,
+      guint tgid,
+      guint cpu,
+      guint ppid,
+      LttTime *birth,
+      guint trace_num,
+      GQuark name,
+      GQuark brand,
+      guint *height,
+      ProcessInfo **pm_process_info,
+      HashedProcessData **pm_hashed_process_data)
+{
+  ProcessInfo *Process_Info = g_new(ProcessInfo, 1);
+  HashedProcessData *hashed_process_data = g_new(HashedProcessData, 1);
+  *pm_hashed_process_data = hashed_process_data;
+  *pm_process_info = Process_Info;
+  Process_Info->pid = pid;
+  Process_Info->tgid = tgid;
+  if(pid == 0)
+    Process_Info->cpu = cpu;
+  else
+    Process_Info->cpu = 0;
+  Process_Info->ppid = ppid;
+  Process_Info->birth = *birth;
+  Process_Info->trace_num = trace_num;
+
+  /* When we create it from before state update, we are sure that the
+   * last event occured before the beginning of the global area.
+   *
+   * If it is created after state update, this value (0) will be
+   * overriden by the new state before anything is drawn.
+   */
+  hashed_process_data->x.over = 0;
+  hashed_process_data->x.over_used = FALSE;
+  hashed_process_data->x.over_marked = FALSE;
+  hashed_process_data->x.middle = 0;
+  hashed_process_data->x.middle_used = FALSE;
+  hashed_process_data->x.middle_marked = FALSE;
+  hashed_process_data->x.under = 0;
+  hashed_process_data->x.under_used = FALSE;
+  hashed_process_data->x.under_marked = FALSE;
+  hashed_process_data->next_good_time = ltt_time_zero;
+  /* Add a new row to the model */
+  gtk_list_store_append ( process_list->list_store,
+                          &hashed_process_data->y_iter);
+
+  gtk_list_store_set (  process_list->list_store, &hashed_process_data->y_iter,
+        PROCESS_COLUMN, g_quark_to_string(name),
+        BRAND_COLUMN, g_quark_to_string(brand),
+        PID_COLUMN, pid,
+        TGID_COLUMN, tgid,
+        PPID_COLUMN, ppid,
+        CPU_COLUMN, cpu,
+        BIRTH_S_COLUMN, birth->tv_sec,
+        BIRTH_NS_COLUMN, birth->tv_nsec,
+        TRACE_COLUMN, trace_num,
+        -1);
+  //gtk_tree_view_set_model(GTK_TREE_VIEW(process_list->process_list_widget),
+  //                        GTK_TREE_MODEL(process_list->list_store));
+  //gtk_container_resize_children(GTK_CONTAINER(process_list->process_list_widget));
+  
+  g_hash_table_insert(process_list->process_hash,
+        (gpointer)Process_Info,
+        (gpointer)hashed_process_data);
+  
+  process_list->number_of_process++;
+
+  hashed_process_data->height = process_list->cell_height;
+
+  g_assert(hashed_process_data->height != 0);
+
+  *height = hashed_process_data->height * process_list->number_of_process;
+
+  hashed_process_data->pixmap = 
+        gdk_pixmap_new(drawing->drawing_area->window,
+                       drawing->alloc_width,
+                       hashed_process_data->height,
+                       -1);
+  
+  // Clear the image
+  gdk_draw_rectangle (hashed_process_data->pixmap,
+        drawing->drawing_area->style->black_gc,
+        TRUE,
+        0, 0,
+        drawing->alloc_width,
+        hashed_process_data->height);
+
+  update_index_to_pixmap(process_list);
+
+
+  return 0;
+}
+
+int processlist_remove( ProcessList *process_list,
+      guint pid,
+      guint cpu,
+      LttTime *birth,
+      guint trace_num)
+{
+  ProcessInfo process_info;
+  HashedProcessData *hashed_process_data;
+  GtkTreeIter iter;
+  
+  process_info.pid = pid;
+  if(pid == 0)
+    process_info.cpu = cpu;
+  else
+    process_info.cpu = 0;
+  process_info.birth = *birth;
+  process_info.trace_num = trace_num;
+
+
+  hashed_process_data = 
+    (HashedProcessData*)g_hash_table_lookup(
+          process_list->process_hash,
+          &process_info);
+  if(likely(hashed_process_data != NULL))
+  {
+    iter = hashed_process_data->y_iter;
+
+    gtk_list_store_remove (process_list->list_store, &iter);
+    
+    g_hash_table_remove(process_list->process_hash,
+        &process_info);
+
+    if(likely(process_list->current_hash_data != NULL)) {
+      if(likely(hashed_process_data == process_list->current_hash_data[trace_num][cpu])) {
+        process_list->current_hash_data[trace_num][cpu] = NULL;
+      }
+    }
+    
+    gdk_pixmap_unref(hashed_process_data->pixmap);
+    
+    update_index_to_pixmap(process_list);
+
+    process_list->number_of_process--;
+
+    return 0; 
+  } else {
+    return 1;
+  }
+}
+
+
+#if 0
+static inline guint get_cpu_number_from_name(GQuark name)
+{
+  const gchar *string;
+  char *begin;
+  guint cpu;
+
+  string = g_quark_to_string(name);
+
+  begin = strrchr(string, '/');
+  begin++;
+
+  g_assert(begin != '\0');
+
+  cpu = strtoul(begin, NULL, 10);
+
+  return cpu;
+}
+#endif //0
diff --git a/ltt/branches/poly/lttv/modules/gui/resourceview/processlist.h b/ltt/branches/poly/lttv/modules/gui/resourceview/processlist.h
new file mode 100644 (file)
index 0000000..d948460
--- /dev/null
@@ -0,0 +1,271 @@
+/* This file is part of the Linux Trace Toolkit viewer
+ * Copyright (C) 2003-2004 Mathieu Desnoyers
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License Version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, 
+ * MA 02111-1307, USA.
+ */
+
+
+
+#ifndef _PROCESS_LIST_H
+#define _PROCESS_LIST_H
+
+#include <gtk/gtk.h>
+#include <gdk/gdk.h>
+#include <lttv/state.h>
+#include <ltt/ltt.h>
+
+#include "drawitem.h"
+
+/* The process list
+ *
+ * Tasks :
+ * Create a process list
+ * contains the data for the process list
+ * tells the height of the process list widget
+ * provides methods to add/remove process from the list
+ *  note : the sync with drawing is left to the caller.
+ * provides helper function to convert a process unique identifier to
+ *  pixels (in height).
+ *
+ */
+
+
+/* Enumeration of the columns */
+enum
+{
+  PROCESS_COLUMN,
+  BRAND_COLUMN,
+  PID_COLUMN,
+  TGID_COLUMN,
+  PPID_COLUMN,
+  CPU_COLUMN,
+  BIRTH_S_COLUMN,
+  BIRTH_NS_COLUMN,
+  TRACE_COLUMN,
+  N_COLUMNS
+};
+
+
+typedef struct _ProcessInfo {
+  
+  guint pid;
+  guint tgid;
+  guint cpu;
+  guint ppid;
+  LttTime birth;
+  guint trace_num;
+
+ // gint height_cache;
+
+} ProcessInfo;
+
+typedef struct _HashedProcessData {
+  GdkPixmap *pixmap;  // Pixmap slice containing drawing buffer for the PID
+  gint height; // height of the pixmap
+  GtkTreeIter y_iter; // Access quickly to y pos.
+ // DrawContext *draw_context;
+  /* Information on current drawing */
+  struct {
+    guint over;
+    gboolean over_used;    /* inform the user that information is incomplete */
+    gboolean over_marked;  /* inform the user that information is incomplete */
+    guint middle;
+    gboolean middle_used;  /* inform the user that information is incomplete */
+    gboolean middle_marked;/* inform the user that information is incomplete */
+    guint under;
+    gboolean under_used;   /* inform the user that information is incomplete */
+    gboolean under_marked; /* inform the user that information is incomplete */
+  } x; /* last x position saved by after state update */
+
+  LttTime next_good_time; /* precalculate the next time where the next
+                             pixel is.*/
+
+} HashedProcessData;
+  
+struct _ProcessList {
+  
+  GtkWidget *process_list_widget;
+  GtkListStore *list_store;
+  GtkWidget *button; /* one button of the tree view */
+  GtkCellRenderer *renderer;
+
+  /* A hash table by PID to speed up process position find in the list */
+  GHashTable *process_hash;
+  
+  guint number_of_process;
+  gint cell_height;
+
+  /* Current process pointer, one per cpu, one per trace */
+  HashedProcessData ***current_hash_data;
+
+  /* Array containing index -> pixmap correspondance. Must be updated
+   * every time the process list is reordered, process added or removed */
+  GPtrArray * index_to_pixmap;
+
+};
+
+
+typedef struct _ProcessList ProcessList;
+
+
+#ifndef TYPE_DRAWING_T_DEFINED
+#define TYPE_DRAWING_T_DEFINED
+typedef struct _Drawing_t Drawing_t;
+#endif //TYPE_DRAWING_T_DEFINED
+
+ProcessList *processlist_construct(void);
+void processlist_destroy(ProcessList *process_list);
+GtkWidget *processlist_get_widget(ProcessList *process_list);
+
+void processlist_clear(ProcessList *process_list);
+
+// out : success (0) and height
+/* CPU num is only used for PID 0 */
+int processlist_add(ProcessList *process_list, Drawing_t * drawing, 
+    guint pid, guint tgid, guint cpu, guint ppid,
+    LttTime *birth, guint trace_num, GQuark name, GQuark brand, guint *height,
+    ProcessInfo **process_info,
+    HashedProcessData **hashed_process_data);
+// out : success (0) and height
+int processlist_remove(ProcessList *process_list, guint pid, guint cpu, 
+    LttTime *birth, guint trace_num);
+
+/* Set the name of a process */
+void processlist_set_name(ProcessList *process_list,
+    GQuark name,
+    HashedProcessData *hashed_process_data);
+
+void processlist_set_brand(ProcessList *process_list,
+    GQuark brand,
+    HashedProcessData *hashed_process_data);
+
+/* Set the ppid of a process */
+void processlist_set_tgid(ProcessList *process_list,
+    guint tgid,
+    HashedProcessData *hashed_process_data);
+void processlist_set_ppid(ProcessList *process_list,
+    guint ppid,
+    HashedProcessData *hashed_process_data);
+
+
+/* Synchronize the list at the left and the drawing */
+void update_index_to_pixmap(ProcessList *process_list);
+
+/* Update the width of each pixmap buffer for each process */
+void update_pixmap_size(ProcessList *process_list, guint width);
+
+
+/* Put src and/or dest to NULL to copy from/to the each PID specific pixmap */
+void copy_pixmap_region(ProcessList *process_list, GdkDrawable *dest,
+    GdkGC *gc, GdkDrawable *src,
+    gint xsrc, gint ysrc,
+    gint xdest, gint ydest, gint width, gint height);
+
+/* If height is -1, the height of each pixmap is used */
+void rectangle_pixmap(ProcessList *process_list, GdkGC *gc,
+    gboolean filled, gint x, gint y, gint width, gint height);
+
+/* Renders each pixmaps into on big drawable */
+void copy_pixmap_to_screen(ProcessList *process_list,
+    GdkDrawable *dest,
+    GdkGC *gc,
+    gint x, gint y,
+    gint width, gint height);
+
+
+static inline gint get_cell_height(GtkTreeView *TreeView)
+{
+  gint height;
+  GtkTreeViewColumn *column = gtk_tree_view_get_column(TreeView, 0);
+  
+  gtk_tree_view_column_cell_get_size(column, NULL, NULL, NULL, NULL, &height);
+
+  gint vertical_separator;
+  gtk_widget_style_get (GTK_WIDGET (TreeView),
+      "vertical-separator", &vertical_separator,
+      NULL);
+  height += vertical_separator;
+
+  return height;
+}
+
+static inline guint processlist_get_height(ProcessList *process_list)
+{
+  return process_list->cell_height * process_list->number_of_process ;
+}
+
+
+static inline HashedProcessData *processlist_get_process_data( 
+          ProcessList *process_list,
+          guint pid, guint cpu, LttTime *birth, guint trace_num)
+{
+  ProcessInfo process_info;
+
+  process_info.pid = pid;
+  if(pid == 0)
+    process_info.cpu = cpu;
+  else
+    process_info.cpu = ANY_CPU;
+  process_info.birth = *birth;
+  process_info.trace_num = trace_num;
+
+  return  (HashedProcessData*)g_hash_table_lookup(
+                process_list->process_hash,
+                &process_info);
+}
+
+
+static inline gint processlist_get_pixels_from_data(  ProcessList *process_list,
+          HashedProcessData *hashed_process_data,
+          guint *y,
+          guint *height)
+{
+  gint *path_indices;
+  GtkTreePath *tree_path;
+
+  tree_path = gtk_tree_model_get_path((GtkTreeModel*)process_list->list_store,
+                    &hashed_process_data->y_iter);
+  path_indices =  gtk_tree_path_get_indices (tree_path);
+
+  *height = get_cell_height((GtkTreeView*)process_list->process_list_widget);
+  *y = *height * path_indices[0];
+  gtk_tree_path_free(tree_path);
+
+  return 0; 
+
+}
+
+static inline guint processlist_get_index_from_data(ProcessList *process_list,
+          HashedProcessData *hashed_process_data)
+{
+  gint *path_indices;
+  GtkTreePath *tree_path;
+  guint ret;
+
+  tree_path = gtk_tree_model_get_path((GtkTreeModel*)process_list->list_store,
+                    &hashed_process_data->y_iter);
+  path_indices =  gtk_tree_path_get_indices (tree_path);
+
+  ret = path_indices[0];
+
+  gtk_tree_path_free(tree_path);
+
+  return ret;
+}
+
+
+
+#endif // _PROCESS_LIST_H
diff --git a/ltt/branches/poly/lttv/modules/gui/resourceview/test.c b/ltt/branches/poly/lttv/modules/gui/resourceview/test.c
new file mode 100644 (file)
index 0000000..8a71a52
--- /dev/null
@@ -0,0 +1,578 @@
+/* This file is part of the Linux Trace Toolkit viewer
+ * Copyright (C) 2003-2004 Mathieu Desnoyers
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License Version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, 
+ * MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+static void destroy_cb( GtkWidget *widget,
+                                       gpointer   data )
+{ 
+           gtk_main_quit ();
+}
+
+
+
+int main(int argc, char **argv)
+{
+       GtkWidget *Window;
+       GtkWidget *CF_Viewer;
+       GtkWidget *VBox_V;
+       GtkWidget *HScroll_VC;
+       ControlFlowData *control_flow_data;
+       guint ev_sel = 444 ;
+       /* Horizontal scrollbar and it's adjustment */
+       GtkWidget *VScroll_VC;
+  GtkAdjustment *v_adjust ;
+       
+       /* Initialize i18n support */
+  gtk_set_locale ();
+
+  /* Initialize the widget set */
+  gtk_init (&argc, &argv);
+
+       init();
+
+  Window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+       gtk_window_set_title (GTK_WINDOW (Window), ("Test Window"));
+       
+       g_signal_connect (G_OBJECT (Window), "destroy",
+                       G_CALLBACK (destroy_cb), NULL);
+
+
+  VBox_V = gtk_vbox_new(0, 0);
+       gtk_container_add (GTK_CONTAINER (Window), VBox_V);
+
+  //ListViewer = hGuiEvents(Window);
+  //gtk_box_pack_start(GTK_BOX(VBox_V), ListViewer, TRUE, TRUE, 0);
+
+  //ListViewer = hGuiEvents(Window);
+  //gtk_box_pack_start(GTK_BOX(VBox_V), ListViewer, FALSE, TRUE, 0);
+       
+       control_flow_data = guicontrolflow();
+       CF_Viewer = control_flow_data->scrolled_window;
+  gtk_box_pack_start(GTK_BOX(VBox_V), CF_Viewer, TRUE, TRUE, 0);
+
+  /* Create horizontal scrollbar and pack it */
+  HScroll_VC = gtk_hscrollbar_new(NULL);
+  gtk_box_pack_start(GTK_BOX(VBox_V), HScroll_VC, FALSE, TRUE, 0);
+       
+       
+  gtk_widget_show (HScroll_VC);
+  gtk_widget_show (VBox_V);
+       gtk_widget_show (Window);
+
+       //Event_Selected_Hook(control_flow_data, &ev_sel);
+       
+       gtk_main ();
+
+       g_critical("main loop finished");
+  
+       //h_guievents_destructor(ListViewer);
+
+       //g_critical("GuiEvents Destructor finished");
+       destroy();
+       
+       return 0;
+}
+
+
+
+void add_test_process(ControlFlowData *control_flow_data)
+{
+       GtkTreeIter iter;
+       int i;
+       gchar *process[] = { "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten" };
+
+       for(i=0; i<control_flow_data->number_of_process; i++)
+       {
+         /* Add a new row to the model */
+               gtk_list_store_append (control_flow_data->list_store, &iter);
+               gtk_list_store_set (    control_flow_data->list_store, &iter,
+                                       PROCESS_COLUMN, process[i],
+                                       -1);
+       }
+                                                       
+}
+       
+
+
+
+
+
+void test_draw(ControlFlowData *control_flow_data)
+{
+       /* Draw event states using available height, Number of process, cell height
+        * (don't forget to remove two pixels at beginning and end).
+        * For horizontal : use width, Time_Begin, Time_End.
+        * This function calls the reading library to get the draw_hook called 
+        * for the desired period of time. */
+       
+       drawingAreaInfo *drawing_Area_Info = &control_flow_data->drawing_Area_Info;
+
+       
+}
+
+#ifdef DEBUG
+void test_draw() {
+       gint cell_height = get_cell_height(GTK_TREE_VIEW(control_flow_data->process_list_widget));
+       GdkGC *GC = gdk_gc_new(widget->window);
+       GdkColor color = CF_Colors[GREEN];
+       
+       gdk_color_alloc (gdk_colormap_get_system () , &color);
+       
+       g_critical("expose");
+
+       /* When redrawing, use widget->allocation.width to get the width of
+        * drawable area. */
+       control_flow_data->drawing_Area_Info.width = widget->allocation.width;
+       
+       test_draw(control_flow_data);
+       
+       gdk_gc_copy(GC,widget->style->black_gc);
+       gdk_gc_set_foreground(GC,&color);
+       
+       //gdk_draw_arc (widget->window,
+  //              widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
+  //              TRUE,
+  //              //0, 0, widget->allocation.width, widget->allocation.height,
+  //              0, 0, widget->allocation.width,
+       //                                                      control_flow_data->drawing_Area_Info.height,
+  //              0, 64 * 360);
+
+       
+       //drawing_Area_Init(control_flow_data);
+       
+       // 2 pixels for the box around the drawing area, 1 pixel for off-by-one
+       // (starting from 0)
+       //gdk_gc_copy (&GC, widget->style->fg_gc[GTK_WIDGET_STATE (widget)]);
+
+       gdk_gc_set_line_attributes(GC,12, GDK_LINE_SOLID, GDK_CAP_NOT_LAST,GDK_JOIN_MITER);
+       
+       gdk_draw_line (widget->window,
+                 GC,
+                                                                0, (cell_height-1)/2,
+                                                                widget->allocation.width, (cell_height-1)/2);
+
+       color = CF_Colors[BLUE];
+       
+       gdk_color_alloc (gdk_colormap_get_system () , &color);
+       
+       gdk_gc_set_foreground(GC,&color);
+
+
+               gdk_gc_set_line_attributes(GC,3, GDK_LINE_SOLID, GDK_CAP_NOT_LAST,GDK_JOIN_MITER);
+       
+       gdk_draw_line (widget->window,
+                 GC,
+                                                                0, (cell_height-1)/2,
+                                                                widget->allocation.width,(cell_height-1)/2);
+       
+
+
+
+
+
+       g_object_unref(GC);
+       
+       //gdk_colormap_alloc_colors(gdk_colormap_get_system(), TRUE, 
+               
+       //gdk_gc_set_line_attributes(GC,5, GDK_LINE_SOLID, GDK_CAP_NOT_LAST,GDK_JOIN_MITER);
+       //gdk_gc_set_foreground(GC, 
+
+       //gdk_draw_line (widget->window,
+  //               GC,
+       //                                                       0, (2*cell_height)-2-1,
+       //                                                       50, (2*cell_height)-2-1);
+
+}
+#endif //DEBUG
+
+
+/* Event_Hook.c tests */
+
+void test_draw_item(Drawing_t *drawing,
+                       GdkPixmap *pixmap) 
+{
+       PropertiesIcon properties_icon;
+       DrawContext draw_context;
+       
+       DrawInfo current, previous;
+       ItemInfo over, middle, under, modify_over, modify_middle, modify_under;
+
+       int i=0,j=0;
+       
+       //for(i=0; i<1024;i=i+15)
+       {
+       //      for(j=0;j<768;j=j+15)
+               {
+                       over.x = i;
+                       over.y = j;
+
+                       current.modify_over = &over;
+       
+                       draw_context.drawable = pixmap;
+                       draw_context.gc = drawing->drawing_area->style->black_gc;
+
+                       draw_context.current = &current;
+                       draw_context.previous = NULL;
+       
+                       properties_icon.icon_name = g_new(char, MAX_PATH_LEN);
+                       strncpy(properties_icon.icon_name, 
+                               "/home/compudj/local/share/LinuxTraceToolkit/pixmaps/mini-display.xpm",
+                               MAX_PATH_LEN);
+                       properties_icon.width = -1;
+                       properties_icon.height = -1;
+                       properties_icon.position = OVER;
+                       draw_icon(&properties_icon, &draw_context);
+                       g_free(properties_icon.icon_name);
+               }
+       }
+
+}
+
+#ifdef NOTUSE
+/* NOTE : no drawing data should be sent there, since the drawing widget
+ * has not been initialized */
+void send_test_drawing(ProcessList *process_list,
+                       Drawing_t *drawing,
+                       GdkPixmap *pixmap,
+                       gint x, gint y, // y not used here?
+                 gint width,
+                       gint height) // height won't be used here ?
+{
+       int i,j;
+       ProcessInfo Process_Info = {10000, 12000, 55600};
+       //ProcessInfo Process_Info = {156, 14000, 55500};
+       GtkTreeRowReference *row_ref;
+       PangoContext *context;
+       PangoLayout *layout;
+       PangoFontDescription *FontDesc;// = pango_font_description_new();
+       gint Font_Size;
+
+       //icon
+       //GdkBitmap *mask = g_new(GdkBitmap, 1);
+       //GdkPixmap *icon_pixmap = g_new(GdkPixmap, 1);
+       GdkGC * gc;
+       // rectangle
+       GdkColor color = { 0, 0xffff, 0x0000, 0x0000 };
+       
+       gc = gdk_gc_new(pixmap);
+       /* Sent text data */
+       layout = gtk_widget_create_pango_layout(drawing->drawing_area,
+                       NULL);
+       context = pango_layout_get_context(layout);
+       FontDesc = pango_context_get_font_description(context);
+       Font_Size = pango_font_description_get_size(FontDesc);
+       pango_font_description_set_size(FontDesc, Font_Size-3*PANGO_SCALE);
+       
+       
+
+
+       LttTime birth;
+       birth.tv_sec = 12000;
+       birth.tv_nsec = 55500;
+       g_info("we have : x : %u, y : %u, width : %u, height : %u", x, y, width, height);
+       processlist_get_process_pixels(process_list,
+                                       1,
+                                       &birth,
+                                       &y,
+                                       &height);
+       
+       g_info("we draw : x : %u, y : %u, width : %u, height : %u", x, y, width, height);
+       drawing_draw_line(
+               drawing, pixmap, x,
+               y+(height/2), x + width, y+(height/2),
+               drawing->drawing_area->style->black_gc);
+
+       pango_layout_set_text(layout, "Test", -1);
+       gdk_draw_layout(pixmap, drawing->drawing_area->style->black_gc,
+                       0, y+height, layout);
+
+       birth.tv_sec = 14000;
+       birth.tv_nsec = 55500;
+
+       processlist_get_process_pixels(process_list,
+                                       156,
+                                       &birth,
+                                       &y,
+                                       &height);
+       
+
+       drawing_draw_line(
+               drawing, pixmap, x,
+               y+(height/2), x + width, y+(height/2),
+               drawing->drawing_area->style->black_gc);
+
+       g_info("y : %u, height : %u", y, height);
+
+       
+
+       birth.tv_sec = 12000;
+       birth.tv_nsec = 55700;
+
+       processlist_get_process_pixels(process_list,
+                                       10,
+                                       &birth,
+                                       &y,
+                                       &height);
+
+       /* Draw rectangle (background color) */
+       gdk_gc_copy(gc, drawing->drawing_area->style->black_gc);
+       gdk_gc_set_rgb_fg_color(gc, &color);
+       gdk_draw_rectangle(pixmap, gc,
+                                       TRUE,
+                                       x, y, width, height);
+
+       drawing_draw_line(
+               drawing, pixmap, x,
+               y+(height/2), x + width, y+(height/2),
+               drawing->drawing_area->style->black_gc);
+
+       
+       /* Draw arc */
+       gdk_draw_arc(pixmap, drawing->drawing_area->style->black_gc,
+                                                       TRUE, 100, y, height/2, height/2, 0, 360*64);
+
+       g_info("y : %u, height : %u", y, height);
+
+       for(i=0; i<10; i++)
+       {
+               birth.tv_sec = i*12000;
+               birth.tv_nsec = i*55700;
+
+               processlist_get_process_pixels(process_list,
+                                               i,
+                                               &birth,
+                                               &y,
+                                               &height);
+               
+
+               drawing_draw_line(
+                       drawing, pixmap, x,
+                       y+(height/2), x + width, y+(height/2),
+                       drawing->drawing_area->style->black_gc);
+
+               g_critical("y : %u, height : %u", y, height);
+
+       }
+
+       birth.tv_sec = 12000;
+       birth.tv_nsec = 55600;
+
+       processlist_get_process_pixels(process_list,
+                                       10,
+                                       &birth,
+                                       &y,
+                                       &height);
+       
+
+       drawing_draw_line(
+               drawing, pixmap, x,
+               y+(height/2), x + width, y+(height/2),
+               drawing->drawing_area->style->black_gc);
+
+       g_info("y : %u, height : %u", y, height);
+       
+
+       /* IMPORTANT : This action uses the cpu heavily! */
+       //icon_pixmap = gdk_pixmap_create_from_xpm(pixmap, &mask, NULL,
+//                             "/home/compudj/local/share/LinuxTraceToolkit/pixmaps/move_message.xpm");
+       //                              "/home/compudj/local/share/LinuxTraceToolkit/pixmaps/mini-display.xpm");
+
+       //              gdk_gc_set_clip_mask(drawing->drawing_area->style->black_gc, mask);
+
+//     for(i=x;i<x+width;i=i+15)
+//     {
+//             for(j=0;j<height*20;j=j+15)
+//             {
+                       
+                       /* Draw icon */
+                       //gdk_gc_copy(gc, drawing->drawing_area->style->black_gc);
+//                     gdk_gc_set_clip_origin(drawing->drawing_area->style->black_gc, i, j);
+//                     gdk_draw_drawable(pixmap, 
+//                                     drawing->drawing_area->style->black_gc,
+//                                     icon_pixmap,
+//                                     0, 0, i, j, -1, -1);
+
+//             }
+//     }
+
+       test_draw_item(drawing,pixmap);
+       
+       //gdk_gc_set_clip_origin(drawing->drawing_area->style->black_gc, 0, 0);
+       //gdk_gc_set_clip_mask(drawing->drawing_area->style->black_gc, NULL);
+
+       //g_free(icon_pixmap);
+       //g_free(mask);
+
+
+
+
+
+
+       pango_font_description_set_size(FontDesc, Font_Size);
+       g_object_unref(layout);
+       g_free(gc);
+}
+
+void send_test_process(ProcessList *process_list, Drawing_t *drawing)
+{
+       guint height, y;
+       int i;
+       ProcessInfo Process_Info = {10000, 12000, 55600};
+       //ProcessInfo Process_Info = {156, 14000, 55500};
+       GtkTreeRowReference *row_ref;
+
+       LttTime birth;
+
+       if(process_list->Test_Process_Sent) return;
+
+       birth.tv_sec = 12000;
+       birth.tv_nsec = 55500;
+
+       processlist_add(process_list,
+                       1,
+                       &birth,
+                       &y);
+       processlist_get_process_pixels(process_list,
+                                       1,
+                                       &birth,
+                                       &y,
+                                       &height);
+       drawing_insert_square( drawing, y, height);
+       
+       //g_critical("y : %u, height : %u", y, height);
+       
+       birth.tv_sec = 14000;
+       birth.tv_nsec = 55500;
+
+       processlist_add(process_list,
+                       156,
+                       &birth,
+                       &y);
+       processlist_get_process_pixels(process_list,
+                                       156,
+                                       &birth,
+                                       &y,
+                                       &height);
+       drawing_insert_square( drawing, y, height);
+       
+       //g_critical("y : %u, height : %u", y, height);
+       
+       birth.tv_sec = 12000;
+       birth.tv_nsec = 55700;
+
+       processlist_add(process_list,
+                       10,
+                       &birth,
+                       &height);
+       processlist_get_process_pixels(process_list,
+                                       10,
+                                       &birth,
+                                       &y,
+                                       &height);
+       drawing_insert_square( drawing, y, height);
+       
+       //g_critical("y : %u, height : %u", y, height);
+       
+       //drawing_insert_square( drawing, height, 5);
+
+       for(i=0; i<10; i++)
+       {
+               birth.tv_sec = i*12000;
+               birth.tv_nsec = i*55700;
+
+               processlist_add(process_list,
+                               i,
+                               &birth,
+                               &height);
+               processlist_get_process_pixels(process_list,
+                                               i,
+                                               &birth,
+                                               &y,
+                                               &height);
+               drawing_insert_square( drawing, y, height);
+       
+       //      g_critical("y : %u, height : %u", y, height);
+       
+       }
+       //g_critical("height : %u", height);
+
+       birth.tv_sec = 12000;
+       birth.tv_nsec = 55600;
+
+       processlist_add(process_list,
+                       10,
+                       &birth,
+                       &y);
+       processlist_get_process_pixels(process_list,
+                                       10,
+                                       &birth,
+                                       &y,
+                                       &height);
+       drawing_insert_square( drawing, y, height);
+       
+       //g_critical("y : %u, height : %u", y, height);
+       
+       processlist_add(process_list,
+                       10000,
+                       &birth,
+                       &height);
+       processlist_get_process_pixels(process_list,
+                                       10000,
+                                       &birth,
+                                       &y,
+                                       &height);
+       drawing_insert_square( drawing, y, height);
+       
+       //g_critical("y : %u, height : %u", y, height);
+       
+       //drawing_insert_square( drawing, height, 5);
+       //g_critical("height : %u", height);
+
+
+       processlist_get_process_pixels(process_list,
+                               10000,
+                               &birth,
+                               &y, &height);
+       processlist_remove(     process_list,
+                               10000,
+                               &birth);
+
+       drawing_remove_square( drawing, y, height);
+       
+       if(row_ref = 
+               (GtkTreeRowReference*)g_hash_table_lookup(
+                                       process_list->process_hash,
+                                       &Process_Info))
+       {
+               g_critical("key found");
+               g_critical("position in the list : %s",
+                       gtk_tree_path_to_string (
+                       gtk_tree_row_reference_get_path(
+                               (GtkTreeRowReference*)row_ref)
+                       ));
+               
+       }
+
+       process_list->Test_Process_Sent = TRUE;
+
+}
+#endif//NOTUSE
+
This page took 0.099034 seconds and 4 git commands to generate.