+/*
+ interface.c -- GTK+/GNOME interface functions
+ Copyright (C) 2002 Guus Sliepen <guus@sliepen.warande.net>,
+ 2002 Ivo Timmermans <ivo@o2w.nl>
+
+ This program 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 of the License, or
+ (at your option) any later version.
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ $Id: interface.c,v 1.5 2002/05/02 11:50:07 zarq Exp $
+*/
+
#include "config.h"
+#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <sys/time.h>
+
+#define log mathlog
#include <math.h>
+#undef log
#include <gtk/gtk.h>
#include <glade/glade.h>
#include <libgnomeui/gnome-canvas-util.h>
#include "node.h"
+#include "connection.h"
#include "edge.h"
#include "interface.h"
+#include "logging.h"
+#include <hooks.h>
#include <xalloc.h>
#include "system.h"
-extern GladeXML *xml;
+/* Node tree & main window stuff */
+static GladeXML *xml;
+static GtkWidget *nodetree;
+static GtkCTreeNode *hosts_ctn;
-#ifdef MAXBUFSIZE
-#undef MAXBUFSIZE
-#endif
-#define MAXBUFSIZE 1024
+/* Graph canvas stuff */
+static GladeXML *canvas_xml;
+
+static GnomeCanvasGroup *edge_group = NULL;
+
+static int canvas_width;
+static int canvas_height;
+
+static GtkWidget *canvas = NULL;
+
+static int canvas_visible = 0;
int build_graph = 0;
double k[MAX_NODES][MAX_NODES];
double d[MAX_NODES][MAX_NODES];
double l[MAX_NODES][MAX_NODES];
-const double epsilon = 0.001;
+static const double epsilon = 0.001;
static int inited = 0;
static int number_of_nodes = 0;
-static GtkWidget *nodetree;
-static GtkCTreeNode *subnets_ctn, *hosts_ctn, *conns_ctn;
+static double canvas_zoom = 1.00;
-static GnomeCanvasGroup *edge_group = NULL;
-static int canvas_width;
-static int canvas_height;
+/* Log window stuff */
+#ifdef MAXBUFSIZE
+#undef MAXBUFSIZE
+#endif
-static GtkWidget *canvas = NULL;
+#define MAXBUFSIZE 1024
+
+static int log_inited = 0;
+static int follow_log = 1;
+
+static int keep_drawing = 1;
+
+static int log_visible = 0;
+static GtkWidget *log_window = NULL;
+
+
+void if_node_add(const char *hooktype, va_list ap);
+void if_node_del(const char *hooktype, va_list ap);
+void if_subnet_add(const char *hooktype, va_list ap);
+void if_subnet_del(const char *hooktype, va_list ap);
+void if_edge_add(const char *hooktype, va_list ap);
+void if_edge_del(const char *hooktype, va_list ap);
+void if_node_visible(const char *hooktype, va_list ap);
+void if_node_invisible(const char *hooktype, va_list ap);
+
+void if_node_create(node_t *n);
GtkWidget *create_canvas(void)
{
- GtkWidget *w;
-
- gtk_widget_push_visual(gdk_rgb_get_visual());
- gtk_widget_push_colormap(gdk_rgb_get_cmap());
-
- canvas = gnome_canvas_new_aa();
-
- gtk_widget_pop_visual();
- gtk_widget_pop_colormap();
-
- gnome_canvas_set_scroll_region(GNOME_CANVAS(canvas), 0, 0, 500, 300);
+ canvas_xml = glade_xml_new(INTERFACE_FILE, "GraphWindow");
+ if(!canvas_xml)
+ {
+ log(0, TLOG_ERROR,
+ _("Could not find widget `%s'"),
+ "GraphWindow");
+ return NULL;
+ }
- w = glade_xml_get_widget(xml, "scrolledwindow3");
- if(!w)
+ canvas = glade_xml_get_widget(xml, "canvas1");
+ if(!canvas)
{
- fprintf(stderr, "Could not find widget `scrolledwindow3'\n");
+ fprintf(stderr, "Could not find widget `canvas1'\n");
return NULL;
}
- gtk_container_add(GTK_CONTAINER(w), canvas);
- gtk_widget_show_all(w);
+
+ gnome_canvas_set_scroll_region(GNOME_CANVAS(canvas), 0.0, 0.0, 700, 500);
canvas_width = 300.0;
canvas_height = 500.0;
return canvas;
}
-int init_interface(void)
+void log_gtk(int level, int priority, char *fmt, va_list ap)
{
- char *l[1];
- GtkArg p;
-
- if(!xml)
- return -1;
-
- nodetree = glade_xml_get_widget(xml, "NodeTree");
- if(!nodetree)
- {
- fprintf(stderr, _("Could not find widget `NodeTree'\n"));
- return -1;
- }
-
- gtk_clist_freeze(GTK_CLIST(nodetree));
-
- l[0] = _("Hosts");
- hosts_ctn = gtk_ctree_insert_node(GTK_CTREE(nodetree),
- NULL, NULL, l, 1,
- NULL, NULL, NULL, NULL,
- FALSE, TRUE);
- l[0] = _("Subnets");
- subnets_ctn = gtk_ctree_insert_node(GTK_CTREE(nodetree),
- NULL, NULL, l, 1,
- NULL, NULL, NULL, NULL,
- FALSE, TRUE);
- l[0] = _("Connections");
- conns_ctn = gtk_ctree_insert_node(GTK_CTREE(nodetree),
- NULL, NULL, l, 1,
- NULL, NULL, NULL, NULL,
- FALSE, TRUE);
-
- gtk_clist_thaw(GTK_CLIST(nodetree));
-
- create_canvas();
-
- return 0;
-}
-
-void log_message(int severity, const char *fmt, ...)
-{
- va_list args;
char buffer1[MAXBUFSIZE];
char buffer2[MAXBUFSIZE];
- GtkWidget *w;
int len;
char *p;
struct tm *tm;
time_t t;
- static int inited = 0;
- if(!xml)
- return;
-
- w = glade_xml_get_widget(xml, "Messages");
- if(!w)
+ if(!log_visible)
return;
/* Use vsnprintf instead of vasprintf: faster, no memory
fragmentation, cleanup is automatic, and there is a limit on the
input buffer anyway */
- va_start(args, fmt);
- len = vsnprintf(buffer1, MAXBUFSIZE, fmt, args);
- va_end(args);
+ len = vsnprintf(buffer1, MAXBUFSIZE, fmt, ap);
buffer1[MAXBUFSIZE-1] = '\0';
if((p = strrchr(buffer1, '\n')))
}
}
- gtk_text_freeze(GTK_TEXT(w));
+ gtk_text_freeze(GTK_TEXT(log_window));
+
+ if(log_inited)
+ gtk_text_insert(GTK_TEXT(log_window), NULL, NULL, NULL, "\n", 1);
+
+ gtk_text_insert(GTK_TEXT(log_window), NULL, &timecolor, NULL, buffer2, strlen(buffer2));
+ gtk_text_insert(GTK_TEXT(log_window), NULL, NULL, NULL, buffer1, len);
+ gtk_text_thaw(GTK_TEXT(log_window));
+
+ log_inited = 1;
+ if(follow_log)
+/* gtk_text_set_point(GTK_TEXT(w), -1); */
+ gtk_editable_set_position(GTK_EDITABLE(log_window), gtk_text_get_length(GTK_TEXT(log_window)));
+}
+
+void if_hostinfoclosebutton_clicked(GtkWidget *w, gpointer data)
+{
+ gtk_widget_destroy(GTK_WIDGET(data));
+}
+
+void update_hostinfo_dialog(GladeXML *x, node_t *n)
+{
+ GtkWidget *w;
+ char s[100];
+ avl_node_t *avlnode;
+ char *l[1];
+
+ w = glade_xml_get_widget(x, "HostInfoNameEntry");
+ if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "HostInfoNameEntry"); return; }
+ gtk_entry_set_text(GTK_ENTRY(w), n->name);
+
+ w = glade_xml_get_widget(x, "HostInfoHostnameEntry");
+ if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "HostInfoHostnameEntry"); return; }
+ gtk_entry_set_text(GTK_ENTRY(w), n->hostname);
+
+ w = glade_xml_get_widget(x, "HostInfoPortEntry");
+ if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "HostInfoPortEntry"); return; }
+/* snprintf(s, sizeof(s)-1, "%hd", "0"); */
+ gtk_entry_set_text(GTK_ENTRY(w), "port");
+
+ w = glade_xml_get_widget(x, "HostInfoVersionEntry");
+ if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "HostInfoVersionEntry"); return; }
+ gtk_entry_set_text(GTK_ENTRY(w), n->name);
+
+ w = glade_xml_get_widget(x, "HostInfoStatusEntry");
+ if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "HostInfoStatusEntry"); return; }
+/* snprintf(s, sizeof(s)-1, "%x", n->status); */
+ gtk_entry_set_text(GTK_ENTRY(w), "0");
+
+ w = glade_xml_get_widget(x, "HostInfoActiveCheckbutton");
+ if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "HostInfoActiveCheckbutton"); return; }
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), n->status.active);
+
+ w = glade_xml_get_widget(x, "HostInfoValidkeyCheckbutton");
+ if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "HostInfoValidkeyCheckbutton"); return; }
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), n->status.validkey);
+
+ w = glade_xml_get_widget(x, "HostInfoWaitingforkeyCheckbutton");
+ if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "HostInfoWaitingforkeyCheckbutton"); return; }
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), n->status.waitingforkey);
+
+ w = glade_xml_get_widget(x, "HostInfoVisitedCheckbutton");
+ if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "HostInfoVisitedCheckbutton"); return; }
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), n->status.visited);
+
+ w = glade_xml_get_widget(x, "HostInfoReachableCheckbutton");
+ if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "HostInfoReachableCheckbutton"); return; }
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), n->status.reachable);
+
+ w = glade_xml_get_widget(x, "HostInfoIndirectCheckbutton");
+ if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "HostInfoIndirectCheckbutton"); return; }
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), n->status.indirect);
+
+ w = glade_xml_get_widget(x, "HostInfoVisibleCheckbutton");
+ if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "HostInfoVisibleCheckbutton"); return; }
+/* gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), n->status.visible); */
+
+ w = glade_xml_get_widget(x, "HostInfoTCPOnlyCheckbutton");
+ if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "HostInfoTCPOnlyCheckbutton"); return; }
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), (n->options & OPTION_TCPONLY) != 0);
+
+ w = glade_xml_get_widget(x, "HostInfoIndirectdataCheckbutton");
+ if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "HostInfoIndirectdataCheckbutton"); return; }
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), (n->options & OPTION_INDIRECT) != 0);
+
+/* w = glade_xml_get_widget(x, "HostInfoWindow"); */
+/* if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "HostInfoWindow"); return; } */
+/* glade_xml_signal_connect_data(x, "on_HostInfoCloseButton_clicked", if_hostinfoclosebutton_clicked, (gpointer)w); */
+ w = glade_xml_get_widget(x, "HostConnectionsCList");
+ if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "HostConnectionsCList"); return; }
+ for(avlnode = n->edge_tree->head; avlnode; avlnode = avlnode->next)
+ {
+ if(((edge_t*)(avlnode->data))->to.node == n)
+ l[0] = ((edge_t*)(avlnode->data))->from.node->name;
+ else
+ l[0] = ((edge_t*)(avlnode->data))->to.node->name;
+ gtk_clist_append(GTK_CLIST(w), l);
+ }
+}
+
+void on_preferences1_activate(GtkMenuItem *mi, gpointer data)
+{
+ GtkWidget *w;
+ GladeXML *x;
+
+ x = glade_xml_new(INTERFACE_FILE, "PropertyBox");
+ if(x == NULL)
+ {
+ log(0, TLOG_ERROR,
+ _("Could not find widget `%s'"),
+ "PropertyBox");
+ return;
+ }
+
+ w = glade_xml_get_widget(x, "PropertyBox");
+ if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "PropertyBox"); return; }
+ glade_xml_signal_autoconnect(x);
+}
+
+void on_logcontext_clear_activate(GtkMenuItem *mi, gpointer data)
+{
+ gtk_editable_delete_text(GTK_EDITABLE(log_window), 0, -1); /* Delete from 0 to end of buffer */
+ log_inited = 0;
+}
+
+void on_logcontext_follow_activate(GtkMenuItem *mi, gpointer data)
+{
+ follow_log = !follow_log;
+}
+
+void on_logcontext_close1_activate(GtkMenuItem *mi, gpointer data)
+{
+
+}
+
+void on_messages_button_press_event(GtkWidget *w, GdkEventButton *event, gpointer data)
+{
+ GladeXML *x;
+ GtkWidget *menu;
+
+ if (event->button == 3)
+ {
+ x = glade_xml_new(INTERFACE_FILE, "LogContextMenu");
+ if(x == NULL)
+ {
+ log(0, TLOG_ERROR,
+ _("Could not find widget `%s'"),
+ "LogContextMenu");
+ return;
+ }
+
+ menu = glade_xml_get_widget(x, "LogContextMenu");
+ if(!menu) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "LogContextMenu"); return; }
+
+ glade_xml_signal_connect_data(x, "on_logcontext_clear_activate", on_logcontext_clear_activate, (gpointer)x);
+ glade_xml_signal_connect_data(x, "on_logcontext_follow_activate", on_logcontext_follow_activate, (gpointer)x);
+ w = glade_xml_get_widget(x, "LogContextFollow");
+ if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "LogContextFollow"); return; }
+ GTK_CHECK_MENU_ITEM(w)->active = follow_log;
+ gnome_popup_menu_do_popup_modal(menu, NULL, NULL, event, NULL);
+ gtk_widget_destroy(menu);
+ }
+}
+
+void shuffle_nodes(void)
+{
+ avl_node_t *avlnode;
+ double newx, newy;
+
+ for(avlnode = node_tree->head; avlnode; avlnode = avlnode->next)
+ {
+ newx = ((double)random()) / ((double)RAND_MAX) * 500.0;
+ newy = ((double)random()) / ((double)RAND_MAX) * 300.0;
+ ((struct if_node_data*)((node_t *)(avlnode->data))->data)->x = newx;
+ ((struct if_node_data*)((node_t *)(avlnode->data))->data)->y = newy;
+
+ if(!((struct if_node_data*)((node_t*)(avlnode->data)))->visible)
+ continue;
+
+ x[((struct if_node_data*)((node_t*)(avlnode->data))->data)->id] = newx;
+ y[((struct if_node_data*)((node_t*)(avlnode->data))->data)->id] = newy;
+ }
+ inited = 0;
+ build_graph = 1;
+}
+
+void on_canvascontext_shuffle_activate(GtkMenuItem *mi, gpointer data)
+{
+ shuffle_nodes();
+}
+
+void on_canvascontext_keep_drawing_activate(GtkMenuItem *mi, gpointer data)
+{
+ GtkWidget *w;
+
+ keep_drawing = !keep_drawing;
+
+ /* No need to fuss with the checkbox in the menu, because that is
+ transient. Do need to update the checkbox at the bottom of the
+ window though. */
+ w = glade_xml_get_widget(canvas_xml, "KeepDrawingButton");
+ if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "KeepDrawingButton"); return; }
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), keep_drawing);
+}
+
+void on_canvascontext_minus50_activate(GtkMenuItem *mi, gpointer data)
+{
+ canvas_zoom *= 0.50;
+ gnome_canvas_set_pixels_per_unit(GNOME_CANVAS(canvas), canvas_zoom);
+}
+
+void on_canvascontext_minus25_activate(GtkMenuItem *mi, gpointer data)
+{
+ canvas_zoom *= 0.75;
+ gnome_canvas_set_pixels_per_unit(GNOME_CANVAS(canvas), canvas_zoom);
+}
+
+void on_canvascontext_minus10_activate(GtkMenuItem *mi, gpointer data)
+{
+ canvas_zoom *= 0.90;
+ gnome_canvas_set_pixels_per_unit(GNOME_CANVAS(canvas), canvas_zoom);
+}
+
+void on_canvascontext_default_activate(GtkMenuItem *mi, gpointer data)
+{
+ canvas_zoom = 1.00;
+ gnome_canvas_set_pixels_per_unit(GNOME_CANVAS(canvas), 1.00);
+}
+
+void on_canvascontext_plus10_activate(GtkMenuItem *mi, gpointer data)
+{
+ canvas_zoom *= 1.10;
+ gnome_canvas_set_pixels_per_unit(GNOME_CANVAS(canvas), canvas_zoom);
+}
+
+void on_canvascontext_plus25_activate(GtkMenuItem *mi, gpointer data)
+{
+ canvas_zoom *= 1.25;
+ gnome_canvas_set_pixels_per_unit(GNOME_CANVAS(canvas), canvas_zoom);
+}
+
+void on_canvascontext_plus50_activate(GtkMenuItem *mi, gpointer data)
+{
+ canvas_zoom *= 1.50;
+ gnome_canvas_set_pixels_per_unit(GNOME_CANVAS(canvas), canvas_zoom);
+}
+
+void on_canvas_button_press_event(GtkWidget *w, GdkEventButton *event, gpointer data)
+{
+ GladeXML *x;
+ GtkWidget *menu;
+
+ if (event->button == 3)
+ {
+ x = glade_xml_new(INTERFACE_FILE, "CanvasContextMenu");
+ if(x == NULL)
+ {
+ log(0, TLOG_ERROR,
+ _("Could not find widget `%s'"),
+ "CanvasContextMenu");
+ return;
+ }
+
+ menu = glade_xml_get_widget(x, "CanvasContextMenu");
+ if(!menu) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "CanvasContextMenu"); return; }
+
+ glade_xml_signal_autoconnect(x);
+ glade_xml_signal_connect_data(x, "on_canvascontext_shuffle_activate", on_canvascontext_shuffle_activate, (gpointer)x);
+ glade_xml_signal_connect_data(x, "on_canvascontext_keep_drawing_activate", on_canvascontext_keep_drawing_activate, (gpointer)x);
+ w = glade_xml_get_widget(x, "CanvasContextKeepDrawing");
+ if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "CanvasContextKeepDrawing"); return; }
+ GTK_CHECK_MENU_ITEM(w)->active = keep_drawing;
+ gnome_popup_menu_do_popup_modal(menu, NULL, NULL, event, NULL);
+ gtk_widget_destroy(menu);
+ }
+}
+
+void on_nodetree_button_press_event(GtkWidget *w, GdkEventButton *event, gpointer data)
+{
+ GtkCTreeNode *node;
+ int row, col;
+ gpointer lt;
+ GladeXML *x;
+
+ gtk_clist_get_selection_info(GTK_CLIST(w), event->x, event->y,
+ &row, &col);
+
+ node = gtk_ctree_node_nth(GTK_CTREE(w), row);
+ if(node == NULL)
+ return;
+ lt = gtk_ctree_node_get_row_data(GTK_CTREE(w), node);
+ if(event->type == GDK_2BUTTON_PRESS && event->button == 1)
+ {
+ /* Double left click on an item */
+ if(lt == NULL)
+ /* this is only a branch, double click wil (un)expand. */
+ return;
+
+ if(GTK_CTREE_ROW(node)->parent == hosts_ctn)
+ {
+ x = ((struct if_node_data*)(((node_t*)lt)->data))->hi_xml = glade_xml_new(INTERFACE_FILE, "HostInfoWindow");
+ if(x == NULL)
+ {
+ log(0, TLOG_ERROR,
+ _("Could not find widget `%s'"),
+ "HostInfoWindow");
+ return;
+ }
+ glade_xml_signal_autoconnect(x);
+ update_hostinfo_dialog(x, (node_t*)lt);
+ }
+ else
+ {
+ log(0, TLOG_ERROR,
+ "WHERE did you click?!");
+ }
+ /* so now we have access to all the data we want. */
+/* gldap_show_details(lt); */
+ return;
+ }
+/* else */
+/* if (event->button == 3) */
+/* { */
+/* GtkWidget *temp_menu; */
+/* temp_menu = gnome_popup_menu_new(data); */
+/* gnome_popup_menu_do_popup_modal(temp_menu, NULL, NULL, event, NULL); */
+/* gtk_widget_destroy(temp_menu); */
+/* } */
+}
+
+void on_exit1_activate(GtkMenuItem *mi, gpointer data)
+{
+ close_network_connections();
+ gtk_exit(0);
+}
+
+void on_about1_activate(GtkMenuItem *mi, gpointer data)
+{
+ GladeXML *x;
+ x = glade_xml_new(INTERFACE_FILE, "AboutWindow");
+ if(x == NULL)
+ {
+ log(0, TLOG_ERROR,
+ _("Could not find widget `%s'"),
+ "AboutWindow");
+ return;
+ }
+ glade_xml_signal_autoconnect(x);
+}
+
+void on_graph_window1_activate(GtkMenuItem *mi, gpointer data)
+{
+ int i;
+ avl_node_t *avlnode;
+ double newx, newy;
+
+ canvas_xml = glade_xml_new(INTERFACE_FILE, "GraphWindow");
+ if(canvas_xml == NULL)
+ {
+ log(0, TLOG_ERROR,
+ _("Could not find widget `%s'"),
+ "GraphWindow");
+ return;
+ }
+ glade_xml_signal_autoconnect(canvas_xml);
+ canvas = glade_xml_get_widget(canvas_xml, "canvas1");
+ if(canvas == NULL) { log(0, TLOG_ERROR, _("Could not find widget `%s'"), "canvas1"); return; }
+
+ for(i = 0, avlnode = node_tree->head; avlnode; avlnode = avlnode->next)
+ {
+ node_t *n = (node_t*)(avlnode->data);
+
+ if(!((struct if_node_data*)(n->data))->item)
+ if_node_create(n);
+
+ if(!n->status.reachable)
+ continue;
+
+ newx = 250.0 + 200.0 * sin(i / 10.0 * M_PI);
+ newy = 150.0 - 100.0 * cos(i / 10.0 * M_PI);
+ gnome_canvas_item_move(GNOME_CANVAS_ITEM(((struct if_node_data*)(n->data))->item), newx - ((struct if_node_data*)(n->data))->x, newy - ((struct if_node_data*)(n->data))->y);
+ ((struct if_node_data*)(n->data))->x = newx;
+ ((struct if_node_data*)(n->data))->y = newy;
+
+ ((struct if_node_data*)(n->data))->id = i;
+
+ gnome_canvas_item_show(GNOME_CANVAS_ITEM(((struct if_node_data*)(n->data))->item));
+ gnome_canvas_update_now(GNOME_CANVAS(canvas));
+ nodes[i] = n;
+ i++;
+ }
+
+ number_of_nodes = i;
+
+ inited = 0;
+ build_graph = 1;
+ canvas_visible = 1;
+}
+
+void on_log_window1_activate(GtkMenuItem *mi, gpointer data)
+{
+ GladeXML *x;
+ GtkWidget *w;
+
+ x = glade_xml_new(INTERFACE_FILE, "LogWindow");
+ if(x == NULL)
+ {
+ log(0, TLOG_ERROR,
+ _("Could not find widget `%s'"),
+ "LogWindow");
+ return;
+ }
+ log_window = glade_xml_get_widget(x, "Messages");
+ if(!log_window)
+ {
+ log(0, TLOG_ERROR,
+ _("Could not find widget `%s'"),
+ "Messages");
+ return;
+ }
+ w = glade_xml_get_widget(x, "DebugLevelSpinbutton");
+ if(!w)
+ {
+ log(0, TLOG_ERROR,
+ _("Could not find widget `%s'"),
+ "DebugLevelSpinbutton");
+ return;
+ }
+ gtk_spin_button_set_value(GTK_SPIN_BUTTON(w), (float)debug_lvl);
+
+ glade_xml_signal_autoconnect(x);
+ log_visible = 1;
+ log_add_hook(log_gtk);
+ log(0, TLOG_NOTICE, "Logging started.\n");
+
+}
+
+void on_debug_level_changed(GtkSpinButton *sb, gpointer data)
+{
+ debug_lvl = gtk_spin_button_get_value_as_int(sb);
+}
+
+void on_logwindow_close_clicked(GtkButton *b, gpointer data)
+{
+ GladeXML *x;
+ GtkWidget *w;
+
+ x = glade_xml_new(INTERFACE_FILE, "LogWindow");
+ if(x == NULL)
+ {
+ log(0, TLOG_ERROR,
+ _("Could not find widget `%s'"),
+ "LogWindow");
+ return;
+ }
+ w = glade_xml_get_widget(x, "LogWindow");
+ if(!w)
+ {
+ log(0, TLOG_ERROR,
+ _("Could not find widget `%s'"),
+ "LogWindow");
+ return;
+ }
+ gtk_widget_destroy(w);
+}
+
+void on_spinbutton2_changed(GtkSpinButton *sb, gpointer data)
+{
+ canvas_zoom = gtk_spin_button_get_value_as_float(sb) / 100.0;
+ gnome_canvas_set_pixels_per_unit(GNOME_CANVAS(canvas), canvas_zoom);
+}
+
+void on_checkbutton1_toggled(GtkCheckButton *cb, gpointer data)
+{
+ keep_drawing = !keep_drawing;
+}
- if(inited)
- gtk_text_insert(GTK_TEXT(w), NULL, NULL, NULL, "\n", 1);
+void on_button19_clicked(GtkWidget *bt, GdkEventButton *ev, gpointer data)
+{
+ shuffle_nodes();
+}
- gtk_text_insert(GTK_TEXT(w), NULL, &timecolor, NULL, buffer2, strlen(buffer2));
- gtk_text_insert(GTK_TEXT(w), NULL, NULL, NULL, buffer1, len);
- gtk_text_thaw(GTK_TEXT(w));
+void on_button18_clicked(GtkWidget *bt, GdkEventButton *ev, gpointer data)
+{
+ GtkWidget *w;
- inited = 1;
+ w = glade_xml_get_widget(canvas_xml, "GraphWindow");
+ if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "GraphWindow"); return; }
+ gtk_object_destroy(GTK_OBJECT(w));
+ build_graph = 0;
+ canvas_visible = 0;
+}
+
+int init_interface(void)
+{
+ char *l[1];
+
+ glade_gnome_init();
+
+ xml = glade_xml_new("pokey.glade", "AppWindow");
+
+ if(!xml)
+ {
+ log(0, TLOG_ERROR,
+ _("Something bad happened while creating the interface.\n"));
+ return -1;
+ }
+
+ nodetree = glade_xml_get_widget(xml, "NodeTree");
+ if(!nodetree)
+ {
+ log(0, TLOG_ERROR,
+ _("Could not find widget `%s'"),
+ "NodeTree");
+ return -1;
+ }
+
+ gtk_clist_freeze(GTK_CLIST(nodetree));
+ l[0] = _("Hosts");
+ hosts_ctn = gtk_ctree_insert_node(GTK_CTREE(nodetree),
+ NULL, NULL, l, 1,
+ NULL, NULL, NULL, NULL,
+ FALSE, TRUE);
+ gtk_clist_thaw(GTK_CLIST(nodetree));
+
+ glade_xml_signal_autoconnect(xml);
+
+ log_del_hook(log_default);
+
+ add_hook("node-add", if_node_add);
+ add_hook("node-del", if_node_del);
+ add_hook("subnet-add", if_subnet_add);
+ add_hook("subnet-del", if_subnet_del);
+ add_hook("edge-add", if_edge_add);
+ add_hook("edge-del", if_edge_del);
+ add_hook("node-visible", if_node_visible);
+ add_hook("node-invisible", if_node_invisible);
+
+ return 0;
}
static gint item_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data)
gnome_canvas_item_ungrab(item, event->button.time);
dragging = FALSE;
n = (node_t *)gtk_object_get_user_data(GTK_OBJECT(item));
- n->x = item_x;
- n->y = item_y;
- x[n->id] = item_x;
- y[n->id] = item_y;
+ ((struct if_node_data*)(n->data))->x = item_x;
+ ((struct if_node_data*)(n->data))->y = item_y;
+ x[((struct if_node_data*)(n->data))->id] = item_x;
+ y[((struct if_node_data*)(n->data))->id] = item_y;
build_graph = 1;
break;
return FALSE;
}
-GtkCTreeNode *if_node_add(node_t *n)
+void if_node_create(node_t *n)
{
- char *l[1];
- GtkCTreeNode *ctn;
+ GnomeCanvasGroup *group;
+
+ group = gnome_canvas_root(GNOME_CANVAS(canvas));
+ group = GNOME_CANVAS_GROUP(gnome_canvas_item_new(group,
+ gnome_canvas_group_get_type(),
+ "x", 0.0,
+ "y", 0.0,
+ NULL));
+
+ gnome_canvas_item_new(group, gnome_canvas_ellipse_get_type(),
+ "x1", -30.0,
+ "y1", -08.0,
+ "x2", 30.0,
+ "y2", 08.0,
+ "fill_color_rgba", 0x5f9ea080,
+ "outline_color", "black",
+ "width_pixels", 0,
+ NULL);
+
+ gnome_canvas_item_new(group,
+ gnome_canvas_text_get_type(),
+ "x", 0.0,
+ "y", 0.0,
+ "text", n->name,
+ "anchor", GTK_ANCHOR_CENTER,
+ "fill_color", "white",
+ "font", "-*-verdana-medium-r-*-*-10-*-*-*-*-*-iso8859-1",
+ NULL);
+
+ ((struct if_node_data*)(n->data))->item = GNOME_CANVAS_ITEM(group);
+ ((struct if_node_data*)(n->data))->x = ((struct if_node_data*)(n->data))->y = 0.0;
+ gtk_object_set_user_data(GTK_OBJECT(group), (gpointer)n);
+
+ gtk_signal_connect(GTK_OBJECT(((struct if_node_data*)(n->data))->item), "event", (GtkSignalFunc) item_event, NULL);
- if(!xml)
- return NULL;
+ gnome_canvas_item_hide(GNOME_CANVAS_ITEM(((struct if_node_data*)(n->data))->item));
+}
- l[0] = n->name;
- gtk_clist_freeze(GTK_CLIST(nodetree));
- n->host_ctn = gtk_ctree_insert_node(GTK_CTREE(nodetree),
- hosts_ctn, NULL, l, 1,
- NULL, NULL, NULL, NULL,
- FALSE, FALSE);
- gtk_clist_thaw(GTK_CLIST(nodetree));
+void if_node_visible(const char *hooktype, va_list ap)
+{
+ int i;
+ avl_node_t *avlnode;
+ double newx, newy;
+ node_t *n = va_arg(ap, node_t*);
+
+ if(!n->data)
+ return;
+
+ if(!((struct if_node_data*)(n->data))->item)
+ /* No GnomeCanvasItem has been created for this node yet */
+ return;
+
+ if(((struct if_node_data*)(n->data))->visible)
+ /* This node is already shown */
+ return;
- if_graph_add_node(n);
+ ((struct if_node_data*)(n->data))->visible = 1;
+ newx = 250.0 + 200.0 * sin(number_of_nodes / 10.0 * M_PI);
+ newy = 150.0 - 100.0 * cos(number_of_nodes / 10.0 * M_PI);
+ gnome_canvas_item_move(GNOME_CANVAS_ITEM(((struct if_node_data*)(n->data))->item), newx - ((struct if_node_data*)(n->data))->x, newy - ((struct if_node_data*)(n->data))->y);
+ ((struct if_node_data*)(n->data))->x = newx;
+ ((struct if_node_data*)(n->data))->y = newy;
+
+ for(i = 0, avlnode = node_tree->head; avlnode; avlnode = avlnode->next, i++)
+ {
+ if(!((struct if_node_data*)(((node_t*)(avlnode->data))->data))->visible)
+ continue;
+
+ nodes[i] = (node_t *)(avlnode->data);
+ ((struct if_node_data*)(nodes[i]->data))->id = i;
+ }
+ number_of_nodes = i;
+
+ gnome_canvas_item_show(GNOME_CANVAS_ITEM(((struct if_node_data*)(n->data))->item));
+ gnome_canvas_update_now(GNOME_CANVAS(canvas));
+
+ /* (Re)start calculations */
inited = 0;
build_graph = 1;
+}
+
+void if_node_invisible(const char *hooktype, va_list ap)
+{
+ int i;
+ avl_node_t *avlnode;
+ node_t *n = va_arg(ap, node_t*);
+
+ if(!((struct if_node_data*)(n->data))->item)
+ return;
+
+ if(!((struct if_node_data*)(n->data))->visible)
+ /* This node is already invisible */
+ return;
+
+ ((struct if_node_data*)(n->data))->visible = 0;
+
+ for(i = 0, avlnode = node_tree->head; avlnode; avlnode = avlnode->next, i++)
+ {
+ if(!((struct if_node_data*)((node_t*)(avlnode->data))->data)->visible)
+ continue;
+
+ nodes[i] = (node_t *)(avlnode->data);
+ ((struct if_node_data*)(nodes[i]->data))->id = i;
+ }
+ number_of_nodes = i;
+
+ gnome_canvas_item_hide(GNOME_CANVAS_ITEM(((struct if_node_data*)(n->data))->item));
+ gnome_canvas_update_now(GNOME_CANVAS(canvas));
- return ctn;
+ /* (Re)start calculations */
+ inited = 0;
+ build_graph = 1;
}
-void if_node_del(node_t *n)
+void if_node_add(const char *hooktype, va_list ap)
{
+ node_t *n = va_arg(ap, node_t*);
+ char *l[1];
+ struct if_node_data *nd;
+
+ if(!xml)
+ return;
+
+ nd = xmalloc_and_zero(sizeof(*nd));
+ l[0] = n->name;
gtk_clist_freeze(GTK_CLIST(nodetree));
- if(n->host_ctn)
- gtk_ctree_remove_node(GTK_CTREE(nodetree), n->host_ctn);
- if(n->conn_ctn)
- gtk_ctree_remove_node(GTK_CTREE(nodetree), n->conn_ctn);
- if(n->subnet_ctn)
- gtk_ctree_remove_node(GTK_CTREE(nodetree), n->subnet_ctn);
+ nd->ctn = gtk_ctree_insert_node(GTK_CTREE(nodetree),
+ hosts_ctn, NULL, l, 1,
+ NULL, NULL, NULL, NULL,
+ FALSE, FALSE);
gtk_clist_thaw(GTK_CLIST(nodetree));
+ gtk_ctree_node_set_row_data(GTK_CTREE(nodetree), nd->ctn, n);
+
+ n->data = (void*)nd;
+
+ if(canvas_visible)
+ {
+ if_node_create(n);
+ if_node_visible(hooktype, ap);
+ }
}
-void if_subnet_add(subnet_t *subnet)
+void if_node_del(const char *hooktype, va_list ap)
+{
+ node_t *n = va_arg(ap, node_t*);
+ struct if_node_data *nd;
+
+ nd = (struct if_node_data*)(n->data);
+ if(nd &&nd->ctn)
+ {
+ gtk_clist_freeze(GTK_CLIST(nodetree));
+ gtk_ctree_remove_node(GTK_CTREE(nodetree), nd->ctn);
+ gtk_clist_thaw(GTK_CLIST(nodetree));
+ }
+
+ if(canvas_visible)
+ {
+ if_node_invisible(hooktype, ap);
+ }
+
+ free(nd);
+ n->data = NULL;
+}
+
+void if_subnet_add(const char *hooktype, va_list ap)
{
char *l[1];
-
+ subnet_t *subnet = va_arg(ap, subnet_t*);
+ struct if_subnet_data *sd;
+ GtkCTreeNode *parent;
+
+ sd = xmalloc_and_zero(sizeof(*sd));
l[0] = net2str(subnet);
+ parent = subnet->owner->data ?
+ ((struct if_subnet_data*)(subnet->owner->data))->ctn
+ : NULL;
+
gtk_clist_freeze(GTK_CLIST(nodetree));
- gtk_ctree_insert_node(GTK_CTREE(nodetree),
- subnets_ctn, NULL, l, 1,
- NULL, NULL, NULL, NULL,
- TRUE, FALSE);
+ sd->ctn = gtk_ctree_insert_node(GTK_CTREE(nodetree),
+ parent, NULL, l, 1,
+ NULL, NULL, NULL, NULL,
+ TRUE, FALSE);
gtk_clist_thaw(GTK_CLIST(nodetree));
+ gtk_ctree_node_set_row_data(GTK_CTREE(nodetree), sd->ctn, subnet);
+
+ subnet->data = (void*)sd;
}
-void if_subnet_del(subnet_t *subnet)
+void if_subnet_del(const char *hooktype, va_list ap)
{
+ subnet_t *subnet = va_arg(ap, subnet_t*);
+ struct if_subnet_data *sd;
+
+ sd = (struct if_subnet_data*)(subnet->data);
+ if(sd && sd->ctn)
+ {
+ gtk_clist_freeze(GTK_CLIST(nodetree));
+ gtk_ctree_remove_node(GTK_CTREE(nodetree), sd->ctn);
+ gtk_clist_thaw(GTK_CLIST(nodetree));
+ }
+
+ free(sd);
+ subnet->data = NULL;
}
void redraw_edges(void)
GnomeCanvasPoints *points;
avl_node_t *avlnode;
edge_t *e;
+ struct if_node_data *fd, *td;
if(edge_group)
gtk_object_destroy(GTK_OBJECT(edge_group));
for(avlnode = edge_tree->head; avlnode; avlnode = avlnode->next)
{
-/* char s[12]; */
e = (edge_t *)avlnode->data;
+ fd = (struct if_node_data*)(e->from.node->data);
+ td = (struct if_node_data*)(e->to.node->data);
+
+/* if(!e->from.node->status.visible || */
+/* !e->to.node->status.visible) */
+/* /\* We shouldn't draw this line *\/ */
+/* continue; */
points = gnome_canvas_points_new(2);
- points->coords[0] = e->from.node->x;
- points->coords[1] = e->from.node->y;
- points->coords[2] = e->to.node->x;
- points->coords[3] = e->to.node->y;
+ points->coords[0] = fd->x;
+ points->coords[1] = fd->y;
+ points->coords[2] = td->x;
+ points->coords[3] = td->y;
gnome_canvas_item_new(group,
gnome_canvas_line_get_type(),
"points", points,
- "fill_color_rgba", 0xe080c0ff,
+ "fill_color_rgba", 0xe080c080,
"width_pixels", 2,
NULL);
gnome_canvas_points_unref(points);
-/* snprintf(s, sizeof(s) - 1, "%d", e->weight); */
-/* gnome_canvas_item_new(group, */
-/* gnome_canvas_text_get_type(), */
-/* "x", (e->from.node->x + e->to.node->x) / 2, */
-/* "y", (e->from.node->y + e->to.node->y) / 2, */
-/* "text", s, */
-/* "anchor", GTK_ANCHOR_CENTER, */
-/* "fill_color", "black", */
-/* "font", "-*-verdana-medium-r-*-*-8-*-*-*-*-*-iso8859-1", */
-/* /\* "font", "fixed", *\/ */
-/* NULL); */
}
+ gnome_canvas_update_now(GNOME_CANVAS(canvas));
+
edge_group = group;
}
-void if_edge_add(edge_t *e)
+void if_edge_add(const char *hooktype, va_list ap)
{
redraw_edges();
- if_graph_add_edge(e);
+
inited = 0;
build_graph = 1;
-
}
-void if_edge_del(edge_t *e)
+void if_edge_del(const char *hooktype, va_list ap)
{
redraw_edges();
+
inited = 0;
build_graph = 1;
-
-}
-
-void if_graph_add_node(node_t *n)
-{
- GnomeCanvasGroup *group;
- double newx, newy;
-
- if(!canvas)
- if(!create_canvas())
- return;
-
- group = gnome_canvas_root(GNOME_CANVAS(canvas));
- group = GNOME_CANVAS_GROUP(gnome_canvas_item_new(group,
- gnome_canvas_group_get_type(),
- "x", 0.0,
- "y", 0.0,
- NULL));
-
- gnome_canvas_item_new(group, gnome_canvas_ellipse_get_type(),
- "x1", -30.0,
- "y1", -08.0,
- "x2", 30.0,
- "y2", 08.0,
- "fill_color_rgba", 0x5f9ea0ff,
- "outline_color", "black",
- "width_pixels", 0,
- NULL);
-
- gnome_canvas_item_new(group,
- gnome_canvas_text_get_type(),
- "x", 0.0,
- "y", 0.0,
- "text", n->name,
- "anchor", GTK_ANCHOR_CENTER,
- "fill_color", "white",
- "font", "-*-verdana-medium-r-*-*-10-*-*-*-*-*-iso8859-1",
-/* "font", "fixed", */
- NULL);
-
- n->item = GNOME_CANVAS_ITEM(group);
- gtk_object_set_user_data(GTK_OBJECT(group), (gpointer)n);
-
- /* TODO: Use this to get more detailed info on a node (For example
- popup a dialog with more info, select the node in the left
- pane, whatever.) */
- gtk_signal_connect(GTK_OBJECT(n->item), "event", (GtkSignalFunc) item_event, NULL);
-
- newx = 250.0 + 200.0 * sin(number_of_nodes / 10.0 * M_PI);
- newy = 150.0 - 100.0 * cos(number_of_nodes / 10.0 * M_PI);
-/* newx = (double)random() / (double)RAND_MAX * 300.0 + 100.0; */
-/* newy = (double)random() / (double)RAND_MAX * 200.0 + 50.0; */
- gnome_canvas_item_move(GNOME_CANVAS_ITEM(n->item), newx, newy);
- n->x = newx;
- n->y = newy;
-
- x[number_of_nodes] = newx;
- y[number_of_nodes] = newy;
- nodes[number_of_nodes] = n;
- n->id = number_of_nodes;
-
- number_of_nodes++;
-
- gnome_canvas_update_now(GNOME_CANVAS(canvas));
}
void if_move_node(node_t *n, double dx, double dy)
{
double newx, newy;
- newx = n->x + dx;
- newy = n->y + dy;
- gnome_canvas_item_move(GNOME_CANVAS_ITEM(n->item), newx - n->x, newy - n->y);
- n->x = newx;
- n->y = newy;
-}
-
-void if_graph_add_edge(edge_t *e)
-{
-/* e->from.node->ifn->nat++; */
-/* e->to.node->ifn->nat++; */
-
-/* avl_insert(e->from.node->ifn->attractors, e->to.node); */
-/* avl_insert(e->to.node->ifn->attractors, e->from.node); */
-
- redraw_edges();
-
- build_graph = 1;
+ newx = ((struct if_node_data*)(n->data))->x + dx;
+ newy = ((struct if_node_data*)(n->data))->y + dy;
+ gnome_canvas_item_move(GNOME_CANVAS_ITEM(((struct if_node_data*)(n->data))->item), newx - ((struct if_node_data*)(n->data))->x, newy - ((struct if_node_data*)(n->data))->y);
+ ((struct if_node_data*)(n->data))->x = newx;
+ ((struct if_node_data*)(n->data))->y = newy;
}
#define X_MARGIN 50.0
int i;
double minx, miny, maxx, maxy;
static double ominx = 0.0, ominy = 0.0, omaxx = 0.0, omaxy = 0.0;
- double ppu, ppux, ppuy;
minx = miny = maxx = maxy = 0.0;
for(i = 0; i < number_of_nodes; i++)
{
- if(nodes[i]->x < minx)
- minx = nodes[i]->x;
+ if(((struct if_node_data*)(nodes[i]->data))->x < minx)
+ minx = ((struct if_node_data*)(nodes[i]->data))->x;
else
- if(nodes[i]->x > maxx)
- maxx = nodes[i]->x;
+ if(((struct if_node_data*)(nodes[i]->data))->x > maxx)
+ maxx = ((struct if_node_data*)(nodes[i]->data))->x;
- if(nodes[i]->y < miny)
- miny = nodes[i]->y;
+ if(((struct if_node_data*)(nodes[i]->data))->y < miny)
+ miny = ((struct if_node_data*)(nodes[i]->data))->y;
else
- if(nodes[i]->y > maxy)
- maxy = nodes[i]->y;
+ if(((struct if_node_data*)(nodes[i]->data))->y > maxy)
+ maxy = ((struct if_node_data*)(nodes[i]->data))->y;
}
if(minx > ominx - X_MARGIN_BUFFER && ominx > minx)
/* gnome_canvas_set_pixels_per_unit(GNOME_CANVAS(canvas), ppu); */
gnome_canvas_set_scroll_region(GNOME_CANVAS(canvas), minx - X_MARGIN, miny - Y_MARGIN, maxx + X_MARGIN, maxy + Y_MARGIN);
+ gnome_canvas_update_now(GNOME_CANVAS(canvas));
}
double calculate_delta_m(int m)
{
int i, j, p, max_i;
double delta_m, max_delta_m;
- double dx, dy, s, L, max_d, old_x, old_y;
+ double dx, dy, s, L, min_d, old_x, old_y;
edge_t *e;
+ if(!keep_drawing)
+ return;
+
if(!inited)
{
+ for(i = 0; i < number_of_nodes; i++)
+ {
+ x[i] = ((struct if_node_data*)(nodes[i]->data))->x;
+ y[i] = ((struct if_node_data*)(nodes[i]->data))->y;
+ }
+
+ /* Initialize Floyd */
for(i = 0; i < number_of_nodes; i++)
{
d[i][i] = 0.0;
d[i][j] = d[j][i] = INFINITY;
}
}
+
+ /* Floyd's shortest path algorithm */
for(i = 0; i < number_of_nodes; i++)
{
for(j = 0; j < number_of_nodes; j++)
}
}
- max_d = 0.0;
+ min_d = INFINITY;
for(i = 0; i < number_of_nodes; i++)
for(j = i + 1; j < number_of_nodes; j++)
- if(d[i][j] > max_d && d[i][j] < INFINITY)
- max_d = d[i][j];
+ if(d[i][j] < min_d && d[i][j] > 0.0)
+ min_d = d[i][j];
- L = 300.0 / log(max_d);
+ L = 5.0 / sqrt(min_d + 1.0);
for(i = 0; i < number_of_nodes; i++)
{
for(j = i + 1; j < number_of_nodes; j++)
{
- d[i][j] = d[j][i] = log(d[i][j]+1.0);
+ d[i][j] = d[j][i] = sqrt(d[i][j]+1.0);
l[i][j] = l[j][i] = L * d[i][j];
k[i][j] = k[j][i] = K / (d[i][j] * d[i][j]);
}
}
if(max_delta_m <= epsilon)
- build_graph = 0;
+ {
+ fprintf(stderr, "Graph building is done; max_delta_m = %f\n", max_delta_m);
+ build_graph = 0;
+ }
else
{
int iter = 0, maxiter = 20;