/* This file is part of GNUnet (C) 2004, 2005, 2006 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet 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 GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Portions of this code were adopted from the gnome-system-monitor v2.0.5, (C) 2001 Kevin Vandersloot */ #include "platform.h" #include "gnunetgtk_common.h" #include #include #include "functions.h" #define MAX_COLOR 5 #define GNOME_PAD_SMALL 2 #define FRAME_WIDTH 0 typedef struct { gint type; guint count; guint speed; guint draw_width, draw_height; guint num_points; guint allocated; GdkColor *colors; gfloat **data; gfloat **odata; guint data_size; gint colors_allocated; GtkWidget *main_widget; GtkWidget *disp; GtkWidget *label; GdkPixmap *pixmap; GdkGC *gc; int timer_index; gboolean draw; int statIdx; } LoadGraph; typedef struct { GdkColor bg_color; GdkColor frame_color; GdkColor mem_color[MAX_COLOR]; } ProcConfig; static unsigned long long UPDATE_INTERVAL; /** * Redraws the backing pixmap for the load graph and updates the window */ static void load_graph_draw(LoadGraph *g) { guint i; guint j; gint dely; float delx; float max; GdkFont * font; if (!g->disp->window) return; g->draw_width = g->disp->allocation.width; g->draw_height = g->disp->allocation.height; if (!g->pixmap) g->pixmap = gdk_pixmap_new (g->disp->window, g->draw_width, g->draw_height, gtk_widget_get_visual (g->disp)->depth); /* Create GC if necessary. */ if (!g->gc) { g->gc = gdk_gc_new (g->disp->window); gdk_gc_copy (g->gc, g->disp->style->white_gc); } /* Allocate colors. */ if (!g->colors_allocated) { GdkColormap *colormap; colormap = gdk_window_get_colormap (g->disp->window); for (i=0;i<2+g->count;i++) gdk_color_alloc (colormap, &(g->colors [i])); g->colors_allocated = 1; } /* Erase Rectangle */ gdk_gc_set_foreground (g->gc, &(g->colors [0])); gdk_draw_rectangle (g->pixmap, g->gc, TRUE, 0, 0, g->disp->allocation.width, g->disp->allocation.height); /* draw frame */ gdk_gc_set_foreground (g->gc, &(g->colors [1])); gdk_draw_rectangle (g->pixmap, g->gc, FALSE, 0, 0, g->draw_width, g->disp->allocation.height); max = 0.26; /* force showing at least the 25% line */ for (i = 0; i < g->num_points - 1; i++) for (j=0;jcount;j++) if (g->data[i][j] > max) max = g->data[i][j]; max = max * 1.01; /* leave top 1% free */ font = gdk_font_load("fixed"); /* deprecated, but pango is far more than what we need here -- fix later? */ /* draw lines at 25%, 50%, 75% and 100% of max */ dely = g->draw_height / max / 4; for (i = 1; i < 5; i++) { gint y1 = g->draw_height + 1 - i * dely; if ( (dely < 30) && (i != 4) ) continue; /* only print additional lines if there is enough space! */ if (y1 > 0) { const gchar * label[] = { NULL, " 25%", " 50%", " 75%", "100%", }; gdk_draw_string(g->pixmap, font, g->gc, 10, y1 - 8, label[i]); gdk_draw_line (g->pixmap, g->gc, 0, y1, g->draw_width, y1); if (i == 4) { /* extra-thick line at 100% */ gdk_draw_line (g->pixmap, g->gc, 0, y1 - 1, g->draw_width, y1 - 1); gdk_draw_line (g->pixmap, g->gc, 0, y1 + 1, g->draw_width, y1 + 1); } } } gdk_gc_set_line_attributes(g->gc, 2, GDK_LINE_SOLID, GDK_CAP_ROUND, GDK_JOIN_MITER); delx = (float)g->draw_width / ( g->num_points - 1); for (j=0;jcount;j++) { gdk_gc_set_foreground (g->gc, &(g->colors [j + 2])); for (i = 0; i < g->num_points - 1; i++) { gint x1 = i * delx; gint x2 = (i + 1) * delx; gint y1 = g->data[i][j] / max * g->draw_height - 1; gint y2 = g->data[i+1][j] / max * g->draw_height - 1; if ((g->data[i][j] != -1) && (g->data[i+1][j] != -1)) { if (stats[g->statIdx].fill == NO) { gdk_draw_line(g->pixmap, g->gc, g->draw_width - x2, g->draw_height - y2, g->draw_width - x1, g->draw_height - y1); } else { GdkPoint points[4]; points[0].x = g->draw_width - x2; points[0].y = g->draw_height - y2; points[1].x = g->draw_width - x1; points[1].y = g->draw_height - y1; points[2].x = g->draw_width - x1; points[3].x = g->draw_width - x2; if (j == 0) { points[2].y = g->draw_height; points[3].y = g->draw_height; } else { gint ly1 = g->data[i][j-1] / max * g->draw_height - 1; gint ly2 = g->data[i+1][j-1] / max * g->draw_height - 1; points[2].y = g->draw_height - ly1; points[3].y = g->draw_height - ly2; } gdk_draw_polygon(g->pixmap, g->gc, 1, points, 4); } } } } gdk_gc_set_line_attributes (g->gc, 1, GDK_LINE_SOLID, GDK_CAP_ROUND, GDK_JOIN_MITER ); gdk_draw_pixmap (g->disp->window, g->disp->style->fg_gc [GTK_WIDGET_STATE(g->disp)], g->pixmap, 0, 0, 0, 0, g->disp->allocation.width, g->disp->allocation.height); } /* Updates the load graph when the timeout expires */ static gboolean load_graph_update(gpointer ptr) { LoadGraph *g = ptr; guint i; guint j; for (i=0;inum_points;i++) memcpy(g->odata[i], g->data[i], g->data_size * g->count); stats[g->statIdx].getData(stats[g->statIdx].get_closure, g->data); for (i=0;inum_points-1;i++) for (j=0;jcount;j++) g->data[i+1][j] = g->odata[i][j]; if (g->draw) load_graph_draw (g); return TRUE; } static void load_graph_unalloc(LoadGraph *g) { int i; if (!g->allocated) return; for (i = 0; i < g->num_points; i++) { FREE(g->data[i]); FREE(g->odata[i]); } FREE(g->data); FREE(g->odata); g->data = g->odata = NULL; if (g->pixmap) { gdk_pixmap_unref(g->pixmap); g->pixmap = NULL; } g->allocated = FALSE; } static void load_graph_alloc (LoadGraph *g) { int i; int j; if (g->allocated) return; g->data = MALLOC(sizeof(gfloat *) * g->num_points); g->odata = MALLOC(sizeof(gfloat*) * g->num_points); g->data_size = sizeof (gfloat); for (i = 0; i < g->num_points; i++) { g->data[i] = MALLOC(g->data_size * g->count); g->odata[i] = MALLOC(g->data_size * g->count); } for (i=0;inum_points;i++) for (j=0;jcount;j++) g->data[i][j] = -1; g->allocated = TRUE; } static gint load_graph_configure(GtkWidget *widget, GdkEventConfigure *event, gpointer data_ptr) { LoadGraph *c = (LoadGraph *) data_ptr; if (c->pixmap) { gdk_pixmap_unref (c->pixmap); c->pixmap = NULL; } if (!c->pixmap) c->pixmap = gdk_pixmap_new(widget->window, widget->allocation.width, widget->allocation.height, gtk_widget_get_visual (c->disp)->depth); gdk_draw_rectangle(c->pixmap, widget->style->black_gc, TRUE, 0,0, widget->allocation.width, widget->allocation.height); gdk_draw_pixmap(widget->window, c->disp->style->fg_gc[GTK_WIDGET_STATE(widget)], c->pixmap, 0, 0, 0, 0, c->disp->allocation.width, c->disp->allocation.height); load_graph_draw(c); return TRUE; } static gint load_graph_expose(GtkWidget *widget, GdkEventExpose *event, gpointer data_ptr) { LoadGraph *g = (LoadGraph *) data_ptr; gdk_draw_pixmap(widget->window, widget->style->fg_gc [GTK_WIDGET_STATE(widget)], g->pixmap, event->area.x, event->area.y, event->area.x, event->area.y, event->area.width, event->area.height); return FALSE; } static void load_graph_stop (LoadGraph *g) { if (g->timer_index != -1) { gtk_timeout_remove(g->timer_index); g->timer_index = -1; } if (!g) return; g->draw = FALSE; } static void load_graph_destroy(GtkWidget *widget, gpointer data_ptr) { LoadGraph *g = (LoadGraph *) data_ptr; load_graph_stop(g); if (g->timer_index != -1) gtk_timeout_remove (g->timer_index); load_graph_unalloc(g); FREE(g->colors); FREE(g); } static LoadGraph * load_graph_new(int statIdx, const ProcConfig * config) { LoadGraph *g; unsigned int i; if (stats[statIdx].count > MAX_COLOR) { GE_BREAK(NULL, 0); return NULL; } g = MALLOC(sizeof(LoadGraph)); g->statIdx = statIdx; g->count = stats[statIdx].count; g->speed = UPDATE_INTERVAL / cronMILLIS; g->num_points = 600; g->colors = MALLOC(sizeof(GdkColor) * (2+g->count)); g->colors[0] = config->bg_color; g->colors[1] = config->frame_color; for (i=0;icount;i++) g->colors[2+i] = config->mem_color[i]; g->timer_index = -1; g->draw = FALSE; g->main_widget = gtk_vbox_new (FALSE, FALSE); gtk_widget_show(g->main_widget); g->disp = gtk_drawing_area_new(); gtk_widget_show (g->disp); gtk_signal_connect(GTK_OBJECT (g->disp), "expose_event", GTK_SIGNAL_FUNC (load_graph_expose), g); gtk_signal_connect(GTK_OBJECT(g->disp), "configure_event", GTK_SIGNAL_FUNC (load_graph_configure), g); gtk_signal_connect(GTK_OBJECT(g->disp), "destroy", GTK_SIGNAL_FUNC (load_graph_destroy), g); gtk_widget_add_events(g->disp, GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK); gtk_box_pack_start(GTK_BOX(g->main_widget), g->disp, TRUE, TRUE, 0); load_graph_alloc(g); gtk_widget_show_all(g->main_widget); g->timer_index = gtk_timeout_add(g->speed, &load_graph_update, g); return g; } static GtkWidget * create_sys_view(int statIdx, const ProcConfig * config) { GtkWidget * mem_frame; LoadGraph * mem_graph; mem_graph = load_graph_new(statIdx, config); if (mem_graph == NULL) return NULL; /* oops */ mem_frame = gtk_frame_new(_(stats[statIdx].frameName)); gtk_container_add(GTK_CONTAINER(mem_frame), mem_graph->main_widget); gtk_container_set_border_width(GTK_CONTAINER(mem_graph->main_widget), GNOME_PAD_SMALL); gtk_container_set_border_width(GTK_CONTAINER(mem_frame), GNOME_PAD_SMALL); gtk_widget_show(mem_frame); if (mem_graph->timer_index == -1) mem_graph->timer_index = gtk_timeout_add(mem_graph->speed, &load_graph_update, mem_graph); mem_graph->draw = TRUE; return mem_frame; } void init_stats(struct GE_Context * ectx, struct GC_Configuration * cfg) { GtkWidget * sys_box; GtkWidget * label; GtkWidget * notebook; ProcConfig config; int i; GC_get_configuration_value_number(cfg, "GNUNET-GTK", "STATS-INTERVAL", 1, 99 * cronYEARS, 30 * cronSECONDS, &UPDATE_INTERVAL); init_functions(ectx, cfg); notebook = glade_xml_get_widget(getMainXML(), "statsNotebook"); memset(&config, 0, sizeof(ProcConfig)); gdk_color_parse("black", &config.bg_color); gdk_color_parse("gray", &config.frame_color); gdk_color_parse("red", &config.mem_color[0]); gdk_color_parse("green", &config.mem_color[1]); gdk_color_parse("yellow", &config.mem_color[2]); gdk_color_parse("blue", &config.mem_color[3]); gdk_color_parse("gray", &config.mem_color[4]); GE_ASSERT(ectx, MAX_COLOR == 5); i = -1; while (stats[++i].paneName != NULL) { sys_box = create_sys_view(i, &config); if (sys_box == NULL) continue; /* oops */ label = gtk_label_new(gettext(stats[i].paneName)); gtk_notebook_append_page(GTK_NOTEBOOK(notebook), sys_box, label); } gtk_widget_show(notebook); } void done_stats() { done_functions(); } /* end of statistics.c */