From 1684ba2ed5c10d89356e2fb8122a8b3eeeb9e0af Mon Sep 17 00:00:00 2001 From: compudj Date: Fri, 17 Mar 2006 17:59:20 +0000 Subject: [PATCH] Add Histogram git-svn-id: http://ltt.polymtl.ca/svn@1710 04897980-b3bd-0310-b5e0-8ef037075253 --- ltt/branches/poly/configure.in | 3 +- .../poly/lttv/modules/gui/Makefile.am | 2 +- .../lttv/modules/gui/histogram/Makefile.am | 42 + .../gui/histogram/hHistogramInsert.xpm | 35 + .../modules/gui/histogram/histobuttonwidget.c | 246 ++++ .../modules/gui/histogram/histobuttonwidget.h | 80 + .../lttv/modules/gui/histogram/histocfv.c | 242 +++ .../lttv/modules/gui/histogram/histocfv.h | 94 ++ .../lttv/modules/gui/histogram/histodrawing.c | 1291 +++++++++++++++++ .../lttv/modules/gui/histogram/histodrawing.h | 224 +++ .../modules/gui/histogram/histodrawitem.c | 464 ++++++ .../modules/gui/histogram/histodrawitem.h | 279 ++++ .../modules/gui/histogram/histoeventhooks.c | 1135 +++++++++++++++ .../modules/gui/histogram/histoeventhooks.h | 128 ++ .../lttv/modules/gui/histogram/histomodule.c | 93 ++ .../gui/histogram/stock_zoom_fit_24.xpm | 216 +++ .../gui/histogram/stock_zoom_in_24.xpm | 169 +++ .../gui/histogram/stock_zoom_out_24.xpm | 207 +++ 18 files changed, 4948 insertions(+), 2 deletions(-) create mode 100644 ltt/branches/poly/lttv/modules/gui/histogram/Makefile.am create mode 100644 ltt/branches/poly/lttv/modules/gui/histogram/hHistogramInsert.xpm create mode 100644 ltt/branches/poly/lttv/modules/gui/histogram/histobuttonwidget.c create mode 100644 ltt/branches/poly/lttv/modules/gui/histogram/histobuttonwidget.h create mode 100644 ltt/branches/poly/lttv/modules/gui/histogram/histocfv.c create mode 100644 ltt/branches/poly/lttv/modules/gui/histogram/histocfv.h create mode 100644 ltt/branches/poly/lttv/modules/gui/histogram/histodrawing.c create mode 100644 ltt/branches/poly/lttv/modules/gui/histogram/histodrawing.h create mode 100644 ltt/branches/poly/lttv/modules/gui/histogram/histodrawitem.c create mode 100644 ltt/branches/poly/lttv/modules/gui/histogram/histodrawitem.h create mode 100644 ltt/branches/poly/lttv/modules/gui/histogram/histoeventhooks.c create mode 100644 ltt/branches/poly/lttv/modules/gui/histogram/histoeventhooks.h create mode 100644 ltt/branches/poly/lttv/modules/gui/histogram/histomodule.c create mode 100644 ltt/branches/poly/lttv/modules/gui/histogram/stock_zoom_fit_24.xpm create mode 100644 ltt/branches/poly/lttv/modules/gui/histogram/stock_zoom_in_24.xpm create mode 100644 ltt/branches/poly/lttv/modules/gui/histogram/stock_zoom_out_24.xpm diff --git a/ltt/branches/poly/configure.in b/ltt/branches/poly/configure.in index 4c8d0557..b25407a5 100644 --- a/ltt/branches/poly/configure.in +++ b/ltt/branches/poly/configure.in @@ -23,7 +23,7 @@ AC_PREREQ(2.57) AC_INIT(FULL-PACKAGE-NAME, VERSION, BUG-REPORT-ADDRESS) #AC_WITH_LTDL # not needed ? -AM_INIT_AUTOMAKE(LinuxTraceToolkitViewer,0.8.33-12032006) +AM_INIT_AUTOMAKE(LinuxTraceToolkitViewer,0.8.34-17032006) AM_CONFIG_HEADER(config.h) AM_PROG_LIBTOOL @@ -125,6 +125,7 @@ AC_CONFIG_FILES([Makefile lttv/modules/gui/controlflow/Makefile lttv/modules/gui/detailedevents/Makefile lttv/modules/gui/statistics/Makefile + lttv/modules/gui/histogram/Makefile lttv/modules/gui/filter/Makefile lttv/modules/gui/tracecontrol/Makefile ltt/Makefile diff --git a/ltt/branches/poly/lttv/modules/gui/Makefile.am b/ltt/branches/poly/lttv/modules/gui/Makefile.am index ee483f4b..82efa567 100644 --- a/ltt/branches/poly/lttv/modules/gui/Makefile.am +++ b/ltt/branches/poly/lttv/modules/gui/Makefile.am @@ -6,7 +6,7 @@ # WARNING : subdirs order is important : mainWin depends on API -SUBDIRS = lttvwindow controlflow detailedevents statistics filter tracecontrol interrupts diskperformance +SUBDIRS = lttvwindow controlflow detailedevents statistics filter tracecontrol interrupts diskperformance histogram diff --git a/ltt/branches/poly/lttv/modules/gui/histogram/Makefile.am b/ltt/branches/poly/lttv/modules/gui/histogram/Makefile.am new file mode 100644 index 00000000..69045fdc --- /dev/null +++ b/ltt/branches/poly/lttv/modules/gui/histogram/Makefile.am @@ -0,0 +1,42 @@ +# 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 May 6, 2003 +# + +AM_CFLAGS = $(GLIB_CFLAGS) +AM_CFLAGS += $(GTK_CFLAGS) +LIBS += $(GLIB_LIBS) +LIBS += $(GTK_LIBS) -L${top_srcdir}/lttv/modules/gui/lttvwindow/lttvwindow -llttvwindow + +libdir = ${lttvplugindir} + +lib_LTLIBRARIES = libguihistogram.la +libguihistogram_la_LDFLAGS = -module +libguihistogram_la_SOURCES = histomodule.c histoeventhooks.c histocfv.c \ + histobuttonwidget.c histodrawing.c histodrawitem.c + +noinst_HEADERS = histoeventhooks.h histocfv.h \ + histobuttonwidget.h histodrawing.h histodrawitem.h + +EXTRA_DIST = \ + hHistogramInsert.xpm stock_zoom_in_24.xpm stock_zoom_out_24.xpm \ stock_zoom_fit_24.xpm diff --git a/ltt/branches/poly/lttv/modules/gui/histogram/hHistogramInsert.xpm b/ltt/branches/poly/lttv/modules/gui/histogram/hHistogramInsert.xpm new file mode 100644 index 00000000..ba18fed1 --- /dev/null +++ b/ltt/branches/poly/lttv/modules/gui/histogram/hHistogramInsert.xpm @@ -0,0 +1,35 @@ +/* XPM */ +static char *hHistogramInsert_xpm[]={ +"22 22 10 1", +"b c None", +". c None", +"f c #0000c0", +"e c #0000ff", +"g c #004000", +"d c #008080", +"a c #00ff00", +"c c #800000", +"# c #808000", +"h c #ffff00", +"......................", +"####aaaaaaaaaaaaaaaaaa", +".....bbbbbb####b......", +"...ccccbbbccccb#b#..##", +"....cc.bbbbcc.b.#.#.#.", +"....cc..bbbcc..ddd.#..", +"....cc..bbbcc.dd.dd...", +"....cc..bbbcc.d...d...", +"....cc..bbbcceeee.dfff", +"....ccccccccc.d...d...", +"....cc..bbbccd....dd..", +"....cc..bbbcc...eeee..", +"....cc..bbbcc......dd.", +"...#cc#####cc.......dd", +"....cc.bbbbcc..bbbbb..", +"...cccc.bbcccc.bbbbb..", +"....bbggbbbbb.ggbbbb..", +"hhhh.ghhghbbbghhghbbhh", +"g.bbbgbbgbbbbgbbg..b..", +"gbbbbgbbgbbbbgbbg..bbg", +".gbhhhhbbghhghb..ghhgb", +"bbgg...b..gg......gg.."}; diff --git a/ltt/branches/poly/lttv/modules/gui/histogram/histobuttonwidget.c b/ltt/branches/poly/lttv/modules/gui/histogram/histobuttonwidget.c new file mode 100644 index 00000000..279be946 --- /dev/null +++ b/ltt/branches/poly/lttv/modules/gui/histogram/histobuttonwidget.c @@ -0,0 +1,246 @@ +/* This file is part of the Linux Trace Toolkit viewer + * Copyright (C) 2006 Parisa Heidari + * + * 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 +#endif + +#include +#include +#include +#include +#include + +#include "histobuttonwidget.h" +#include "histodrawing.h" +#include "histodrawitem.h" +#include "stock_zoom_in_24.xpm" +#include "stock_zoom_out_24.xpm" +#include "stock_zoom_fit_24.xpm" + +#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 + +/***************************************************************************** + * * + *****************************************************************************/ +static GtkWidget *xpm_label_box( gchar *xpm_filename, + gchar *label_text ); +static gboolean gplus( GtkWidget *widget,gpointer user_data) +{ + HistoControlFlowData *histo_cfd = (HistoControlFlowData *)user_data; + //histo_cfd->vertical_ratio =histo_cfd->vertical_ratio * (1.0/2.0); + if(histo_cfd->max_height>1) + { + histo_cfd->max_height /= 2; + //just redraw.horizontal scale is not changed so Array's data are valid. + histogram_show(histo_cfd ,0,histo_cfd->number_of_process->len); + } + else + g_warning("Zoom more than 1 event is impossible"); + + histo_drawing_update_vertical_ruler(histo_cfd->drawing);//, TimeWindow *time_window); + return 0; +} + +static gboolean gMinus( GtkWidget *widget, + gpointer user_data ) +{ + HistoControlFlowData *histo_cfd = (HistoControlFlowData *)user_data; + histo_cfd->max_height *= 2; + + //just redraw.horizontal scale is not changed so Array's data are valid. + histogram_show(histo_cfd ,0,histo_cfd->number_of_process->len); + histo_drawing_update_vertical_ruler(histo_cfd->drawing);//, TimeWindow *time_window); + return 0; +} + +static gboolean gFit( GtkWidget *widget, + gpointer user_data ) +{ + /*find the maximum value and put max_height equal with this maximum*/ + HistoControlFlowData *histo_cfd = (HistoControlFlowData *)user_data; + gint i=1,x; + guint maximum; + maximum =g_array_index(histo_cfd->number_of_process,guint,i); + for (i=1; i < histo_cfd->number_of_process-> len ;i++) + { + x=g_array_index(histo_cfd->number_of_process,guint,i); + maximum=MAX(x,maximum); + } + if (maximum >0) + { + histo_cfd->max_height=maximum; + histogram_show (histo_cfd,0,histo_cfd->number_of_process->len); + } + histo_drawing_update_vertical_ruler(histo_cfd->drawing); + + return 0; +} +/* Create a new hbox with an image and a label packed into it + * and return the box. */ + +static GtkWidget *xpm_label_box( gchar* xpm_filename, + gchar *label_text ) +{ + GtkWidget *box; + GtkWidget *label; + GtkWidget *image; + + GdkPixbuf *pixbufP; + //GError **error; + /* Create box for image and label */ + box = gtk_hbox_new (FALSE, 0); + gtk_container_set_border_width (GTK_CONTAINER (box), 1); + + /* Now on to the image stuff */ + + pixbufP = gdk_pixbuf_new_from_xpm_data((const char*)xpm_filename); + image = gtk_image_new_from_pixbuf(pixbufP); + + /* Create a label for the button */ + label = gtk_label_new (label_text); + + /* Pack the image and label into the box */ + gtk_box_pack_start (GTK_BOX (box), image, FALSE, FALSE, 1); + gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 1); + + gtk_widget_show (image); + gtk_widget_show (label); + + return box; +} + +ButtonWidget *histo_buttonwidget_construct(HistoControlFlowData *histocontrol_flow_data) +{ + GtkWidget *boxPlus, *boxMinus , *boxfit;//containing text and image for each button. + + ButtonWidget *buttonwidget = g_new(ButtonWidget,1); + buttonwidget->histo_control_flow_data = histocontrol_flow_data; + /* Put + and - on the vbox and assign related functions to each button */ + buttonwidget-> vbox1 = gtk_vbox_new (FALSE, 0); + +// Add 2 buttons on the vbox +// buttonwidget ->buttonP = gtk_button_new_with_mnemonic ("+"); +// buttonwidget->buttonM = gtk_button_new_with_mnemonic ("-"); +// Instead, add 2 button with image and text: + + buttonwidget ->buttonP =gtk_button_new (); + buttonwidget ->buttonM =gtk_button_new (); + buttonwidget ->buttonFit =gtk_button_new (); + +/* This calls our box creating function */ + boxPlus = xpm_label_box (stock_zoom_in_24, "vertical"); + boxMinus = xpm_label_box (stock_zoom_out_24, "vertical"); + boxfit = xpm_label_box (stock_zoom_fit_24, "vertical"); + +/* Pack and show all widgets */ + gtk_widget_show (boxPlus); + gtk_widget_show (boxMinus); + gtk_widget_show (boxfit); + + gtk_container_add (GTK_CONTAINER (buttonwidget -> buttonP), boxPlus); + gtk_container_add (GTK_CONTAINER (buttonwidget -> buttonM), boxMinus); + gtk_container_add (GTK_CONTAINER (buttonwidget -> buttonFit), boxfit); + + gtk_box_pack_start (GTK_BOX (buttonwidget->vbox1),buttonwidget->buttonP, TRUE, FALSE, 0); + gtk_box_pack_start (GTK_BOX (buttonwidget->vbox1),buttonwidget->buttonM, TRUE, FALSE, 0); + gtk_box_pack_end (GTK_BOX (buttonwidget->vbox1),buttonwidget->buttonFit, TRUE, FALSE, 0); + + /* When the button receives the "clicked" signal, it will call the + * function gplus() passing it NULL as its argument. The gplus() + * function is defined above . */ + + g_signal_connect (G_OBJECT (buttonwidget ->buttonP), "clicked", + G_CALLBACK (gplus), (gpointer)histocontrol_flow_data); + g_signal_connect (G_OBJECT ( buttonwidget->buttonM), "clicked", + G_CALLBACK (gMinus), (gpointer)histocontrol_flow_data); + g_signal_connect (G_OBJECT ( buttonwidget->buttonFit), "clicked", + G_CALLBACK (gFit), (gpointer)histocontrol_flow_data); + + gtk_widget_show (buttonwidget -> vbox1); + gtk_widget_show (buttonwidget ->buttonP); + gtk_widget_show (buttonwidget ->buttonM); + gtk_widget_show (buttonwidget ->buttonFit); + + return buttonwidget; +} + +void histo_buttonwidget_destroy(ButtonWidget *buttonwidget) +{ + g_debug("buttonwidget_destroy %p", buttonwidget); + + g_free(buttonwidget); + g_debug("buttonwidget_destroy end"); +} + +GtkWidget *histo_buttonwidget_get_widget(ButtonWidget *button_widget) +{ + return button_widget->vbox1; +} + + + +void histo_rectangle_pixmap (GdkGC *gc, + gboolean filled, gint x, gint y, gint width, gint height, + histoDrawing_t *value) +{ + if(height == -1) + height = value->drawing_area->allocation.height; + if(width == -1) + height = value->drawing_area->allocation.width; + gdk_draw_rectangle (value->pixmap, + gc, + filled, + x, y, + width, height); +} + +//This could be usefull if a vertical scroll bar is added to viewer: +void histo_copy_pixmap_region(histoDrawing_t *drawing,GdkDrawable *dest, + GdkGC *gc, GdkDrawable *src, + gint xsrc, gint ysrc, + gint xdest, gint ydest, gint width, gint height) +{ + + if(dest == NULL) + dest = drawing->pixmap; + if(src == NULL) + src = drawing->pixmap; + + gdk_draw_drawable (dest,gc,src,xsrc, ysrc, + xdest, ydest,width, height); +} + +void histo_update_pixmap_size(histoDrawing_t *value, + guint width) +{ + GdkPixmap *old_pixmap = value->pixmap; + + value->pixmap = + gdk_pixmap_new(old_pixmap, + width, + value->height, + -1); + + gdk_pixmap_unref(old_pixmap); +} + diff --git a/ltt/branches/poly/lttv/modules/gui/histogram/histobuttonwidget.h b/ltt/branches/poly/lttv/modules/gui/histogram/histobuttonwidget.h new file mode 100644 index 00000000..7c2ed889 --- /dev/null +++ b/ltt/branches/poly/lttv/modules/gui/histogram/histobuttonwidget.h @@ -0,0 +1,80 @@ +/* This file is part of the Linux Trace Toolkit viewer + * Copyright (C) 2006 Parisa Heidari + * + * 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 _HISTOBUTTONWIDGET_H +#define _HISTOBUTTONWIDGET_H + +#include +#include +#include +#include "histocfv.h" +#include "histodrawitem.h" + + +/* The ButtonWidget + * + * Tasks : + * Create a widget + * containing 3 buttons zoomIn,zoonOut and zoomFit to change the vertical scale. + * + */ +#ifndef TYPE_ButtonWidget_DEFINED +#define TYPE_ButtonWidget_DEFINED +typedef struct _ButtonWidget ButtonWidget; +#endif //TYPE_ButtonWidget_DEFINED + +#ifndef TYPE_HistoControlFlowData_DEFINED +#define TYPE_HistoControlFlowData_DEFINED +typedef struct _HistoControlFlowData HistoControlFlowData; +#endif //TYPE_HistoControlFlowData_DEFINED + +struct _ButtonWidget { + + GtkWidget *buttonP; + GtkWidget *buttonM; + GtkWidget *buttonFit; + + GtkWidget *vbox1;//buttons are placed on this vbox + + GtkWidget *hbox;//Parent Widget containing buttons and drawing area. + HistoControlFlowData *histo_control_flow_data; + +}; + + +void histo_copy_pixmap_region(histoDrawing_t *drawing,GdkDrawable *dest, + GdkGC *gc, GdkDrawable *src, + gint xsrc, gint ysrc, + gint xdest, gint ydest, gint width, gint height); + +void histo_rectangle_pixmap (GdkGC *gc,gboolean filled, gint x, gint y, + gint width, gint height,histoDrawing_t *value); + +ButtonWidget *histo_buttonwidget_construct(HistoControlFlowData *histocontrol_flow_data); + +void histo_buttonwidget_destroy(ButtonWidget *buttonwidget); + + +static gboolean gplus( GtkWidget *widget,gpointer user_data);//assigned to zoomIn +static gboolean gMinus( GtkWidget *widget,gpointer user_data );//assigned to zoomOut +static gboolean gFit( GtkWidget *widget,gpointer user_data );//assigned to zoomFit + +GtkWidget *histo_buttonwidget_get_widget(ButtonWidget *button_widget); +void histo_update_pixmap_size(histoDrawing_t *value, + guint width); +#endif //_HISTOBUTTONWIDGET_H diff --git a/ltt/branches/poly/lttv/modules/gui/histogram/histocfv.c b/ltt/branches/poly/lttv/modules/gui/histogram/histocfv.c new file mode 100644 index 00000000..32da15b0 --- /dev/null +++ b/ltt/branches/poly/lttv/modules/gui/histogram/histocfv.c @@ -0,0 +1,242 @@ +/* This file is part of the Linux Trace Toolkit viewer + * Copyright (C) 2006 Parisa heidari (inspired from CFV by 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 +#endif + +#include +#include +#include +#include +#include + +#include "histocfv.h" +#include "histodrawing.h" +#include "histobuttonwidget.h" +#include "histoeventhooks.h" + +#define PREDEFINED_HEIGHT 5000 + +extern GSList *g_histo_control_flow_data_list; + +static gboolean +header_size_allocate(GtkWidget *widget, + GtkAllocation *allocation, + gpointer user_data) +{ + histoDrawing_t *drawing = (histoDrawing_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; +} + + +/***************************************************************************** + * Histo Control Flow Viewer class implementation * + *****************************************************************************/ +/** + * Histo 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. + */ +HistoControlFlowData * +guihistocontrolflow(Tab *tab) +{ + GtkWidget *button_widget, *drawing_widget, *drawing_area; + GtkWidget *buttonP,*buttonM; + histoDrawing_t *drawing; + HistoControlFlowData* histo_control_flow_data = g_new(HistoControlFlowData,1) ; + + + histo_control_flow_data->tab = tab; + histo_control_flow_data->max_height = PREDEFINED_HEIGHT; + + /*histo_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 + histo_control_flow_data->drawing = histo_drawing_construct(histo_control_flow_data); + + drawing = histo_control_flow_data->drawing; + drawing_widget = histo_drawing_get_widget(drawing); + + drawing_area = histo_drawing_get_drawing_area(drawing); + + histo_control_flow_data->number_of_process = 0; + + ///histo_control_flow_data->background_info_waiting = 0; + + // Create the Button widget + histo_control_flow_data->buttonwidget = histo_buttonwidget_construct(histo_control_flow_data); + + button_widget = histo_buttonwidget_get_widget( histo_control_flow_data-> buttonwidget); + buttonP =histo_control_flow_data-> buttonwidget->buttonP; + buttonM =histo_control_flow_data-> buttonwidget->buttonM; + + //set the size of ruler fix + gtk_widget_set_size_request(histo_control_flow_data->drawing->ruler, -1, 25); + gtk_container_check_resize(GTK_CONTAINER(histo_control_flow_data->drawing->ruler_hbox)); + +/*//or set the size of ruler by button P + g_signal_connect (G_OBJECT(buttonP), + "size-allocate", + G_CALLBACK(header_size_allocate), + (gpointer)histo_control_flow_data->drawing);*/ + + + ///histo_control_flow_data->h_paned = gtk_hpaned_new(); + + ///changed for histogram + histo_control_flow_data->box = gtk_hbox_new(FALSE, 0); + histo_control_flow_data->ev_box = gtk_event_box_new(); + + /// histo_control_flow_data->top_widget =gtk_event_box_new(); + gtk_container_add(GTK_CONTAINER(histo_control_flow_data->ev_box), + drawing_widget); + ///Now add button widget and drawing area on the top_widget. + gtk_box_pack_start (GTK_BOX (histo_control_flow_data->box), + button_widget,FALSE,FALSE, 10); + gtk_box_pack_end (GTK_BOX (histo_control_flow_data->box), + histo_control_flow_data->ev_box,TRUE,TRUE, 0); + histo_control_flow_data->top_widget = histo_control_flow_data->box; + + /*gtk_container_add(GTK_CONTAINER(histo_control_flow_data->box), + histo_control_flow_data->h_paned); + + gtk_paned_pack1(GTK_PANED(histo_control_flow_data->h_paned), + button_widget->vbox1, FALSE, TRUE); + gtk_paned_pack2(GTK_PANED(histo_control_flow_data->h_paned), + drawing_widget, TRUE, TRUE); + */ + gtk_container_set_border_width(GTK_CONTAINER(histo_control_flow_data->ev_box), 1); + + // Set the size of the drawing area + //drawing_Resize(drawing, h, w); + + // Get trace statistics + //histo_control_flow_data->Trace_Statistics = get_trace_statistics(Trace); + + gtk_widget_show(drawing_widget); + gtk_widget_show(button_widget); + /*gtk_widget_show(histo_control_flow_data->h_paned);*/ + gtk_widget_show(histo_control_flow_data->box); + gtk_widget_show(histo_control_flow_data->ev_box); + gtk_widget_show(histo_control_flow_data->top_widget); + g_object_set_data_full( + G_OBJECT(histo_control_flow_data->top_widget), + "histo_control_flow_data", + histo_control_flow_data, + (GDestroyNotify)guihistocontrolflow_destructor); + + g_object_set_data( + G_OBJECT(drawing_area), + "histo_control_flow_data", + histo_control_flow_data); + + g_histo_control_flow_data_list = g_slist_append( + g_histo_control_flow_data_list, + histo_control_flow_data); + histo_control_flow_data->number_of_process =g_array_new (FALSE, + TRUE, + sizeof(guint)); + g_array_set_size (histo_control_flow_data->number_of_process, + drawing_area->allocation.width); + + //WARNING : The widget must be + //inserted in the main window before the drawing area + //can be configured (and this must happend before sending + //data) + + return histo_control_flow_data; + +} + +/* Destroys widget also */ +void guihistocontrolflow_destructor_full(HistoControlFlowData *histo_control_flow_data) +{ + g_info("HISTOCFV.c : guihistocontrolflow_destructor_full, %p", histo_control_flow_data); + /* May already have been done by GTK window closing */ + if(GTK_IS_WIDGET(guihistocontrolflow_get_widget(histo_control_flow_data))) + gtk_widget_destroy(guihistocontrolflow_get_widget(histo_control_flow_data)); + //histo_control_flow_data->mw = NULL; + //FIXME guihistocontrolflow_destructor(histo_control_flow_data); +} + +/* When this destructor is called, the widgets are already disconnected */ +void guihistocontrolflow_destructor(HistoControlFlowData *histo_control_flow_data) +{ + Tab *tab = histo_control_flow_data->tab; + + g_info("HISTOCFV.c : guihistocontrolflow_destructor, %p", histo_control_flow_data); + g_info("%p, %p, %p", histo_update_time_window_hook, histo_control_flow_data, tab); + if(GTK_IS_WIDGET(guihistocontrolflow_get_widget(histo_control_flow_data))) + g_info("widget still exists"); + + /* ButtonWidget is removed with it's widget */ + //buttonwidget_destroy(histo_control_flow_data->buttonwidget); + if(tab != NULL) + { + // Delete reading hooks + lttvwindow_unregister_traceset_notify(tab, + histo_traceset_notify, + histo_control_flow_data); + + lttvwindow_unregister_time_window_notify(tab, + histo_update_time_window_hook, + histo_control_flow_data); + + lttvwindow_unregister_current_time_notify(tab, + histo_update_current_time_hook, + histo_control_flow_data); + + lttvwindow_unregister_redraw_notify(tab, histo_redraw_notify, histo_control_flow_data); + lttvwindow_unregister_continue_notify(tab, + histo_continue_notify, + histo_control_flow_data); + + lttvwindow_events_request_remove_all(histo_control_flow_data->tab, + histo_control_flow_data); + + lttvwindow_unregister_filter_notify(tab, + histo_filter_changed, histo_control_flow_data); + + } + lttvwindowtraces_background_notify_remove(histo_control_flow_data); + g_histo_control_flow_data_list = + g_slist_remove(g_histo_control_flow_data_list,histo_control_flow_data); + + g_array_free(histo_control_flow_data->number_of_process, TRUE); + + g_info("HISTOCFV.c : guihistocontrolflow_destructor end, %p", histo_control_flow_data); + g_free(histo_control_flow_data); + +} + + diff --git a/ltt/branches/poly/lttv/modules/gui/histogram/histocfv.h b/ltt/branches/poly/lttv/modules/gui/histogram/histocfv.h new file mode 100644 index 00000000..4ab10513 --- /dev/null +++ b/ltt/branches/poly/lttv/modules/gui/histogram/histocfv.h @@ -0,0 +1,94 @@ +/* This file is part of the Linux Trace Toolkit viewer + * Copyright (C) 2006 Parisa heidari (inspired from CFV by 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 _HISTOCFV_H +#define _HISTOCFV_H + +#include +#include +//#include "histobuttonwidget.h" + +extern GQuark LTT_NAME_CPU; + + +#ifndef TYPE_histoDrawing_t_DEFINED +#define TYPE_histoDrawing_t_DEFINED +typedef struct _histoDrawing_t histoDrawing_t; +#endif //TYPE_histoDrawing_t_DEFINED + +#ifndef TYPE_ButtonWidget_DEFINED +#define TYPE_ButtonWidget_DEFINED +typedef struct _ButtonWidget ButtonWidget; +#endif //TYPE_ButtonWidget_DEFINED + +#ifndef TYPE_HistoControlFlowData_DEFINED +#define TYPE_HistoControlFlowData_DEFINED +typedef struct _HistoControlFlowData HistoControlFlowData; +#endif //TYPE_HistoControlFlowData_DEFINED + + + +struct _HistoControlFlowData { + + GtkWidget *top_widget;//The hbox containing buttons and drawing area. + Tab *tab; + GtkWidget *box; + GtkWidget *ev_box;//for histogram + ButtonWidget *buttonwidget; + + histoDrawing_t *drawing; + //GtkAdjustment *v_adjust ;//may be used later for scrollbar + + /* Shown events information */ +// TimeWindow time_window; +// LttTime current_time; + + //guint currently_Selected_Event ; + GArray *number_of_process;//number of events + guint background_info_waiting; /* Number of background requests waited for + in order to have all the info ready. */ +// For histogram + guint max_height; + + LttvFilter *histo_main_win_filter; +} ; + +/* Control Flow Data constructor */ +HistoControlFlowData *guihistocontrolflow(Tab *tab); +void +guihistocontrolflow_destructor_full(HistoControlFlowData *histo_control_flow_data); +void +guihistocontrolflow_destructor(HistoControlFlowData *histo_control_flow_data); + +static inline GtkWidget *guihistocontrolflow_get_widget( + HistoControlFlowData *histo_control_flow_data) +{ + return histo_control_flow_data->top_widget ; +} + +static inline ButtonWidget *guihistocontrolflow_get_buttonwidget + (HistoControlFlowData *histo_control_flow_data) +{ + return histo_control_flow_data->buttonwidget ; +} + + + +#endif // _HISTOCFV_H diff --git a/ltt/branches/poly/lttv/modules/gui/histogram/histodrawing.c b/ltt/branches/poly/lttv/modules/gui/histogram/histodrawing.c new file mode 100644 index 00000000..39095ffb --- /dev/null +++ b/ltt/branches/poly/lttv/modules/gui/histogram/histodrawing.c @@ -0,0 +1,1291 @@ +/* This file is part of the Linux Trace Toolkit viewer + * Copyright (C) 2006 Parisa heidari (inspired from CFV by 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 +#endif + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include "histodrawing.h" +#include "histoeventhooks.h" +#include "histocfv.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 +#define TRACE_NUMBER 0 +#define EXTRA_ALLOC 1024 // pixels +#define padding_width 50 + +#if 0 /* colors for two lines representation */ +GdkColor histo_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 histo_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 : red */ + { 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 +histo_expose_ruler( GtkWidget *widget, GdkEventExpose *event, gpointer user_data ); + +static gboolean +histo_expose_vertical_ruler( GtkWidget *widget, GdkEventExpose *event, gpointer user_data ); + +static gboolean +histo_motion_notify_ruler(GtkWidget *widget, GdkEventMotion *event, gpointer user_data); + +static gboolean +histo_motion_notify_vertical_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 histo_drawing_data_request(histoDrawing_t *drawing, + gint x, gint y, + gint width, + gint height) +{ + +} + + +void histo_drawing_data_request_begin(EventsRequest *events_request, LttvTracesetState *tss) +{ + g_debug("Begin of data request"); + HistoControlFlowData *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; + + histo_convert_time_to_pixels( + time_window, + events_request->start_time, + width, + &x); + + } + + void histo_drawing_chunk_begin(EventsRequest *events_request, LttvTracesetState *tss) +{ + g_debug("Begin of chunk"); + HistoControlFlowData *cfd = events_request->viewer_data; + LttvTracesetContext *tsc = LTTV_TRACESET_CONTEXT(tss); + //LttTime current_time = lttv_traceset_context_get_current_tfc(tsc)->timestamp; + guint num_cpu = + ltt_trace_get_num_cpu(tss->parent.traces[TRACE_NUMBER]->t); + + /* //disabled for histogram + cfd->process_list->current_hash_data = g_new(HashedProcessData*,num_cpu); + memset(cfd->process_list->current_hash_data, 0, + sizeof(HashedProcessData*)*num_cpu);*/ + //cfd->drawing->last_start = LTT_TIME_MIN(current_time, + // events_request->end_time); +} + + +void histo_drawing_request_expose(EventsRequest *events_request, + LttvTracesetState *tss, + LttTime end_time) +{ + HistoControlFlowData *cfd = events_request->viewer_data; + histoDrawing_t *drawing = cfd->drawing; + + gint x, x_end, width; + LttvTracesetContext *tsc = (LttvTracesetContext*)tss; + + TimeWindow time_window = + lttvwindow_get_time_window(cfd->tab); + + g_debug("histo request expose"); + + histo_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 ? + //changed for histogram: + 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. + * + * Change the size if width or height changes. + * (different from control flow viewer!) + */ +static gboolean +histo_configure_event( GtkWidget *widget, GdkEventConfigure *event, + gpointer user_data) +{ + histoDrawing_t *drawing = (histoDrawing_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->histo_control_flow_data->mw, + // &drawing->histo_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); + g_debug("drawing configure event"); + g_debug("New alloc draw size : %i by %i",widget->allocation.width, + widget->allocation.height); + +/*modified for histogram, if width is not changed, GArray is valid so + just redraw, else recalculate all.(event request again)*/ + +//enabled again for histogram: + if(drawing->pixmap) + gdk_pixmap_unref(drawing->pixmap); + + drawing->pixmap = gdk_pixmap_new(widget->window, + widget->allocation.width ,//+ SAFETY + EXTRA_ALLOC, + widget->allocation.height + EXTRA_ALLOC, + -1); + +//end add + drawing->alloc_width = drawing->width + SAFETY + EXTRA_ALLOC; + drawing->alloc_height = drawing->height + EXTRA_ALLOC; + + //drawing->height = widget->allocation.height; + + + +// 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. + //histo_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 */) + { + + gdk_draw_rectangle (drawing->pixmap, + drawing->drawing_area->style->black_gc, + TRUE, + 0, 0, + drawing->drawing_area->allocation.width, drawing->drawing_area->allocation.height); + /* histo_drawing_data_request(drawing, + drawing->damage_begin, + 0, + drawing->damage_end - drawing->damage_begin, + drawing->height);*/ + } +//modified for histogram + + if(widget->allocation.width == drawing->width) + { + + drawing->height = widget->allocation.height; + histogram_show( drawing->histo_control_flow_data,0, + drawing->histo_control_flow_data->number_of_process->len); + } + else + { + drawing->width = widget->allocation.width; + drawing->height = widget->allocation.height; + + g_array_set_size (drawing->histo_control_flow_data->number_of_process, + widget->allocation.width); + histo_request_event( drawing->histo_control_flow_data,drawing->damage_begin + ,drawing->damage_end - drawing->damage_begin); + } + return TRUE; +} + + +/* Redraw the screen from the backing pixmap */ +static gboolean +histo_expose_event( GtkWidget *widget, GdkEventExpose *event, gpointer user_data ) +{ + histoDrawing_t *drawing = (histoDrawing_t*)user_data; + + HistoControlFlowData *histo_control_flow_data = + (HistoControlFlowData*)g_object_get_data( + G_OBJECT(widget), + "histo_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(histo_control_flow_data->tab); + LttTime current_time = + lttvwindow_get_current_time(histo_control_flow_data->tab); + + guint cursor_x=0; + + LttTime window_end = time_window.end_time; + + + /* update the screen from the pixmap buffer */ +//added again for histogram: + + 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); + //0 + + drawing->height = drawing-> drawing_area ->allocation.height; + +#if 0 + copy_pixmap_to_screen(histo_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 + + + /* //disabled for histogram + copy_pixmap_to_screen(histo_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 */ + histo_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 +histo_after_expose_event( GtkWidget *widget, GdkEventExpose *event, gpointer user_data ) +{ + //g_assert(0); + g_debug("AFTER EXPOSE"); + + return FALSE; +} + +/* mouse click */ +static gboolean +histo_button_press_event( GtkWidget *widget, GdkEventButton *event, gpointer user_data ) +{ + HistoControlFlowData *histo_control_flow_data = + (HistoControlFlowData*)g_object_get_data( + G_OBJECT(widget), + "histo_control_flow_data"); + histoDrawing_t *drawing = histo_control_flow_data->drawing; + TimeWindow time_window = + lttvwindow_get_time_window(histo_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); + + histo_convert_pixels_to_time(drawing->width, (guint)event->x, + time_window, + &time); + + lttvwindow_report_current_time(histo_control_flow_data->tab, time); + ////report event->y for vertical zoom +,- + } + + return FALSE; +} +/* + //Viewer's vertical scroll bar is already omitted, not needed for histogram. +static gboolean +scrollbar_size_allocate(GtkWidget *widget, + GtkAllocation *allocation, + gpointer user_data) +{ + histoDrawing_t *drawing = (histoDrawing_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; +} +*/ + + +histoDrawing_t *histo_drawing_construct(HistoControlFlowData *histo_control_flow_data) +{ + histoDrawing_t *drawing = g_new(histoDrawing_t, 1); + + drawing->histo_control_flow_data = histo_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->padding,FALSE, FALSE, 0); + + gtk_box_pack_end(GTK_BOX(drawing->ruler_hbox), drawing->ruler, + TRUE, TRUE, 0); + + drawing->drawing_area = gtk_drawing_area_new (); + + drawing->gc = NULL; + /* + ///at this time not necessary for histogram + drawing->hbox = gtk_hbox_new(FALSE, 1); + + drawing->viewport = gtk_viewport_new(NULL, histo_control_flow_data->v_adjust); + drawing->scrollbar = gtk_vscrollbar_new(histo_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); + gtk_container_add(GTK_CONTAINER(drawing->viewport), + drawing->drawing_area);*/ + + //add vertical ruler: + drawing->vruler_drawing_hbox = gtk_hbox_new(FALSE, 1); + drawing-> vertical_ruler =gtk_drawing_area_new (); + gtk_box_pack_start(GTK_BOX(drawing->vruler_drawing_hbox), drawing->vertical_ruler, + FALSE, FALSE, 0); + gtk_box_pack_end(GTK_BOX(drawing->vruler_drawing_hbox), drawing->drawing_area, + TRUE, TRUE, 1); + gtk_widget_set_size_request(drawing->vertical_ruler, padding_width, -1); + + gtk_box_pack_start(GTK_BOX(drawing->vbox), drawing->ruler_hbox, + FALSE, FALSE, 1); + gtk_box_pack_end(GTK_BOX(drawing->vbox), drawing->vruler_drawing_hbox/*drawing_area*/, + TRUE, TRUE, 1); + + 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), + "histo_Link_drawing_Data", + drawing, + (GDestroyNotify)histo_drawing_destroy); + + g_object_set_data( + G_OBJECT(drawing->ruler), + "histo_drawing", + drawing); + + g_object_set_data( + G_OBJECT(drawing->vertical_ruler), + "histo_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 (histo_configure_event), + (gpointer)drawing); + + g_signal_connect (G_OBJECT(drawing->ruler), + "expose_event", + G_CALLBACK(histo_expose_ruler), + (gpointer)drawing); + + gtk_widget_add_events(drawing->ruler, GDK_POINTER_MOTION_MASK); + gtk_widget_add_events(drawing->vertical_ruler, GDK_POINTER_MOTION_MASK); + + g_signal_connect (G_OBJECT(drawing->ruler), + "motion-notify-event", + G_CALLBACK(histo_motion_notify_ruler), + (gpointer)drawing); + + + g_signal_connect (G_OBJECT(drawing->vertical_ruler), + "expose_event", + G_CALLBACK(histo_expose_vertical_ruler), + (gpointer)drawing); + + g_signal_connect (G_OBJECT(drawing->vertical_ruler), + "motion-notify-event", + G_CALLBACK(histo_motion_notify_vertical_ruler), + (gpointer)drawing); + +/*//not necessary for historam. + g_signal_connect (G_OBJECT(drawing->drawing_area), + "size-allocate", + G_CALLBACK(scrollbar_size_allocate), + (gpointer)drawing); */ + + + gtk_widget_set_size_request(drawing->padding, padding_width, -1);//use it for vertical ruler + + g_signal_connect (G_OBJECT(drawing->drawing_area), + "expose_event", + G_CALLBACK (histo_expose_event), + (gpointer)drawing); + + g_signal_connect_after (G_OBJECT(drawing->drawing_area), + "expose_event", + G_CALLBACK (histo_after_expose_event), + (gpointer)drawing); + + g_signal_connect (G_OBJECT(drawing->drawing_area), + "button-press-event", + G_CALLBACK (histo_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->vertical_ruler); + gtk_widget_show(drawing->vruler_drawing_hbox); + gtk_widget_show(drawing->drawing_area); + + /// 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, histo_drawing_colors, NUM_COLORS, FALSE, + TRUE, success); + + drawing->gc = + gdk_gc_new(GDK_DRAWABLE(main_window_get_widget(histo_control_flow_data->tab)->window)); + drawing->dotted_gc = + gdk_gc_new(GDK_DRAWABLE(main_window_get_widget(histo_control_flow_data->tab)->window)); + + gdk_gc_copy(drawing->gc, + main_window_get_widget(histo_control_flow_data->tab)->style->black_gc); + gdk_gc_copy(drawing->dotted_gc, + main_window_get_widget(histo_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(histo_control_flow_data->tab)->window)); + gdk_gc_copy(drawing->ruler_gc_butt, + main_window_get_widget(histo_control_flow_data->tab)->style->black_gc); + drawing->ruler_gc_round = + gdk_gc_new(GDK_DRAWABLE(main_window_get_widget(histo_control_flow_data->tab)->window)); + gdk_gc_copy(drawing->ruler_gc_round, + main_window_get_widget(histo_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 histo_drawing_destroy(histoDrawing_t *drawing) +{ + g_info("histo_drawing_destroy %p", drawing); + + /* Free the colors */ + GdkColormap* colormap = gdk_colormap_get_system(); + + gdk_colormap_free_colors(colormap, histo_drawing_colors, NUM_COLORS); + + // Do not unref here, histoDrawing_t destroyed by it's widget. + //g_object_unref( G_OBJECT(drawing->drawing_area)); + if(drawing->gc != NULL) + gdk_gc_unref(drawing->gc); + + g_free(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); + + //added for histogram + if(drawing->pixmap) + gdk_pixmap_unref(drawing->pixmap); + g_free(drawing); + g_info("histo_drawing_destroy end"); +} + + GtkWidget *histo_drawing_get_drawing_area(histoDrawing_t *drawing) +{ + return drawing->drawing_area; +} + + GtkWidget *histo_drawing_get_widget(histoDrawing_t *drawing) +{ + return drawing->vbox; +} + + void histo_drawing_draw_line( histoDrawing_t *drawing, + GdkPixmap *pixmap, + guint x1, guint y1, + guint x2, guint y2, + GdkGC *GC) +{ + gdk_draw_line (pixmap, + GC, + x1, y1, x2, y2); +} + +void histo_drawing_clear(histoDrawing_t *drawing,guint clear_from,guint clear_to) +{ + + HistoControlFlowData *cfd = drawing->histo_control_flow_data; + guint clear_width = clear_to- clear_from; + /* + //disabled for histogram + rectangle_pixmap(cfd->process_list, + drawing->drawing_area->style->black_gc, + TRUE, + 0, 0, + drawing->alloc_width, // do not overlap + -1);*/ + //instead, this is added for histogram + + histo_rectangle_pixmap (drawing->drawing_area->style->black_gc, + TRUE, + clear_from/*0*/, 0, + clear_width/*drawing->width*/, + -1,drawing); + + + +/* gdk_draw_rectangle (drawing->pixmap, + drawing->drawing_area->style->black_gc, + TRUE, + 0,0, + drawing->drawing_area->allocation.width,drawing->drawing_area->allocation.height ); + + /* ask for the buffer to be redrawn */ +//enabled again for histogram. + gtk_widget_queue_draw_area ( drawing->drawing_area, + clear_from, 0, + clear_width, drawing->height); + gdk_window_process_updates(drawing->drawing_area->window,TRUE); +//disabled instead for histogram + //gtk_widget_queue_draw ( drawing->drawing_area); + return; +} + +#if 0 +/* Insert a square corresponding to a new process in the list */ +/* Applies to whole drawing->width */ +void drawing_insert_square(histoDrawing_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(histoDrawing_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 histo_drawing_update_ruler(histoDrawing_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 +histo_expose_ruler( GtkWidget *widget, GdkEventExpose *event, gpointer user_data ) +{ + histoDrawing_t *drawing = (histoDrawing_t*)user_data; + TimeWindow time_window = lttvwindow_get_time_window(drawing->histo_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; +} + + void histo_drawing_update_vertical_ruler(histoDrawing_t *drawing)//, TimeWindow *time_window) +{ + GtkRequisition req; + GdkRectangle rect; + + req.width = drawing->vertical_ruler->allocation.width; + req.height = drawing->vertical_ruler->allocation.height; + + rect.x = 0; + rect.y = 0; + rect.width = req.width; + rect.height = req.height; + + gtk_widget_queue_draw(drawing->vertical_ruler); + //gtk_widget_draw( drawing->ruler, &rect); +} + +/* notify mouse on ruler */ +static gboolean +histo_motion_notify_ruler(GtkWidget *widget, GdkEventMotion *event, gpointer user_data) +{ + //g_debug("motion"); + //eventually follow mouse and show time here +} + +static gboolean +histo_motion_notify_vertical_ruler(GtkWidget *widget, GdkEventMotion *event, gpointer user_data) +{ + //g_debug("motion"); + //eventually follow mouse and show time here +} + + + +/* Redraw the vertical ruler */ +static gboolean +histo_expose_vertical_ruler( GtkWidget *widget, GdkEventExpose *event, gpointer user_data ) +{ + histoDrawing_t *drawing = (histoDrawing_t*)user_data; + HistoControlFlowData *histo_cfv = drawing->histo_control_flow_data; + gchar text[255]; + + PangoContext *context; + PangoLayout *layout; + PangoFontDescription *FontDesc; + PangoRectangle ink_rect; + gint global_height=0; + GdkColor foreground = { 0, 0, 0, 0 }; + GdkColor background = { 0, 0xffff, 0xffff, 0xffff }; + GdkColor red ={ 0, 0xFFFF, 0x1E00, 0x1000 }; + GdkColor magneta ={ 0, 0x8900, 0x0000, 0x8400 }; + g_debug("vertical ruler expose event"); + + gdk_draw_rectangle (drawing->vertical_ruler->window, + drawing->vertical_ruler->style->white_gc, + TRUE, + event->area.x, event->area.y, + event->area.width, + event->area.height); + + gdk_draw_line (drawing->vertical_ruler->window, + drawing->ruler_gc_butt, + padding_width-1/*event->area.width-1*/,event->area.y, + padding_width-1/*event->area.width-1*/,event->area.y + event->area.height); + + snprintf(text, 255, "%.1f", (float)histo_cfv->max_height); + + 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_height += ink_rect.height; + + gdk_draw_layout_with_colors(drawing->vertical_ruler->window, + drawing->ruler_gc_butt, + 1, + 1, + layout, &foreground, &background); + + gdk_draw_line (drawing->vertical_ruler->window, + drawing->ruler_gc_round, + drawing->vertical_ruler-> allocation.width-1, 1, + drawing->vertical_ruler-> allocation.width-7, 1); + + + snprintf(text, 255, "%lu",0); + + pango_layout_set_text(layout, text, -1); + pango_layout_get_pixel_extents(layout, &ink_rect, NULL); + global_height += ink_rect.height; + + if(global_height <= drawing->vertical_ruler->allocation.height) + { + gdk_draw_layout_with_colors(drawing->vertical_ruler->window, + drawing->ruler_gc_butt, + 1, + drawing->vertical_ruler->allocation.height - ink_rect.height-2, + layout, &foreground, &background); + + gdk_draw_line (drawing->vertical_ruler->window, + drawing->ruler_gc_butt, + drawing->vertical_ruler-> allocation.width-1, + drawing->vertical_ruler->allocation.height-1, + drawing->vertical_ruler-> allocation.width-7, + drawing->vertical_ruler->allocation.height-1); + } + + + snprintf(text, 255, "%.1f",(float) histo_cfv->max_height/2.0); + + pango_layout_set_text(layout, text, -1); + pango_layout_get_pixel_extents(layout, &ink_rect, NULL); + global_height += ink_rect.height; + + if(global_height <= drawing->vertical_ruler->allocation.height) + { + gdk_draw_layout_with_colors(drawing->vertical_ruler->window, + drawing->ruler_gc_butt, + 1, + (drawing->vertical_ruler->allocation.height - ink_rect.height)/2, + layout, &foreground, &background); + + gdk_draw_line (drawing->vertical_ruler->window, + drawing->ruler_gc_butt, + drawing->vertical_ruler-> allocation.width-1, + drawing->vertical_ruler-> allocation.height/2, + drawing->vertical_ruler-> allocation.width-7, + drawing->vertical_ruler->allocation.height/2); + } + + //show number of events at current time: + LttTime current_time = + lttvwindow_get_current_time(histo_cfv->tab); + TimeWindow time_window = + lttvwindow_get_time_window(histo_cfv->tab); + LttTime time_begin = time_window.start_time; + LttTime time_width = time_window.time_width; + LttTime time_end = ltt_time_add(time_begin, time_width); + if((ltt_time_compare(current_time, time_begin) >= 0)&& + (ltt_time_compare(current_time, time_end) <= 0)) + { + guint *events_at_currenttime; + guint max_height=histo_cfv ->max_height; + guint x; + histo_convert_time_to_pixels( + time_window, + current_time, + drawing->width, + &x); + // if(x_testnumber_of_process->len) + + { + events_at_currenttime = + &g_array_index(histo_cfv->number_of_process,guint,x); + + + if((*events_at_currenttime) > max_height) + { + snprintf(text, 255, "OverFlow!"); + pango_layout_set_text(layout, text, -1); + pango_layout_get_pixel_extents(layout, &ink_rect, NULL); + global_height += ink_rect.height; + gdk_draw_layout_with_colors(drawing->vertical_ruler->window, + drawing->ruler_gc_butt, + 1, + (drawing->vertical_ruler->allocation.height - ink_rect.height)/5, + layout, &red, &background); + }else + // if((*events_at_currenttime) <= max_height) + { + snprintf(text, 255, "%.1f", + (float) *events_at_currenttime); + + pango_layout_set_text(layout, text, -1); + pango_layout_get_pixel_extents(layout, &ink_rect, NULL); + global_height += ink_rect.height; + + if ((*events_at_currenttime) == 0) + { + gdk_draw_layout_with_colors(drawing->vertical_ruler->window, + drawing->ruler_gc_butt, + 1, + (drawing->vertical_ruler->allocation.height - ink_rect.height)-2, + layout, &red, &background); + } + else if ((*events_at_currenttime) == max_height) + { + gdk_draw_layout_with_colors(drawing->vertical_ruler->window, + drawing->ruler_gc_butt, + 1, + 1, + layout, &red, &background); + } + /*else if ((*events_at_currenttime) == max_height/2) + { + gdk_draw_layout_with_colors(drawing->vertical_ruler->window, + drawing->ruler_gc_butt, + 1, + (drawing->vertical_ruler->allocation.height - ink_rect.height)/2, + layout, &red, &background); + }*/ + else if ((*events_at_currenttime) > max_height/2) + { + gdk_draw_layout_with_colors(drawing->vertical_ruler->window, + drawing->ruler_gc_butt, + 1, + (drawing->vertical_ruler->allocation.height - ink_rect.height)/4, + layout, &red, &background); + } + else{ + gdk_draw_layout_with_colors(drawing->vertical_ruler->window, + drawing->ruler_gc_butt, + 1, + ((drawing->vertical_ruler->allocation.height + - ink_rect.height)*3)/4, + layout, &red, &background); + } + } + + } + } + + g_object_unref(layout); + + return FALSE; +} + diff --git a/ltt/branches/poly/lttv/modules/gui/histogram/histodrawing.h b/ltt/branches/poly/lttv/modules/gui/histogram/histodrawing.h new file mode 100644 index 00000000..179c92e4 --- /dev/null +++ b/ltt/branches/poly/lttv/modules/gui/histogram/histodrawing.h @@ -0,0 +1,224 @@ +/* This file is part of the Linux Trace Toolkit viewer + * Copyright (C) 2006 Parisa heidari (inspired from CFV by 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 _HISTODRAWING_H +#define _HISTODRAWING_H + +#include +#include +#include +#include +#include +#include +#include +#include "histocfv.h" +#include "histodrawitem.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, /* 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 histo_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_histoDrawing_t_DEFINED +#define TYPE_histoDrawing_t_DEFINED +typedef struct _histoDrawing_t histoDrawing_t; +#endif //TYPE_DRAWING_T_DEFINED + +#ifndef TYPE_HistoControlFlowData_DEFINED +#define TYPE_HistoControlFlowData_DEFINED +typedef struct _HistoControlFlowData HistoControlFlowData; +#endif //TYPE_HistoControlFlowData_DEFINED + +struct _histoDrawing_t { + GtkWidget *vbox; + GtkWidget *drawing_area; + /* + GtkWidget *hbox; + GtkWidget *viewport; + GtkWidget *scrollbar;*///at this time,not necessary for histogram + + GtkWidget *ruler_hbox; + GtkWidget *ruler; + GtkWidget *padding; +//vertical ruler + GtkWidget *vruler_drawing_hbox; + GtkWidget *vertical_ruler; + + GdkPixmap *pixmap; + HistoControlFlowData *histo_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; +}; + +histoDrawing_t *histo_drawing_construct(HistoControlFlowData *histo_control_flow_data); +void histo_drawing_destroy(histoDrawing_t *drawing); + + +void histo_drawing_data_request(histoDrawing_t *drawing, + gint x, gint y, + gint width, + gint height); + + GtkWidget *histo_drawing_get_widget(histoDrawing_t *drawing); +GtkWidget *histo_drawing_get_drawing_area(histoDrawing_t *drawing); + + void histo_drawing_draw_line(histoDrawing_t *drawing, + GdkPixmap *pixmap, + guint x1, guint y1, + guint x2, guint y2, + GdkGC *GC); + +//void drawing_copy(histoDrawing_t *drawing, +// guint xsrc, guint ysrc, +// guint xdest, guint ydest, +// guint width, guint height); + +/* Clear the drawing : make it 1xwidth. */ +void histo_drawing_clear(histoDrawing_t *drawing,guint clear_from,guint clear_to); + +/* Insert a square corresponding to a new process in the list */ +static void drawing_insert_square(histoDrawing_t *drawing, + guint y, + guint height); + +/* Remove a square corresponding to a removed process in the list */ +static void drawing_remove_square(histoDrawing_t *drawing, + guint y, + guint height); + +void histo_drawing_update_ruler(histoDrawing_t *drawing, TimeWindow *time_window); + +void histo_drawing_update_vertical_ruler(histoDrawing_t *drawing);//, TimeWindow *time_window); + +void histo_drawing_request_expose(EventsRequest *events_request, + LttvTracesetState *tss, + LttTime end_time); + +void histo_drawing_data_request_begin(EventsRequest *events_request, + LttvTracesetState *tss); +void histo_drawing_chunk_begin(EventsRequest *events_request, LttvTracesetState *tss); + + + +static void +tree_row_activated(GtkTreeModel *treemodel, + GtkTreePath *arg1, + GtkTreeViewColumn *arg2, + gpointer user_data); + + +/* histo_convert_pixels_to_time + * + * Convert from window pixel and time interval to an absolute time. + */ +static inline void histo_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 histo_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/histogram/histodrawitem.c b/ltt/branches/poly/lttv/modules/gui/histogram/histodrawitem.c new file mode 100644 index 00000000..aafa515d --- /dev/null +++ b/ltt/branches/poly/lttv/modules/gui/histogram/histodrawitem.c @@ -0,0 +1,464 @@ +/* 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 +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "histodrawitem.h" + + +#define MAX_PATH_LEN 256 + +/* drawing hook functions */ +gboolean histo_draw_text( void *hook_data, void *call_data) +{ + histo_PropertiesText *properties = (histo_PropertiesText*)hook_data; + histo_DrawContext *draw_context = (histo_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->histo_position.x) { + case POS_START: + x = draw_context->histo_drawinfo.start.x; + switch(properties->histo_position.y) { + case OVER: + offset = &draw_context->histo_drawinfo.start.offset.over; + x += draw_context->histo_drawinfo.start.offset.over; + y = draw_context->histo_drawinfo.y.over; + break; + case MIDDLE: + offset = &draw_context->histo_drawinfo.start.offset.middle; + x += draw_context->histo_drawinfo.start.offset.middle; + y = draw_context->histo_drawinfo.y.middle; + break; + case UNDER: + offset = &draw_context->histo_drawinfo.start.offset.under; + x += draw_context->histo_drawinfo.start.offset.under; + y = draw_context->histo_drawinfo.y.under; + break; + } + /* verify if there is enough space to draw */ + if(unlikely(x + width <= draw_context->histo_drawinfo.end.x)) { + enough_space = TRUE; + *offset += width; + } + break; + case POS_END: + x = draw_context->histo_drawinfo.end.x; + switch(properties->histo_position.y) { + case OVER: + offset = &draw_context->histo_drawinfo.end.offset.over; + x += draw_context->histo_drawinfo.end.offset.over; + y = draw_context->histo_drawinfo.y.over; + break; + case MIDDLE: + offset = &draw_context->histo_drawinfo.end.offset.middle; + x += draw_context->histo_drawinfo.end.offset.middle; + y = draw_context->histo_drawinfo.y.middle; + break; + case UNDER: + offset = &draw_context->histo_drawinfo.end.offset.under; + x += draw_context->histo_drawinfo.end.offset.under; + y = draw_context->histo_drawinfo.y.under; + break; + } + /* verify if there is enough space to draw */ + if(unlikely(x - width >= draw_context->histo_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 histo_draw_icon( void *hook_data, void *call_data) +{ + histo_PropertiesIcon *properties = (histo_PropertiesIcon*)hook_data; + histo_DrawContext *draw_context = (histo_DrawContext*)call_data; + + LttvIAttribute *attributes = LTTV_IATTRIBUTE(lttv_global_attributes()); + LttvAttributeValue value; + gchar icon_name[MAX_PATH_LEN] = "icons/"; + histo_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(histo_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->histo_position.x) { + case POS_START: + x = draw_context->histo_drawinfo.start.x; + switch(properties->histo_position.y) { + case OVER: + offset = &draw_context->histo_drawinfo.start.offset.over; + x += draw_context->histo_drawinfo.start.offset.over; + y = draw_context->histo_drawinfo.y.over; + break; + case MIDDLE: + offset = &draw_context->histo_drawinfo.start.offset.middle; + x += draw_context->histo_drawinfo.start.offset.middle; + y = draw_context->histo_drawinfo.y.middle; + break; + case UNDER: + offset = &draw_context->histo_drawinfo.start.offset.under; + x += draw_context->histo_drawinfo.start.offset.under; + y = draw_context->histo_drawinfo.y.under; + break; + } + /* verify if there is enough space to draw */ + if(unlikely(x + width <= draw_context->histo_drawinfo.end.x)) { + enough_space = TRUE; + *offset += width; + } + break; + case POS_END: + x = draw_context->histo_drawinfo.end.x; + switch(properties->histo_position.y) { + case OVER: + offset = &draw_context->histo_drawinfo.end.offset.over; + x += draw_context->histo_drawinfo.end.offset.over; + y = draw_context->histo_drawinfo.y.over; + break; + case MIDDLE: + offset = &draw_context->histo_drawinfo.end.offset.middle; + x += draw_context->histo_drawinfo.end.offset.middle; + y = draw_context->histo_drawinfo.y.middle; + break; + case UNDER: + offset = &draw_context->histo_drawinfo.end.offset.under; + x += draw_context->histo_drawinfo.end.offset.under; + y = draw_context->histo_drawinfo.y.under; + break; + } + /* verify if there is enough space to draw */ + if(unlikely(x - width >= draw_context->histo_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 histo_draw_line( void *hook_data, void *call_data) +{ + histo_PropertiesLine *properties = (histo_PropertiesLine*)hook_data; + histo_DrawContext *draw_context = (histo_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->histo_drawinfo.start.x; + x_end = draw_context->histo_drawinfo.end.x; + + switch(properties->y) { + case OVER: + y = draw_context->histo_drawinfo.y.over; + break; + case MIDDLE: + y = draw_context->histo_drawinfo.y.middle; + break; + case UNDER: + y = draw_context->histo_drawinfo.y.under; + break; + } + + histo_drawing_draw_line( + NULL, draw_context->drawable, + x_begin, + y, + x_end, + y, + draw_context->gc); + + return 0; +} + +gboolean histo_draw_arc( void *hook_data, void *call_data) +{ + histo_PropertiesArc *properties = (histo_PropertiesArc*)hook_data; + histo_DrawContext *draw_context = (histo_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->histo_position.x) { + case POS_START: + x = draw_context->histo_drawinfo.start.x; + switch(properties->histo_position.y) { + case OVER: + offset = &draw_context->histo_drawinfo.start.offset.over; + x += draw_context->histo_drawinfo.start.offset.over; + y = draw_context->histo_drawinfo.y.over; + break; + case MIDDLE: + offset = &draw_context->histo_drawinfo.start.offset.middle; + x += draw_context->histo_drawinfo.start.offset.middle; + y = draw_context->histo_drawinfo.y.middle; + break; + case UNDER: + offset = &draw_context->histo_drawinfo.start.offset.under; + x += draw_context->histo_drawinfo.start.offset.under; + y = draw_context->histo_drawinfo.y.under; + break; + } + /* verify if there is enough space to draw */ + if(unlikely(x + width <= draw_context->histo_drawinfo.end.x)) { + enough_space = TRUE; + *offset += width; + } + break; + case POS_END: + x = draw_context->histo_drawinfo.end.x; + switch(properties->histo_position.y) { + case OVER: + offset = &draw_context->histo_drawinfo.end.offset.over; + x += draw_context->histo_drawinfo.end.offset.over; + y = draw_context->histo_drawinfo.y.over; + break; + case MIDDLE: + offset = &draw_context->histo_drawinfo.end.offset.middle; + x += draw_context->histo_drawinfo.end.offset.middle; + y = draw_context->histo_drawinfo.y.middle; + break; + case UNDER: + offset = &draw_context->histo_drawinfo.end.offset.under; + x += draw_context->histo_drawinfo.end.offset.under; + y = draw_context->histo_drawinfo.y.under; + break; + } + /* verify if there is enough space to draw */ + if(unlikely(x - width >= draw_context->histo_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 histo_draw_bg( void *hook_data, void *call_data) +{ + histo_PropertiesBG *properties = (histo_PropertiesBG*)hook_data; + histo_DrawContext *draw_context = (histo_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->histo_drawinfo.start.x, + draw_context->histo_drawinfo.y.over, + draw_context->histo_drawinfo.end.x - draw_context->histo_drawinfo.start.x, + draw_context->histo_drawinfo.y.under - draw_context->histo_drawinfo.y.over); + + return 0; +} + + diff --git a/ltt/branches/poly/lttv/modules/gui/histogram/histodrawitem.h b/ltt/branches/poly/lttv/modules/gui/histogram/histodrawitem.h new file mode 100644 index 00000000..909185ab --- /dev/null +++ b/ltt/branches/poly/lttv/modules/gui/histogram/histodrawitem.h @@ -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 + +typedef struct _histo_DrawContext histo_DrawContext; +typedef struct _histo_DrawInfo histo_DrawInfo; +typedef struct _histo_ItemInfo histo_ItemInfo; + +typedef struct _histo_IconStruct histo_IconStruct; + +typedef struct _histo_DrawOperation histo_DrawOperation; + + +typedef struct _histo_PropertiesText histo_PropertiesText; +typedef struct _histo_PropertiesIcon histo_PropertiesIcon; +typedef struct _histo_PropertiesLine histo_PropertiesLine; +typedef struct _histo_PropertiesArc histo_PropertiesArc; +typedef struct _histo_PropertiesBG histo_PropertiesBG; + +typedef enum _histo_DrawableItems histo_DrawableItems; +enum _histo_DrawableItems { + ITEM_TEXT, ITEM_ICON, ITEM_LINE, ITEM_POINT, ITEM_BACKGROUND +}; + +typedef enum _histo_RelPosX { + POS_START, POS_END +} histo_RelPosX; + +typedef enum _histo_RelPosY { + OVER, MIDDLE, UNDER +} histo_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 _histo_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; + + } histo_drawinfo; +}; + + + + +/* + * Structure used to keep information about icons. + */ +struct _histo_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 _histo_DrawOperation { + histo_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 _histo_PropertiesText { + GdkColor *foreground; + GdkColor *background; + gint size; + gchar *text; + struct { + histo_RelPosX x; + histo_RelPosY y; + } histo_position; +}; + + +struct _histo_PropertiesIcon { + gchar *icon_name; + gint width; + gint height; + struct { + histo_RelPosX x; + histo_RelPosY y; + } histo_position; +}; + +struct _histo_PropertiesLine { + GdkColor color; + gint line_width; + GdkLineStyle style; + histo_RelPosY y; +}; + +struct _histo_PropertiesArc { + GdkColor *color; + gint size; /* We force circle by width = height */ + gboolean filled; + struct { + histo_RelPosX x; + histo_RelPosY y; + } histo_position; +}; + +struct _histo_PropertiesBG { + GdkColor *color; +}; + + + +void histo_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 histo_draw_text( void *hook_data, void *call_data); +gboolean histo_draw_icon( void *hook_data, void *call_data); +gboolean histo_draw_line( void *hook_data, void *call_data); +gboolean histo_draw_arc( void *hook_data, void *call_data); +gboolean histo_draw_bg( void *hook_data, void *call_data); + + +#endif // _DRAW_ITEM_H diff --git a/ltt/branches/poly/lttv/modules/gui/histogram/histoeventhooks.c b/ltt/branches/poly/lttv/modules/gui/histogram/histoeventhooks.c new file mode 100644 index 00000000..900154b4 --- /dev/null +++ b/ltt/branches/poly/lttv/modules/gui/histogram/histoeventhooks.c @@ -0,0 +1,1135 @@ +/* This file is part of the Linux Trace Toolkit viewer + * Copyright (C) 2006 Parisa heidari (inspired from CFV by 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 +#endif + +//#define PANGO_ENABLE_BACKEND +#include +#include +#include +#include +#include +#include + +//#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +#include "histoeventhooks.h" +#include "histocfv.h" +#include "histobuttonwidget.h" +#include "histodrawing.h" + + +#define MAX_PATH_LEN 256 +#define g_info(format...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, format) +//FIXME +#define TRACE_NUMBER 0 +#define EXTRA_ALLOC 1024 // pixels + +/* Action to do when background computation completed. + * + * Wait for all the awaited computations to be over. + */ + +static gint histo_background_ready(void *hook_data, void *call_data) +{ + HistoControlFlowData *histocontrol_flow_data = (HistoControlFlowData *)hook_data; + LttvTrace *trace = (LttvTrace*)call_data; + + histoDrawing_t *drawing = histocontrol_flow_data->drawing; + histocontrol_flow_data->background_info_waiting--; + + if(histocontrol_flow_data->background_info_waiting == 0) { + g_message("Histocontrol flow viewer : background computation data ready."); + + histo_drawing_clear(drawing,0,drawing->width); + + gtk_widget_set_size_request(drawing->drawing_area, + -1, -1); + histo_redraw_notify(histocontrol_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 histo_request_background_data(HistoControlFlowData *histocontrol_flow_data) +{ + LttvTracesetContext * tsc = + lttvwindow_get_traceset_context(histocontrol_flow_data->tab); + gint num_traces = lttv_traceset_number(tsc->ts); + gint i; + LttvTrace *trace; + + LttvHooks *histo_background_ready_hook = + lttv_hooks_new(); + lttv_hooks_add(histo_background_ready_hook, histo_background_ready, histocontrol_flow_data, + LTTV_PRIO_DEFAULT); + histocontrol_flow_data->background_info_waiting = 0; + + for(i=0;its, i); + + if(lttvwindowtraces_get_ready(g_quark_from_string("state"),trace)==FALSE) { + + 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(histocontrol_flow_data->tab), trace, "state"); + lttvwindowtraces_background_notify_queue(histocontrol_flow_data, + trace, + ltt_time_infinite, + NULL, + histo_background_ready_hook); + histocontrol_flow_data->background_info_waiting++; + } else { /* in progress */ + + lttvwindowtraces_background_notify_current(histocontrol_flow_data, + trace, + ltt_time_infinite, + NULL, + histo_background_ready_hook); + histocontrol_flow_data->background_info_waiting++; + } + } else { + /* Data ready. Be 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(histo_background_ready_hook); +} + +/** + * Histogram 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_guihistocontrolflow(Tab *tab) +{ + g_info("h_guihistocontrolflow, %p", tab); + HistoControlFlowData *histocontrol_flow_data = guihistocontrolflow(tab) ; + + histocontrol_flow_data->tab = tab; + + // Unreg done in the GuiHistoControlFlow_Destructor + lttvwindow_register_traceset_notify(tab, + histo_traceset_notify, + histocontrol_flow_data); + + lttvwindow_register_time_window_notify(tab, + histo_update_time_window_hook, + histocontrol_flow_data); + lttvwindow_register_current_time_notify(tab, + histo_update_current_time_hook, + histocontrol_flow_data); + lttvwindow_register_redraw_notify(tab, + histo_redraw_notify, + histocontrol_flow_data); + lttvwindow_register_continue_notify(tab, + histo_continue_notify, + histocontrol_flow_data); + //added for histogram, enable filter: + lttvwindow_register_filter_notify(tab, + histo_filter_changed,histocontrol_flow_data ); + histocontrol_flow_data->histo_main_win_filter = lttvwindow_get_filter(tab); + +// histo_request_background_data(histocontrol_flow_data); + + return guihistocontrolflow_get_widget(histocontrol_flow_data) ; + +} + + + +/// added for histogram. +void histo_request_event( HistoControlFlowData *histocontrol_flow_data, guint x, guint width) +{ + if(width < 0) return ; + + guint i, nb_trace; + Tab *tab = histocontrol_flow_data->tab; + TimeWindow time_window = lttvwindow_get_time_window( tab ); + LttTime time_start, time_end; + + LttvTraceState *ts; + + //find the tracehooks + LttvTracesetContext *tsc = lttvwindow_get_traceset_context(tab); + + LttvTraceset *traceset = tsc->ts; + nb_trace = lttv_traceset_number(traceset); + guint drawing_width= histocontrol_flow_data->drawing->width; +//start time for chunk. + histo_convert_pixels_to_time(drawing_width, /*0*/x, time_window, + &time_start); +//end time for chunk. + histo_convert_pixels_to_time(drawing_width, + /*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, + histocontrol_flow_data); + + + // LttvHooksById *histo_event_by_id = lttv_hooks_by_id_new();//if necessary for filter! + // FIXME : eventually request for more traces + for(i = 0; itraces[i]; + // Fill the events request + histo_events_request->owner = histocontrol_flow_data; + histo_events_request->viewer_data = histocontrol_flow_data; + histo_events_request->servicing = FALSE; + histo_events_request->start_time = time_start;//time_window.start_time; + + histo_events_request->start_position = NULL; + histo_events_request->stop_flag = FALSE; + histo_events_request->end_time = time_end;//time_window.end_time; + + histo_events_request->num_events = G_MAXUINT; + histo_events_request->end_position = NULL; + histo_events_request->trace = i; + histo_events_request->hooks = NULL; + histo_events_request->before_chunk_traceset = histo_before_chunk_traceset;//NULL; + histo_events_request->before_chunk_trace = NULL; + histo_events_request->before_chunk_tracefile= NULL; + histo_events_request->event = histo_count_event_hooks; + histo_events_request->event_by_id = NULL;//histo_event_by_id;//NULL; + histo_events_request->after_chunk_tracefile = NULL; + histo_events_request->after_chunk_trace = NULL; + histo_events_request->after_chunk_traceset = histo_after_chunk_traceset;//NULL; + histo_events_request->before_request = histo_before_trace_hooks; + histo_events_request->after_request = histo_after_trace_hooks; + + lttvwindow_events_request(histocontrol_flow_data->tab, histo_events_request); + } +return; +} + +//hook,added for histogram +int histo_count_event(void *hook_data, void *call_data){ + + guint x;//time to pixel + guint i;// number of events + LttTime event_time; + LttEvent *e; + guint *element; + + EventsRequest *events_request = (EventsRequest*)hook_data; + HistoControlFlowData *histocontrol_flow_data = events_request->viewer_data; + + histoDrawing_t *drawing = histocontrol_flow_data->drawing; + int width = drawing->width; + + g_info("Histogram: count_event() \n"); + + + LttvTracefileContext *tfc = (LttvTracefileContext *)call_data; + LttvTracefileState *tfs = (LttvTracefileState *)call_data; + + e = ltt_tracefile_get_event(tfc->tf); + + LttvFilter *histo_filter = histocontrol_flow_data->histo_main_win_filter; + if(histo_filter != NULL && histo_filter->head != NULL) + if(!lttv_filter_tree_parse(histo_filter->head,e,tfc->tf, + tfc->t_context->t,tfc)) + return FALSE; + + TimeWindow time_window = lttvwindow_get_time_window(histocontrol_flow_data->tab); + event_time = ltt_event_time(e); + + histo_convert_time_to_pixels( + time_window, + event_time, + width, + &x); + element = &g_array_index(histocontrol_flow_data->number_of_process, guint, x); + (*element)++; + + return 0; +} +///befor hook:Added for histogram +int histo_before_trace(void *hook_data, void *call_data){ + + EventsRequest *events_request = (EventsRequest*)hook_data; + HistoControlFlowData *histocontrol_flow_data = events_request->viewer_data; + + histoDrawing_t *drawing = histocontrol_flow_data->drawing; + +//in order to reset all of the array elements. + guint i,end; + end = MIN(histocontrol_flow_data->number_of_process->len,drawing->damage_end); + for(i=drawing->damage_begin/*0*/; + i < end/*histocontrol_flow_data->number_of_process->len*/;i++) + { + g_array_index(histocontrol_flow_data->number_of_process, guint, i) = 0; + } + histo_drawing_clear(drawing,drawing->damage_begin/*0*/, + drawing->damage_end - drawing->damage_begin/*drawing->width*/); + //g_array_free(histocontrol_flow_data->number_of_process,TRUE); + //histocontrol_flow_data->number_of_process =g_array_new (FALSE, + // TRUE, + // sizeof(guint));//4 byte for guint + //g_array_set_size (histocontrol_flow_data->number_of_process, + // drawing->drawing_area->allocation.width); +// gtk_widget_set_size_request(drawing->drawing_area,-1,-1); + gtk_widget_queue_draw(drawing->drawing_area); + return 0; +} +//after hook,added for histogram +int histo_after_trace(void *hook_data, void *call_data){ + + EventsRequest *events_request = (EventsRequest*)hook_data; + HistoControlFlowData *histocontrol_flow_data = events_request->viewer_data; + histoDrawing_t *drawing = histocontrol_flow_data->drawing; + guint x, x_end, width; + LttTime end_time = events_request->end_time; + TimeWindow time_window = + lttvwindow_get_time_window(histocontrol_flow_data->tab); + + g_debug("histo after trace"); + + histo_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; + histogram_show (histocontrol_flow_data,x,x_end); + + return 0; +} + +void histogram_show(HistoControlFlowData *histocontrol_flow_data,guint draw_begin, + guint draw_end) +{ + histoDrawing_t *drawing = histocontrol_flow_data->drawing; + GtkWidget *drawingarea= histo_drawing_get_drawing_area(drawing); + guint width = drawing->width; + guint height= drawing->height;//drawingarea->allocation.height; + + /* gdk_gc_set_line_attributes(drawing->gc, + 2, + GDK_LINE_SOLID, + GDK_CAP_BUTT, + GDK_JOIN_MITER);*/ +//clean the area! + histo_drawing_clear(drawing,draw_begin,draw_end); + LttTime t1,t2; + TimeWindow time_window = + lttvwindow_get_time_window(histocontrol_flow_data->tab); + + guint val,h_val; + + guint i,line_src,line_end; + guint end_chunk=MIN(draw_end,(histocontrol_flow_data->number_of_process)->len); + + for (i=draw_begin/*0*/;inumber_of_process)->len*/;i++){ + val=g_array_index(histocontrol_flow_data->number_of_process,guint,i); + h_val= height-((height*val)/histocontrol_flow_data->max_height); + + histo_convert_pixels_to_time(width, i, + time_window, + &t1); + histo_convert_pixels_to_time(width, i+1, + time_window, + &t2); + line_src=i; + +//check if zoom in is used and more than 1 pixel correspond to each 1nsec +//used for drawing point (not line) on the screen. +/* while (ltt_time_compare(t1,t2)==0) + { + histo_convert_pixels_to_time(width, i++, + time_window, + &t1); + histo_convert_pixels_to_time(width, i+1, + time_window, + &t2); + + + }//while (t1==t2) +*/ //replaced later for lines. + + if(val > drawing->histo_control_flow_data->max_height){ + //overlimit, yellow color + gdk_gc_set_foreground(drawing->gc,&histo_drawing_colors[COL_WHITE] );//COL_RUN_TRAP + gdk_draw_line (drawing->pixmap, + drawing->gc, + i/*line_src*/,1, + i,/*1*/height); + } + else{ + gdk_gc_set_foreground(drawing->gc,&histo_drawing_colors[COL_RUN_USER_MODE] ); + gdk_draw_line (drawing->pixmap, + drawing->gc, + i/*line_src*/,h_val, + i,/*h_val*/height); + } + + while ((ltt_time_compare(t1,t2)==0)&&(i drawing->histo_control_flow_data->max_height){ + //overlimit, yellow color + gdk_gc_set_foreground(drawing->gc, + &histo_drawing_colors[COL_RUN_TRAP] ); + gdk_draw_line (drawing->pixmap, + drawing->gc, + i,1, + i,height); + } + else{ + gdk_gc_set_foreground(drawing->gc,&histo_drawing_colors[COL_RUN_USER_MODE] ); + gdk_draw_line (drawing->pixmap, + drawing->gc, + i,h_val, + i,height); + } + histo_convert_pixels_to_time(width, i, + time_window, + &t1); + if(idrawing_area, + draw_begin, 0, + draw_end-draw_begin, drawing->height); + gdk_window_process_updates(drawingarea->window,TRUE); +} + +int histo_event_selected_hook(void *hook_data, void *call_data) +{ + HistoControlFlowData *histocontrol_flow_data = (HistoControlFlowData*) hook_data; + guint *event_number = (guint*) call_data; + + g_debug("DEBUG : event selected by main window : %u", *event_number); + + return 0; +} + + + +/* histo_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 histo_before_schedchange_hook(void *hook_data, void *call_data) +{ + return 0; +} +*/ + +gint histo_update_time_window_hook(void *hook_data, void *call_data) +{ + HistoControlFlowData *histocontrol_flow_data = (HistoControlFlowData*) hook_data; + histoDrawing_t *drawing = histocontrol_flow_data->drawing; + + const TimeWindowNotifyData *histo_time_window_nofify_data = + ((const TimeWindowNotifyData *)call_data); + + TimeWindow *histo_old_time_window = + histo_time_window_nofify_data->old_time_window; + TimeWindow *histo_new_time_window = + histo_time_window_nofify_data->new_time_window; + + // Update the ruler + histo_drawing_update_ruler(drawing, + histo_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", + histo_old_time_window->start_time.tv_sec, + histo_old_time_window->start_time.tv_nsec, + histo_old_time_window->time_width.tv_sec, + histo_old_time_window->time_width.tv_nsec); + + g_info("New time window HOOK : %lu, %lu to %lu, %lu", + histo_new_time_window->start_time.tv_sec, + histo_new_time_window->start_time.tv_nsec, + histo_new_time_window->time_width.tv_sec, + histo_new_time_window->time_width.tv_nsec); + + //For Histo,redraw always except if zoom fit is pushed 2 times consequently + if( histo_new_time_window->start_time.tv_sec == histo_old_time_window->start_time.tv_sec + && histo_new_time_window->start_time.tv_nsec == histo_old_time_window->start_time.tv_nsec + && histo_new_time_window->time_width.tv_sec == histo_old_time_window->time_width.tv_sec + && histo_new_time_window->time_width.tv_nsec == histo_old_time_window->time_width.tv_nsec) + { + return 0; + } + histo_rectangle_pixmap (drawing->drawing_area->style->black_gc, + TRUE, + 0, 0, + drawing->width,//+SAFETY, // do not overlap + -1,drawing); + + drawing->damage_begin = 0; + drawing->damage_end = drawing->width; + + gtk_widget_queue_draw(drawing->drawing_area); + histo_request_event(histocontrol_flow_data,drawing->damage_begin, + drawing->damage_end- drawing->damage_begin); + + gdk_window_process_updates(drawing->drawing_area->window,TRUE); + +//show number of event at current time + + histo_drawing_update_vertical_ruler(drawing); + + + +/*// if( histo_new_time_window->time_width.tv_sec == histo_old_time_window->time_width.tv_sec + && histo_new_time_window->time_width.tv_nsec == histo_old_time_window->time_width.tv_nsec) + { + // Same scale (scrolling) + g_info("scrolling"); + /* For histogram, + while scrolling no matter far or near , + right or left it's necessary to redraw whole screen!*/ +/*// LttTime *ns = &histo_new_time_window->start_time; + LttTime *nw = &histo_new_time_window->time_width; + LttTime *os = &histo_old_time_window->start_time; + LttTime *ow = &histo_old_time_window->time_width; + LttTime histo_old_end = histo_old_time_window->end_time; + LttTime histo_new_end = histo_new_time_window->end_time; + //if(nsdrawing_area); + + drawing->damage_begin = 0; + drawing->damage_end = drawing->width; + + //replaced for hisogram + histo_request_event(histocontrol_flow_data,drawing->damage_begin, + drawing->damage_end- drawing->damage_begin); +/* + if(ltt_time_compare(*ns, histo_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 = drawing->width; + histo_convert_time_to_pixels( + *histo_old_time_window, + *ns, + width, + &x); + + // Copy old data to new location + //replaced for histogram: + histo_copy_pixmap_region(drawing,NULL, + drawing->drawing_area->style->black_gc,//drawing->gc, + NULL, + x, 0, + 0, 0, (drawing->width-x) + , -1); + + if(drawing->damage_begin == drawing->damage_end) + drawing->damage_begin = drawing->width-x; + else + drawing->damage_begin = 0; + + drawing->damage_end = drawing->width; + +//(histo) copy corresponding array region too: + guint i; + + for(i=0; i < histocontrol_flow_data->number_of_process->len-x;i++) + { + g_array_index(histocontrol_flow_data->number_of_process, guint, i) = + g_array_index(histocontrol_flow_data->number_of_process, guint, i+x); + } + + // Clear the data request background, but not SAFETY + + +//not necessary for histo, because in before chunk ,it clears the area +/* histo_rectangle_pixmap ( + drawing->drawing_area->style->black_gc, + TRUE, + drawing->damage_begin, 0, + drawing->damage_end - drawing->damage_begin, // do not overlap + -1,drawing); +*/ + /* gtk_widget_queue_draw(drawing->drawing_area); + //gtk_widget_queue_draw_area (drawing->drawing_area, + // 0,0, + // histocontrol_flow_data->drawing->width, + // histocontrol_flow_data->drawing->height); + + // Get new data for the rest. + //replaced for hisogram + histo_request_event(histocontrol_flow_data,drawing->damage_begin, + drawing->damage_end- drawing->damage_begin); + } else { + //if(nswidth; + histo_convert_time_to_pixels( + *histo_new_time_window, + *os, + width, + &x); + + // Copy old data to new location + //replaced for histogram + + histo_copy_pixmap_region(drawing,NULL, + drawing->drawing_area->style->black_gc,//drawing->gc, + NULL, + 0, 0, + x, 0, -1, -1); + //(histo) copy corresponding array region too: + guint i; + for(i=histocontrol_flow_data->number_of_process->len; i > x-1;i--) + { + g_array_index(histocontrol_flow_data->number_of_process, guint, i) = + g_array_index(histocontrol_flow_data->number_of_process, guint, i-x); + } + + if(drawing->damage_begin == drawing->damage_end) + drawing->damage_end = x; + else + drawing->damage_end = + drawing->width; + + drawing->damage_begin = 0; + + +//not necessary for histo, because in before chunk ,it clears the area + /* histo_rectangle_pixmap (drawing->drawing_area->style->black_gc, + TRUE, + drawing->damage_begin, 0, + drawing->damage_end - drawing->damage_begin, // do not overlap + -1,drawing); +*/ + /* gtk_widget_queue_draw(drawing->drawing_area); + //gtk_widget_queue_draw_area (drawing->drawing_area, + // 0,0, + // histocontrol_flow_data->drawing->width, + // histocontrol_flow_data->drawing->height); + + + // Get new data for the rest. + +//replaced for hisogram + histo_request_event(histocontrol_flow_data,drawing->damage_begin, + drawing->damage_end- drawing->damage_begin); + + } 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 + + //not necessary for histo, because in before chunk ,it clears the area + /* histo_rectangle_pixmap (histocontrol_flow_data->drawing->drawing_area->style->black_gc, + TRUE, + 0, 0, + histocontrol_flow_data->drawing->width,//+SAFETY, // do not overlap + -1,drawing); +*/ + //gtk_widget_queue_draw_area (drawing->drawing_area, + // 0,0, + // histocontrol_flow_data->drawing->width, + // histocontrol_flow_data->drawing->height); +/* gtk_widget_queue_draw(drawing->drawing_area); + + drawing->damage_begin = 0; + drawing->damage_end = histocontrol_flow_data->drawing->width; +/* + histo_drawing_data_request(histocontrol_flow_data->drawing, + 0, 0, + histocontrol_flow_data->drawing->width, + histocontrol_flow_data->drawing->height);*/ + //replaced for hisogram + /* histo_request_event(histocontrol_flow_data,drawing->damage_begin, + drawing->damage_end- drawing->damage_begin); + } + } + } + } else { + // Different scale (zoom) + g_info("zoom"); + + //not necessary for histo, because in before chunk ,it clears the area + /* + histo_rectangle_pixmap (drawing->drawing_area->style->black_gc, + TRUE, + 0, 0, + histocontrol_flow_data->drawing->width+SAFETY, // do not overlap + -1,drawing); +*/ + //gtk_widget_queue_draw_area (drawing->drawing_area, + // 0,0, + // histocontrol_flow_data->drawing->width, + // histocontrol_flow_data->drawing->height); +/*// gtk_widget_queue_draw(drawing->drawing_area); + + drawing->damage_begin = 0; + drawing->damage_end = drawing->width; + + //replaced for hisogram + histo_request_event(histocontrol_flow_data,drawing->damage_begin, + drawing->damage_end- drawing->damage_begin); + } + + // Update directly when scrolling + gdk_window_process_updates(drawing->drawing_area->window, + TRUE); + + //show number of event at current time + + histo_drawing_update_vertical_ruler(drawing); +*/ +//disabled for histogram, always redraw whole screen. + return 0; +} + +gint histo_traceset_notify(void *hook_data, void *call_data) +{ + HistoControlFlowData *histocontrol_flow_data = (HistoControlFlowData*) hook_data; + histoDrawing_t *drawing = histocontrol_flow_data->drawing; + + if(unlikely(drawing->gc == NULL)) { + return FALSE; + } + if(drawing->dotted_gc == NULL) { + return FALSE; + } + + histo_drawing_clear(drawing,0,drawing->width); + + guint i; + for(i=0;i < histocontrol_flow_data->number_of_process->len;i++) + { + g_array_index(histocontrol_flow_data->number_of_process, guint, i) = 0; + } + gtk_widget_set_size_request( + drawing->drawing_area, + -1, -1); + histo_redraw_notify(histocontrol_flow_data, NULL); + + ///histo_request_background_data(histocontrol_flow_data); + + return FALSE; +} + +gint histo_redraw_notify(void *hook_data, void *call_data) +{ + HistoControlFlowData *histocontrol_flow_data = (HistoControlFlowData*) hook_data; + histoDrawing_t *drawing = histocontrol_flow_data->drawing; + GtkWidget *widget = drawing->drawing_area; + + drawing->damage_begin = 0; + drawing->damage_end = drawing->width; + + // fun feature, to be separated someday... + + histo_drawing_clear(drawing,0,drawing->width); + + gtk_widget_set_size_request( + drawing->drawing_area, + -1, -1); + // Clear the images + + histo_rectangle_pixmap (widget->style->black_gc, + TRUE, + 0, 0, + drawing->alloc_width, + -1,drawing); + gtk_widget_queue_draw(widget); + + + if(drawing->damage_begin < drawing->damage_end) + { + //replaced for histogram + histo_request_event(histocontrol_flow_data,0,drawing->width); + } + + + //gtk_widget_queue_draw_area(drawing->drawing_area, + // 0,0, + // drawing->width, + // drawing->height); + return FALSE; + +} + + +gint histo_continue_notify(void *hook_data, void *call_data) +{ + HistoControlFlowData *histocontrol_flow_data = (HistoControlFlowData*) hook_data; + histoDrawing_t *drawing = histocontrol_flow_data->drawing; + + //g_assert(widget->allocation.width == drawing->damage_end); + + if(drawing->damage_begin < drawing->damage_end) + { + histo_request_event(histocontrol_flow_data,drawing->damage_begin, + drawing->damage_end-drawing->damage_begin); + } + + return FALSE; +} + + +gint histo_update_current_time_hook(void *hook_data, void *call_data) +{ + HistoControlFlowData *histocontrol_flow_data = (HistoControlFlowData*)hook_data; + histoDrawing_t *drawing = histocontrol_flow_data->drawing; + + LttTime current_time = *((LttTime*)call_data); + + TimeWindow time_window = + lttvwindow_get_time_window(histocontrol_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(histocontrol_flow_data->tab); + + LttTime trace_start = tsc->time_span.start_time; + LttTime trace_end = tsc->time_span.end_time; + + g_info("Histogram: 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 histo_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); + + histo_new_time_window.start_time = time_begin; + histo_new_time_window.time_width = width; + histo_new_time_window.time_width_double = ltt_time_to_double(width); + histo_new_time_window.end_time = ltt_time_add(time_begin, width); + + lttvwindow_report_time_window(histocontrol_flow_data->tab, histo_new_time_window); + } + else if(ltt_time_compare(current_time, time_end) > 0) + { + TimeWindow histo_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); + + histo_new_time_window.start_time = time_begin; + histo_new_time_window.time_width = width; + histo_new_time_window.time_width_double = ltt_time_to_double(width); + histo_new_time_window.end_time = ltt_time_add(time_begin, width); + + lttvwindow_report_time_window(histocontrol_flow_data->tab, histo_new_time_window); + + } + gtk_widget_queue_draw(drawing->drawing_area); + + /* Update directly when scrolling */ + gdk_window_process_updates(drawing->drawing_area->window, + TRUE); + + histo_drawing_update_vertical_ruler(drawing); + + return 0; +} + +gboolean histo_filter_changed(void * hook_data, void * call_data) +{ + HistoControlFlowData *histocontrol_flow_data = (HistoControlFlowData*)hook_data; + histoDrawing_t *drawing =histocontrol_flow_data->drawing; + + LttvTracesetContext * tsc = + lttvwindow_get_traceset_context(histocontrol_flow_data->tab); + + histocontrol_flow_data->histo_main_win_filter = + (LttvFilter*)call_data; + //get_events(event_viewer_data->vadjust_c->value, event_viewer_data); + gtk_widget_set_size_request( + drawing->drawing_area, + -1, -1); + drawing->damage_begin = 0; + drawing->damage_end = drawing->width; + + /* //done in, before request! + histo_drawing_clear(drawing,0,drawing->width); + guint i; + for(i=0;i < histocontrol_flow_data->number_of_process->len;i++) + { + g_array_index(histocontrol_flow_data->number_of_process, guint, i) = 0; + }*/ + + histo_request_event(histocontrol_flow_data,0,drawing->width); + + return FALSE; +} + +typedef struct _histo_ClosureData { + EventsRequest *events_request; + LttvTracesetState *tss; + LttTime end_time; + guint x_end; +} histo_ClosureData; + + + +int histo_before_chunk(void *hook_data, void *call_data) +{ + EventsRequest *histo_events_request = (EventsRequest*)hook_data; + LttvTracesetState *histo_tss = (LttvTracesetState*)call_data; + HistoControlFlowData *histo_cfd = (HistoControlFlowData*)histo_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 + histo_drawing_chunk_begin(histo_events_request, histo_tss); + + return 0; +} + +/*int histo_before_request(void *hook_data, void *call_data) +{ + EventsRequest *events_request = (EventsRequest*)hook_data; + LttvTracesetState *tss = (LttvTracesetState*)call_data; + + histo_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 histo_after_request(void *hook_data, void *call_data) +{ + return 0; +} +*/ +/* + * for each process + * draw closing line + * expose + */ + +int histo_after_chunk(void *hook_data, void *call_data) +{ + EventsRequest *events_request = (EventsRequest*)hook_data; + HistoControlFlowData *histocontrol_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; + + histoDrawing_t *drawing = histocontrol_flow_data->drawing; + + 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; + + guint x, x_end, width; + + TimeWindow time_window = + lttvwindow_get_time_window(histocontrol_flow_data->tab); + + g_debug("histo after chunk"); + + histo_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; + + histogram_show (histocontrol_flow_data,x,x_end); + + return 0; +} + diff --git a/ltt/branches/poly/lttv/modules/gui/histogram/histoeventhooks.h b/ltt/branches/poly/lttv/modules/gui/histogram/histoeventhooks.h new file mode 100644 index 00000000..e8a49bea --- /dev/null +++ b/ltt/branches/poly/lttv/modules/gui/histogram/histoeventhooks.h @@ -0,0 +1,128 @@ +/* This file is part of the Linux Trace Toolkit viewer + * Copyright (C) 2006 Parisa heidari (inspired from CFV by 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 +#include +#include + +#include "histobuttonwidget.h" +#include "histodrawing.h" +#include "histocfv.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(ButtonWidget *buttonwidget, histoDrawing_t *drawing);//?? + +GtkWidget *h_guihistocontrolflow(Tab *tab); + +//GtkWidget *h_legend(Tab *tab); + +int histo_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 histo_before_schedchange_hook(void *hook_data, void *call_data); +int histo_after_schedchange_hook(void *hook_data, void *call_data); +int histo_before_execmode_hook(void *hook_data, void *call_data); +int histo_after_execmode_hook(void *hook_data, void *call_data); + + +int histo_before_process_exit_hook(void *hook_data, void *call_data); +int histo_before_process_release_hook(void *hook_data, void *call_data); +int histo_after_process_exit_hook(void *hook_data, void *call_data); +int histo_after_process_fork_hook(void *hook_data, void *call_data); +int histo_after_fs_exec_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 histo_draw_closure(guint key, gpointer value, gpointer user_data); + +int histo_before_chunk(void *hook_data, void *call_data); +int histo_after_chunk(void *hook_data, void *call_data); +//int histo_before_request(void *hook_data, void *call_data); +//int histo_after_request(void *hook_data, void *call_data); + + + +gint histo_update_time_window_hook(void *hook_data, void *call_data); +gint histo_update_current_time_hook(void *hook_data, void *call_data); +gint histo_traceset_notify(void *hook_data, void *call_data); +gint histo_redraw_notify(void *hook_data, void *call_data); +gint histo_continue_notify(void *hook_data, void *call_data); + +//just for histogram +void histo_request_event( HistoControlFlowData *histocontrol_flow_data,guint x, guint width); +int histo_count_event(void *hook_data, void *call_data); +int histo_before_trace(void *hook_data, void *call_data);//replaced for histo_before_request +int histo_after_trace(void *hook_data, void *call_data);//replaced for histo_after_request + +gboolean histo_filter_changed(void * hook_data, void * call_data); + +void histogram_show(HistoControlFlowData *histocontrol_flow_data,guint draw_begin,guint draw_end); +#endif // _EVENT_HOOKS_H diff --git a/ltt/branches/poly/lttv/modules/gui/histogram/histomodule.c b/ltt/branches/poly/lttv/modules/gui/histogram/histomodule.c new file mode 100644 index 00000000..c9c58141 --- /dev/null +++ b/ltt/branches/poly/lttv/modules/gui/histogram/histomodule.c @@ -0,0 +1,93 @@ +/* This file is part of the Linux Trace Toolkit viewer + * Copyright (C) 2006 Parisa heidari (inspired from CFV by 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 +#endif + +#include +#include +#include +#include + +#include "histocfv.h" +#include "histoeventhooks.h" + +#include "hHistogramInsert.xpm" + + +GQuark LTT_NAME_CPU; + +/** Array containing instanced objects. Used when module is unloaded */ +GSList *g_histo_control_flow_data_list = NULL ; + +/***************************************************************************** + * Functions for module loading/unloading * + *****************************************************************************/ +/** + * plugin's init function + * + * This function initializes the Histogram Control Flow Viewer functionnality through the + * gtkTraceSet API. + */ +static void histo_init() { + + g_info("GUI ControlFlow Viewer init()"); + + /* Register the toolbar insert button and menu entry*/ + lttvwindow_register_constructor("histogram", + "/", + "Insert Histogram Viewer", + hHistogramInsert_xpm, + "Insert Histogram Viewer", + h_guihistocontrolflow); + + LTT_NAME_CPU = g_quark_from_string("/cpu"); +} + +void histo_destroy_walk(gpointer data, gpointer user_data) +{ + g_info("Walk destroy GUI Histogram Control Flow Viewer"); + guihistocontrolflow_destructor_full((HistoControlFlowData*)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 histo_destroy() { + g_info("GUI Histogram Control Flow Viewer destroy()"); + + g_slist_foreach(g_histo_control_flow_data_list, histo_destroy_walk, NULL ); + + g_slist_free(g_histo_control_flow_data_list); + + /* Unregister the toolbar insert button and menu entry */ + lttvwindow_unregister_constructor(h_guihistocontrolflow); + +} + + +LTTV_MODULE("guihistogram", "Event Histogram viewer", \ + "Graphical module to view events' density histogram", \ + histo_init, histo_destroy, "lttvwindow") diff --git a/ltt/branches/poly/lttv/modules/gui/histogram/stock_zoom_fit_24.xpm b/ltt/branches/poly/lttv/modules/gui/histogram/stock_zoom_fit_24.xpm new file mode 100644 index 00000000..bd0b3f43 --- /dev/null +++ b/ltt/branches/poly/lttv/modules/gui/histogram/stock_zoom_fit_24.xpm @@ -0,0 +1,216 @@ +/* XPM */ +static char *stock_zoom_fit_24[]={ +"24 24 189 2", +"Qt c None", +"ae c #000000", +"aF c #000000", +"an c #050505", +".U c #242424", +".s c #373737", +".G c #4f4f4f", +".h c #5d5d5d", +"aS c #000000", +"a6 c #000000", +"at c #000000", +"aQ c #000000", +"ad c #000000", +"au c #030303", +"#8 c #0c0c0c", +"#j c #121212", +".F c #232323", +"#. c #303030", +".g c #353535", +".t c #404040", +".# c #494949", +"aE c #000000", +"#7 c #000000", +"#s c #090909", +"#1 c #0a0a0a", +"#k c #1b1b1b", +".f c #262626", +".a c #343434", +"am c #000000", +"aG c #010101", +"af c #060606", +".9 c #0f0f0f", +".r c #1c1c1c", +".V c #212121", +".i c #2e2e2e", +"aR c #000000", +"#0 c #020202", +"#A c #060606", +"#V c #0b0b0b", +"#t c #141414", +".e c #262626", +".b c #2d2d2d", +"aN c #000000", +"a4 c #000000", +"aW c #000000", +"aO c #000000", +"aC c #000000", +"aD c #000000", +"aP c #000000", +"aT c #202020", +"a1 c #000000", +"aU c #202020", +"aV c #000000", +"aY c #343434", +"a2 c #000000", +"as c #000000", +"av c #030303", +"#U c #050505", +"#J c #060606", +"#K c #0e0e0e", +".T c #101010", +"#B c #111111", +".E c #131313", +"a3 c #1f1f1f", +".H c #222222", +".d c #262626", +".u c #272727", +".c c #292929", +"aX c #686868", +"a0 c #3a3a3a", +"a5 c #000000", +"aZ c #797979", +"aM c #000000", +"ac c #020202", +"aH c #030303", +"#9 c #0a0a0a", +"#i c #0e0e0e", +"## c #1f1f1f", +".q c #202020", +"aB c #2b2b2b", +"al c #2e2e2e", +".j c #303030", +"aw c #313131", +"ag c #3b3b3b", +"aL c #3c3c3c", +"aj c #414141", +".8 c #434343", +"ai c #444444", +"aa c #454545", +".Y c #464646", +"a# c #474747", +"#5 c #484848", +"a. c #494949", +".6 c #4a4a4a", +".Z c #4b4b4b", +".D c #4c4c4c", +"#f c #4d4d4d", +"#p c #4e4e4e", +".5 c #4f4f4f", +".0 c #505050", +".4 c #515151", +".1 c #525252", +"#c c #535353", +"#r c #575757", +".W c #5b5b5b", +".S c #5e5e5e", +"#2 c #5f5f5f", +".v c #616161", +".p c #676767", +"#l c #6d6d6d", +".k c #737373", +".I c #757575", +"aK c #777777", +"aI c #7a7a7a", +"aA c #909090", +"#Z c #939393", +"ax c #999999", +"aJ c #9a9a9a", +"#z c #9b9b9b", +".o c #9d9d9d", +".l c #a1a1a1", +"#W c #a5a5a5", +".C c #a7a7a7", +"#u c #a8a8a8", +"#h c #ababab", +".n c #b2b2b2", +".m c #b4b4b4", +"az c #b6b6b6", +"ar c #b8b8b8", +"#a c #b9b9b9", +"#T c #bababa", +"ay c #bbbbbb", +".R c #bcbcbc", +"ak c #bdbdbd", +"#I c #bfbfbf", +".B c #c1c1c1", +".7 c #c2c2c2", +"#C c #c5c5c5", +"#L c #c6c6c6", +"ao c #c7c7c7", +"aq c #c8c8c8", +".A c #c9c9c9", +".w c #cacaca", +"ab c #cbcbcb", +".X c #cccccc", +"ap c #cdcdcd", +".z c #cecece", +".x c #cfcfcf", +".y c #d0d0d0", +"#Y c #d1d1d1", +".Q c #d2d2d2", +".J c #d3d3d3", +"#6 c #d4d4d4", +"#b c #d6d6d6", +"#S c #d7d7d7", +"#v c #d8d8d8", +"#3 c #d9d9d9", +"ah c #dadada", +".K c #dbdbdb", +"#y c #dcdcdc", +"#D c #dfdfdf", +"#R c #e0e0e0", +"#m c #e1e1e1", +"#M c #e3e3e3", +"#g c #e4e4e4", +".P c #e5e5e5", +"#q c #e6e6e6", +".L c #e7e7e7", +"#4 c #e9e9e9", +"#Q c #eaeaea", +"#N c #ececec", +"#H c #ededed", +"#w c #eeeeee", +".M c #efefef", +"#P c #f0f0f0", +".O c #f1f1f1", +"#G c #f2f2f2", +".N c #f3f3f3", +"#O c #f4f4f4", +"#E c #f5f5f5", +"#X c #f6f6f6", +"#F c #f7f7f7", +"#x c #f8f8f8", +"#o c #f9f9f9", +".3 c #fafafa", +".2 c #fbfbfb", +"#e c #fcfcfc", +"#d c #fdfdfd", +"#n c #fefefe", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQt.#.a.b.c.d.e.f.gQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQt.h.i.j.k.l.m.n.o.p.q.r.sQtQtQtQtQtQtQtQt", +"QtQtQt.t.u.v.m.w.x.y.z.A.B.C.D.E.FQtQtQtQtQtQtQt", +"QtQt.G.H.I.w.J.K.L.M.N.O.P.Q.R.S.T.UQtQtQtQtQtQt", +"QtQt.V.W.X.Y.Z.0.1.2.3.4.0.5.6.7.8.9QtQtQtQtQtQt", +"Qt#.###a#b.D.1.1#c#d#e.1.4.5#f#g#h#i#jQtQtQtQtQt", +"Qt#k#l.Q#m.0.1#d#n#n#d#e#o.0#p#q.K#r#sQtQtQtQtQt", +"Qt#t#u#v#w.4.1#e#n#n#d.2#x.0#p#q#y#z#AQtQtQtQtQt", +"Qt#B#C#D.M#E#x.2#d#d#e.3#F#G#H.P.K#I#JQtQtQtQtQt", +"Qt#K#L#M#N#G#E#x.3.3.3#F#O#P#Q#R#S#T#UQtQtQtQtQt", +"Qt#V#W#m.L#p.5#O#X#X#E.N.M#f.Z.K#Y#Z#0QtQtQtQtQt", +"Qt#1#2#3#m.Z#f#w.M.M#w#H#4.Z#5#6.w.D#7QtQtQtQtQt", +"Qt#8#9.m#v#5.6.Z.Z#q.L.6a.a#aaab.lacadQtQtQtQtQt", +"Qtaeafag.Xaaaaa##5ah.Ka#.YaiajakalamQtQtQtQtQtQt", +"QtQtan#U.4.7aoab.Xapababaq.7araaasatQtQtQtQtQtQt", +"QtQtaeauavawaxayak.R.R.RazaAaBasaCaDaEQtQtQtQtQt", +"QtQtQtaeaFaGaHajaIaJaJaKaLaMamaFaNaOaPaNaQQtQtQt", +"QtQtQtQtQtaead#7aRasasaR#7adaSaeaeaTaUaVaCaSQtQt", +"QtQtQtQtQtQtQtaeaeaeaeaeaeaeQtQtaeaWaXaYaDaVaeQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtaeaPaZa0aPa1ae", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtaeaea2aXa3a1ae", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtaeaea4a5a6ae", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtaeaeaeQtQt"}; diff --git a/ltt/branches/poly/lttv/modules/gui/histogram/stock_zoom_in_24.xpm b/ltt/branches/poly/lttv/modules/gui/histogram/stock_zoom_in_24.xpm new file mode 100644 index 00000000..a23a4442 --- /dev/null +++ b/ltt/branches/poly/lttv/modules/gui/histogram/stock_zoom_in_24.xpm @@ -0,0 +1,169 @@ +/* XPM */ +static char *stock_zoom_in_24[]={ +"24 24 142 2", +"Qt c None", +"#V c #000000", +"ae c #010101", +"#O c #020202", +"#9 c #030303", +"#J c #050505", +"#v c #060606", +"#n c #090909", +"#P c #0a0a0a", +"#K c #0b0b0b", +"#W c #0c0c0c", +"#e c #0e0e0e", +".5 c #0f0f0f", +".R c #101010", +"#w c #111111", +"#f c #121212", +".C c #131313", +"#o c #141414", +"#g c #1b1b1b", +".p c #1c1c1c", +".6 c #1f1f1f", +".o c #202020", +".T c #212121", +".F c #222222", +".D c #232323", +".S c #242424", +".d c #262626", +".s c #272727", +".c c #292929", +"ad c #2b2b2b", +".b c #2d2d2d", +".g c #2e2e2e", +".h c #303030", +"a. c #313131", +".a c #343434", +".e c #353535", +".q c #373737", +"al c #3a3a3a", +"#1 c #3b3b3b", +"ai c #3c3c3c", +"#Y c #3f3f3f", +".r c #404040", +"#F c #414141", +"#A c #424242", +".4 c #434343", +"#z c #444444", +"## c #454545", +".# c #494949", +".B c #4c4c4c", +".E c #4f4f4f", +"#5 c #515151", +"#m c #575757", +".U c #5b5b5b", +".f c #5d5d5d", +".Q c #5e5e5e", +"#Q c #5f5f5f", +".t c #616161", +".n c #676767", +"aj c #686868", +"#h c #6d6d6d", +".i c #737373", +".G c #757575", +"ah c #777777", +"ak c #797979", +"af c #7a7a7a", +"ac c #909090", +"#N c #939393", +"a# c #999999", +"ag c #9a9a9a", +"#u c #9b9b9b", +".m c #9d9d9d", +".j c #a1a1a1", +"#L c #a5a5a5", +".A c #a7a7a7", +"#p c #a8a8a8", +"#d c #ababab", +".l c #b2b2b2", +".k c #b4b4b4", +"ab c #b6b6b6", +"#8 c #b8b8b8", +".7 c #b9b9b9", +"#I c #bababa", +"aa c #bbbbbb", +".P c #bcbcbc", +"#4 c #bdbdbd", +"#C c #bfbfbf", +".z c #c1c1c1", +".3 c #c2c2c2", +"#x c #c5c5c5", +"#D c #c6c6c6", +"#6 c #c7c7c7", +"#3 c #c8c8c8", +".y c #c9c9c9", +".u c #cacaca", +"#0 c #cbcbcb", +".V c #cccccc", +"#7 c #cdcdcd", +".x c #cecece", +".v c #cfcfcf", +".w c #d0d0d0", +"#M c #d1d1d1", +".O c #d2d2d2", +".H c #d3d3d3", +"#U c #d4d4d4", +"#2 c #d5d5d5", +".8 c #d6d6d6", +".W c #d7d7d7", +"#q c #d8d8d8", +"#R c #d9d9d9", +"#Z c #dadada", +".I c #dbdbdb", +"#t c #dcdcdc", +"#y c #dfdfdf", +"#H c #e0e0e0", +".2 c #e1e1e1", +"#X c #e2e2e2", +"#E c #e3e3e3", +"#c c #e4e4e4", +".N c #e5e5e5", +"#l c #e6e6e6", +".J c #e7e7e7", +"#T c #e9e9e9", +"#G c #eaeaea", +"#S c #ebebeb", +"#b c #ececec", +"#B c #ededed", +"#k c #eeeeee", +".K c #efefef", +".1 c #f0f0f0", +".M c #f1f1f1", +"#a c #f2f2f2", +".L c #f3f3f3", +"#s c #f4f4f4", +".X c #f5f5f5", +"#r c #f6f6f6", +".0 c #f8f8f8", +".9 c #f9f9f9", +".Y c #fafafa", +".Z c #fbfbfb", +"#j c #fcfcfc", +"#. c #fdfdfd", +"#i c #fefefe", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQt.#.a.b.c.d.d.d.eQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQt.f.g.h.i.j.k.l.m.n.o.p.qQtQtQtQtQtQtQtQt", +"QtQtQt.r.s.t.k.u.v.w.x.y.z.A.B.C.DQtQtQtQtQtQtQt", +"QtQt.E.F.G.u.H.I.J.K.L.M.N.O.P.Q.R.SQtQtQtQtQtQt", +"QtQt.T.U.V.W.N.X.Y.Z.Y.0.X.1.2.3.4.5QtQtQtQtQtQt", +"Qt.h.6.7.8.J.9.Z#.####.Z.0#a#b#c#d#e#fQtQtQtQtQt", +"Qt#g#h.O.2.X.Y#.#i#####j.9.X#k#l.I#m#nQtQtQtQtQt", +"Qt#o#p#q#k#r.9#j#i####.Z.0#s#k#l#t#u#vQtQtQtQtQt", +"Qt#w#x#y.K.X#z#z#######z.4#A#B.N.I#C#vQtQtQtQtQt", +"Qt#e#D#E#b#a.4#z#z#z#z.4#A#F#G#H.W#I#JQtQtQtQtQt", +"Qt#K#L.2.J#B.M#s#r.4.4.L.K#b#c.I#M#N#OQtQtQtQtQt", +"Qt#P#Q#R.2#l#S#k.K#F#F#B#T#c.I#U.u.B#VQtQtQtQtQt", +"Qt#W#P.k#q#t#X.N#l#Y#Y#E#y#Z#U#0.j#O#VQtQtQtQtQt", +"Qt#V#v#1.V.O#U#Z.I#Z.I#q#2.w#3#4.g#VQtQtQtQtQtQt", +"QtQt#J#J#5.3#6#0.V#7#0#0#3.3#8###V#VQtQtQtQtQtQt", +"QtQt#V#9#9a.a#aa#4.P.P.Pabacad#V#V#V#VQtQtQtQtQt", +"QtQtQt#V#Vae#9#Fafagagahai#V#V#V#V#V#V#V#VQtQtQt", +"QtQtQtQtQt#V#V#V#V#V#V#V#V#V#V#V#V.o.o#V#V#VQtQt", +"QtQtQtQtQtQtQt#V#V#V#V#V#V#VQtQt#V#Vaj.a#V#V#VQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt#V#Vakal#V#V#V", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt#V#V#Vaj.6#V#V", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt#V#V#V#V#V#V", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt#V#V#VQtQt"}; diff --git a/ltt/branches/poly/lttv/modules/gui/histogram/stock_zoom_out_24.xpm b/ltt/branches/poly/lttv/modules/gui/histogram/stock_zoom_out_24.xpm new file mode 100644 index 00000000..61121991 --- /dev/null +++ b/ltt/branches/poly/lttv/modules/gui/histogram/stock_zoom_out_24.xpm @@ -0,0 +1,207 @@ +/* XPM */ +static char *stock_zoom_out_24[]={ +"24 24 180 2", +"Qt c None", +"#8 c #000000", +"aw c #000000", +"ae c #050505", +".U c #242424", +".s c #373737", +".G c #4f4f4f", +".h c #5d5d5d", +"aJ c #000000", +"aX c #000000", +"ak c #000000", +"aH c #000000", +"#7 c #000000", +"al c #030303", +"#1 c #0c0c0c", +"#i c #121212", +".F c #232323", +".8 c #303030", +".g c #353535", +".t c #404040", +".# c #494949", +"av c #000000", +"#0 c #000000", +"#p c #090909", +"#U c #0a0a0a", +"#j c #1b1b1b", +".f c #262626", +".a c #343434", +"ad c #000000", +"ax c #010101", +"#9 c #060606", +".7 c #0f0f0f", +".r c #1c1c1c", +".V c #212121", +".i c #2e2e2e", +"aI c #000000", +"#T c #020202", +"#x c #060606", +"#P c #0b0b0b", +"#q c #141414", +".e c #262626", +".b c #2d2d2d", +"aE c #000000", +"aV c #000000", +"aN c #000000", +"aF c #000000", +"at c #000000", +"au c #000000", +"aG c #000000", +"aK c #202020", +"aS c #000000", +"aL c #202020", +"aM c #000000", +"aP c #343434", +"aT c #000000", +"aj c #000000", +"am c #030303", +"#O c #050505", +"#G c #060606", +"#H c #0e0e0e", +".T c #101010", +"#y c #111111", +".E c #131313", +"aU c #1f1f1f", +".H c #222222", +".d c #262626", +".u c #272727", +".c c #292929", +"aO c #686868", +"aR c #3a3a3a", +"aW c #000000", +"aQ c #797979", +"aD c #000000", +"#6 c #020202", +"ay c #030303", +"#2 c #0a0a0a", +"#h c #0e0e0e", +".9 c #1f1f1f", +".q c #202020", +"as c #2b2b2b", +"ac c #2e2e2e", +".j c #303030", +"an c #313131", +"a. c #3b3b3b", +"aC c #3c3c3c", +"#K c #414141", +"#D c #424242", +".6 c #434343", +"#B c #444444", +"#C c #454545", +".D c #4c4c4c", +"af c #515151", +"#o c #575757", +".W c #5b5b5b", +".S c #5e5e5e", +"#V c #5f5f5f", +".v c #616161", +".p c #676767", +"#k c #6d6d6d", +".k c #737373", +".I c #757575", +"aB c #777777", +"az c #7a7a7a", +"ar c #909090", +"#S c #939393", +"ao c #999999", +"aA c #9a9a9a", +"#w c #9b9b9b", +".o c #9d9d9d", +".l c #a1a1a1", +"#Q c #a5a5a5", +".C c #a7a7a7", +"#r c #a8a8a8", +"#g c #ababab", +".n c #b2b2b2", +".m c #b4b4b4", +"aq c #b6b6b6", +"ai c #b8b8b8", +"#. c #b9b9b9", +"#N c #bababa", +"ap c #bbbbbb", +".R c #bcbcbc", +"ab c #bdbdbd", +"#F c #bfbfbf", +".B c #c1c1c1", +".5 c #c2c2c2", +"#z c #c5c5c5", +"#I c #c6c6c6", +"ag c #c7c7c7", +"aa c #c8c8c8", +".A c #c9c9c9", +".w c #cacaca", +"#5 c #cbcbcb", +".X c #cccccc", +"ah c #cdcdcd", +".z c #cecece", +".x c #cfcfcf", +".y c #d0d0d0", +"#R c #d1d1d1", +".Q c #d2d2d2", +".J c #d3d3d3", +"#Z c #d4d4d4", +"a# c #d5d5d5", +"## c #d6d6d6", +".Y c #d7d7d7", +"#s c #d8d8d8", +"#W c #d9d9d9", +"#4 c #dadada", +".K c #dbdbdb", +"#v c #dcdcdc", +"#A c #dfdfdf", +"#M c #e0e0e0", +".4 c #e1e1e1", +"#3 c #e2e2e2", +"#J c #e3e3e3", +"#f c #e4e4e4", +".P c #e5e5e5", +"#n c #e6e6e6", +".L c #e7e7e7", +"#Y c #e9e9e9", +"#L c #eaeaea", +"#X c #ebebeb", +"#e c #ececec", +"#E c #ededed", +"#m c #eeeeee", +".M c #efefef", +".3 c #f0f0f0", +".O c #f1f1f1", +"#d c #f2f2f2", +".N c #f3f3f3", +"#u c #f4f4f4", +".Z c #f5f5f5", +"#t c #f6f6f6", +".2 c #f8f8f8", +"#a c #f9f9f9", +".0 c #fafafa", +".1 c #fbfbfb", +"#c c #fcfcfc", +"#b c #fdfdfd", +"#l c #fefefe", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQt.#.a.b.c.d.e.f.gQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQt.h.i.j.k.l.m.n.o.p.q.r.sQtQtQtQtQtQtQtQt", +"QtQtQt.t.u.v.m.w.x.y.z.A.B.C.D.E.FQtQtQtQtQtQtQt", +"QtQt.G.H.I.w.J.K.L.M.N.O.P.Q.R.S.T.UQtQtQtQtQtQt", +"QtQt.V.W.X.Y.P.Z.0.1.0.2.Z.3.4.5.6.7QtQtQtQtQtQt", +"Qt.8.9#.##.L#a.1#b#b#c.1.2#d#e#f#g#h#iQtQtQtQtQt", +"Qt#j#k.Q.4.Z.0#b#l#l#b#c#a.Z#m#n.K#o#pQtQtQtQtQt", +"Qt#q#r#s#m#t#a#c#l#l#b.1.2#u#m#n#v#w#xQtQtQtQtQt", +"Qt#y#z#A.M.Z#B#B#C#C#C#B.6#D#E.P.K#F#GQtQtQtQtQt", +"Qt#H#I#J#e#d.6#B#B#B#B.6#D#K#L#M.Y#N#OQtQtQtQtQt", +"Qt#P#Q.4.L#E.O#u#t#t.Z.N.M#e#f.K#R#S#TQtQtQtQtQt", +"Qt#U#V#W.4#n#X#m.M.M#m#E#Y#f.K#Z.w.D#0QtQtQtQtQt", +"Qt#1#2.m#s#v#3.P#n#n.L#J#A#4#Z#5.l#6#7QtQtQtQtQt", +"Qt#8#9a..X.Q#Z#4.K#4.K#sa#.yaaabacadQtQtQtQtQtQt", +"QtQtae#Oaf.5ag#5.Xah#5#5aa.5ai#CajakQtQtQtQtQtQt", +"QtQt#8alamanaoapab.R.R.RaqarasajatauavQtQtQtQtQt", +"QtQtQt#8awaxay#KazaAaAaBaCaDadawaEaFaGaEaHQtQtQt", +"QtQtQtQtQt#8#7#0aIajajaI#0#7aJ#8#8aKaLaMataJQtQt", +"QtQtQtQtQtQtQt#8#8#8#8#8#8#8QtQt#8aNaOaPauaM#8Qt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt#8aGaQaRaGaS#8", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt#8#8aTaOaUaS#8", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt#8#8aVaWaX#8", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt#8#8#8QtQt"}; -- 2.34.1