2 interface.c -- GTK+/GNOME interface functions
3 Copyright (C) 2002 Guus Sliepen <guus@sliepen.warande.net>,
4 2002 Ivo Timmermans <ivo@o2w.nl>
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 $Id: interface.c,v 1.5 2002/05/02 11:50:07 zarq Exp $
35 #include <glade/glade.h>
36 #include <libgnomeui/gnome-canvas.h>
37 #include <libgnomeui/gnome-canvas-rect-ellipse.h>
38 #include <libgnomeui/gnome-canvas-text.h>
39 #include <libgnomeui/gnome-canvas-line.h>
40 #include <libgnomeui/gnome-canvas-util.h>
43 #include "connection.h"
45 #include "interface.h"
53 /* Node tree & main window stuff */
55 static GtkWidget *nodetree;
56 static GtkCTreeNode *hosts_ctn;
59 /* Graph canvas stuff */
60 static GladeXML *canvas_xml;
62 static GnomeCanvasGroup *edge_group = NULL;
64 static int canvas_width;
65 static int canvas_height;
67 static GtkWidget *canvas = NULL;
69 static int canvas_visible = 0;
73 static GdkColormap *colormap = NULL;
74 static GdkColor timecolor;
82 #define INFINITY 1.0e10
84 node_t *nodes[MAX_NODES];
87 double k[MAX_NODES][MAX_NODES];
88 double d[MAX_NODES][MAX_NODES];
89 double l[MAX_NODES][MAX_NODES];
90 static const double epsilon = 0.001;
92 static int inited = 0;
94 static int number_of_nodes = 0;
96 static double canvas_zoom = 1.00;
99 /* Log window stuff */
104 #define MAXBUFSIZE 1024
106 static int log_inited = 0;
107 static int follow_log = 1;
109 static int keep_drawing = 1;
111 static int log_visible = 0;
112 static GtkWidget *log_window = NULL;
115 void if_node_add(const char *hooktype, va_list ap);
116 void if_node_del(const char *hooktype, va_list ap);
117 void if_subnet_add(const char *hooktype, va_list ap);
118 void if_subnet_del(const char *hooktype, va_list ap);
119 void if_edge_add(const char *hooktype, va_list ap);
120 void if_edge_del(const char *hooktype, va_list ap);
121 void if_node_visible(const char *hooktype, va_list ap);
122 void if_node_invisible(const char *hooktype, va_list ap);
124 void if_node_create(node_t *n);
126 GtkWidget *create_canvas(void)
128 canvas_xml = glade_xml_new(INTERFACE_FILE, "GraphWindow");
132 _("Could not find widget `%s'"),
137 canvas = glade_xml_get_widget(xml, "canvas1");
140 fprintf(stderr, "Could not find widget `canvas1'\n");
144 gnome_canvas_set_scroll_region(GNOME_CANVAS(canvas), 0.0, 0.0, 700, 500);
146 canvas_width = 300.0;
147 canvas_height = 500.0;
152 void log_gtk(int level, int priority, char *fmt, va_list ap)
154 char buffer1[MAXBUFSIZE];
155 char buffer2[MAXBUFSIZE];
164 /* Use vsnprintf instead of vasprintf: faster, no memory
165 fragmentation, cleanup is automatic, and there is a limit on the
166 input buffer anyway */
167 len = vsnprintf(buffer1, MAXBUFSIZE, fmt, ap);
169 buffer1[MAXBUFSIZE-1] = '\0';
170 if((p = strrchr(buffer1, '\n')))
175 snprintf(buffer2, MAXBUFSIZE, "%02d:%02d:%02d ",
176 tm->tm_hour, tm->tm_min, tm->tm_sec);
180 colormap = gdk_colormap_new(gdk_visual_get_system(), FALSE);
181 timecolor.red = 0xffff;
184 if(gdk_colormap_alloc_color(colormap, &timecolor, FALSE, TRUE) != TRUE)
186 fprintf(stderr, "Failed to allocate color\n");
191 gtk_text_freeze(GTK_TEXT(log_window));
194 gtk_text_insert(GTK_TEXT(log_window), NULL, NULL, NULL, "\n", 1);
196 gtk_text_insert(GTK_TEXT(log_window), NULL, &timecolor, NULL, buffer2, strlen(buffer2));
197 gtk_text_insert(GTK_TEXT(log_window), NULL, NULL, NULL, buffer1, len);
198 gtk_text_thaw(GTK_TEXT(log_window));
202 /* gtk_text_set_point(GTK_TEXT(w), -1); */
203 gtk_editable_set_position(GTK_EDITABLE(log_window), gtk_text_get_length(GTK_TEXT(log_window)));
206 void if_hostinfoclosebutton_clicked(GtkWidget *w, gpointer data)
208 gtk_widget_destroy(GTK_WIDGET(data));
211 void update_hostinfo_dialog(GladeXML *x, node_t *n)
218 w = glade_xml_get_widget(x, "HostInfoNameEntry");
219 if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "HostInfoNameEntry"); return; }
220 gtk_entry_set_text(GTK_ENTRY(w), n->name);
222 w = glade_xml_get_widget(x, "HostInfoHostnameEntry");
223 if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "HostInfoHostnameEntry"); return; }
224 gtk_entry_set_text(GTK_ENTRY(w), n->hostname);
226 w = glade_xml_get_widget(x, "HostInfoPortEntry");
227 if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "HostInfoPortEntry"); return; }
228 /* snprintf(s, sizeof(s)-1, "%hd", "0"); */
229 gtk_entry_set_text(GTK_ENTRY(w), "port");
231 w = glade_xml_get_widget(x, "HostInfoVersionEntry");
232 if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "HostInfoVersionEntry"); return; }
233 gtk_entry_set_text(GTK_ENTRY(w), n->name);
235 w = glade_xml_get_widget(x, "HostInfoStatusEntry");
236 if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "HostInfoStatusEntry"); return; }
237 /* snprintf(s, sizeof(s)-1, "%x", n->status); */
238 gtk_entry_set_text(GTK_ENTRY(w), "0");
240 w = glade_xml_get_widget(x, "HostInfoActiveCheckbutton");
241 if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "HostInfoActiveCheckbutton"); return; }
242 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), n->status.active);
244 w = glade_xml_get_widget(x, "HostInfoValidkeyCheckbutton");
245 if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "HostInfoValidkeyCheckbutton"); return; }
246 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), n->status.validkey);
248 w = glade_xml_get_widget(x, "HostInfoWaitingforkeyCheckbutton");
249 if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "HostInfoWaitingforkeyCheckbutton"); return; }
250 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), n->status.waitingforkey);
252 w = glade_xml_get_widget(x, "HostInfoVisitedCheckbutton");
253 if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "HostInfoVisitedCheckbutton"); return; }
254 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), n->status.visited);
256 w = glade_xml_get_widget(x, "HostInfoReachableCheckbutton");
257 if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "HostInfoReachableCheckbutton"); return; }
258 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), n->status.reachable);
260 w = glade_xml_get_widget(x, "HostInfoIndirectCheckbutton");
261 if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "HostInfoIndirectCheckbutton"); return; }
262 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), n->status.indirect);
264 w = glade_xml_get_widget(x, "HostInfoVisibleCheckbutton");
265 if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "HostInfoVisibleCheckbutton"); return; }
266 /* gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), n->status.visible); */
268 w = glade_xml_get_widget(x, "HostInfoTCPOnlyCheckbutton");
269 if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "HostInfoTCPOnlyCheckbutton"); return; }
270 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), (n->options & OPTION_TCPONLY) != 0);
272 w = glade_xml_get_widget(x, "HostInfoIndirectdataCheckbutton");
273 if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "HostInfoIndirectdataCheckbutton"); return; }
274 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), (n->options & OPTION_INDIRECT) != 0);
276 /* w = glade_xml_get_widget(x, "HostInfoWindow"); */
277 /* if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "HostInfoWindow"); return; } */
278 /* glade_xml_signal_connect_data(x, "on_HostInfoCloseButton_clicked", if_hostinfoclosebutton_clicked, (gpointer)w); */
279 w = glade_xml_get_widget(x, "HostConnectionsCList");
280 if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "HostConnectionsCList"); return; }
281 for(avlnode = n->edge_tree->head; avlnode; avlnode = avlnode->next)
283 if(((edge_t*)(avlnode->data))->to.node == n)
284 l[0] = ((edge_t*)(avlnode->data))->from.node->name;
286 l[0] = ((edge_t*)(avlnode->data))->to.node->name;
287 gtk_clist_append(GTK_CLIST(w), l);
291 void on_preferences1_activate(GtkMenuItem *mi, gpointer data)
296 x = glade_xml_new(INTERFACE_FILE, "PropertyBox");
300 _("Could not find widget `%s'"),
305 w = glade_xml_get_widget(x, "PropertyBox");
306 if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "PropertyBox"); return; }
307 glade_xml_signal_autoconnect(x);
310 void on_logcontext_clear_activate(GtkMenuItem *mi, gpointer data)
312 gtk_editable_delete_text(GTK_EDITABLE(log_window), 0, -1); /* Delete from 0 to end of buffer */
316 void on_logcontext_follow_activate(GtkMenuItem *mi, gpointer data)
318 follow_log = !follow_log;
321 void on_logcontext_close1_activate(GtkMenuItem *mi, gpointer data)
326 void on_messages_button_press_event(GtkWidget *w, GdkEventButton *event, gpointer data)
331 if (event->button == 3)
333 x = glade_xml_new(INTERFACE_FILE, "LogContextMenu");
337 _("Could not find widget `%s'"),
342 menu = glade_xml_get_widget(x, "LogContextMenu");
343 if(!menu) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "LogContextMenu"); return; }
345 glade_xml_signal_connect_data(x, "on_logcontext_clear_activate", on_logcontext_clear_activate, (gpointer)x);
346 glade_xml_signal_connect_data(x, "on_logcontext_follow_activate", on_logcontext_follow_activate, (gpointer)x);
347 w = glade_xml_get_widget(x, "LogContextFollow");
348 if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "LogContextFollow"); return; }
349 GTK_CHECK_MENU_ITEM(w)->active = follow_log;
350 gnome_popup_menu_do_popup_modal(menu, NULL, NULL, event, NULL);
351 gtk_widget_destroy(menu);
355 void shuffle_nodes(void)
360 for(avlnode = node_tree->head; avlnode; avlnode = avlnode->next)
362 newx = ((double)random()) / ((double)RAND_MAX) * 500.0;
363 newy = ((double)random()) / ((double)RAND_MAX) * 300.0;
364 ((struct if_node_data*)((node_t *)(avlnode->data))->data)->x = newx;
365 ((struct if_node_data*)((node_t *)(avlnode->data))->data)->y = newy;
367 if(!((struct if_node_data*)((node_t*)(avlnode->data)))->visible)
370 x[((struct if_node_data*)((node_t*)(avlnode->data))->data)->id] = newx;
371 y[((struct if_node_data*)((node_t*)(avlnode->data))->data)->id] = newy;
377 void on_canvascontext_shuffle_activate(GtkMenuItem *mi, gpointer data)
382 void on_canvascontext_keep_drawing_activate(GtkMenuItem *mi, gpointer data)
386 keep_drawing = !keep_drawing;
388 /* No need to fuss with the checkbox in the menu, because that is
389 transient. Do need to update the checkbox at the bottom of the
391 w = glade_xml_get_widget(canvas_xml, "KeepDrawingButton");
392 if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "KeepDrawingButton"); return; }
393 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), keep_drawing);
396 void on_canvascontext_minus50_activate(GtkMenuItem *mi, gpointer data)
399 gnome_canvas_set_pixels_per_unit(GNOME_CANVAS(canvas), canvas_zoom);
402 void on_canvascontext_minus25_activate(GtkMenuItem *mi, gpointer data)
405 gnome_canvas_set_pixels_per_unit(GNOME_CANVAS(canvas), canvas_zoom);
408 void on_canvascontext_minus10_activate(GtkMenuItem *mi, gpointer data)
411 gnome_canvas_set_pixels_per_unit(GNOME_CANVAS(canvas), canvas_zoom);
414 void on_canvascontext_default_activate(GtkMenuItem *mi, gpointer data)
417 gnome_canvas_set_pixels_per_unit(GNOME_CANVAS(canvas), 1.00);
420 void on_canvascontext_plus10_activate(GtkMenuItem *mi, gpointer data)
423 gnome_canvas_set_pixels_per_unit(GNOME_CANVAS(canvas), canvas_zoom);
426 void on_canvascontext_plus25_activate(GtkMenuItem *mi, gpointer data)
429 gnome_canvas_set_pixels_per_unit(GNOME_CANVAS(canvas), canvas_zoom);
432 void on_canvascontext_plus50_activate(GtkMenuItem *mi, gpointer data)
435 gnome_canvas_set_pixels_per_unit(GNOME_CANVAS(canvas), canvas_zoom);
438 void on_canvas_button_press_event(GtkWidget *w, GdkEventButton *event, gpointer data)
443 if (event->button == 3)
445 x = glade_xml_new(INTERFACE_FILE, "CanvasContextMenu");
449 _("Could not find widget `%s'"),
450 "CanvasContextMenu");
454 menu = glade_xml_get_widget(x, "CanvasContextMenu");
455 if(!menu) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "CanvasContextMenu"); return; }
457 glade_xml_signal_autoconnect(x);
458 glade_xml_signal_connect_data(x, "on_canvascontext_shuffle_activate", on_canvascontext_shuffle_activate, (gpointer)x);
459 glade_xml_signal_connect_data(x, "on_canvascontext_keep_drawing_activate", on_canvascontext_keep_drawing_activate, (gpointer)x);
460 w = glade_xml_get_widget(x, "CanvasContextKeepDrawing");
461 if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "CanvasContextKeepDrawing"); return; }
462 GTK_CHECK_MENU_ITEM(w)->active = keep_drawing;
463 gnome_popup_menu_do_popup_modal(menu, NULL, NULL, event, NULL);
464 gtk_widget_destroy(menu);
468 void on_nodetree_button_press_event(GtkWidget *w, GdkEventButton *event, gpointer data)
475 gtk_clist_get_selection_info(GTK_CLIST(w), event->x, event->y,
478 node = gtk_ctree_node_nth(GTK_CTREE(w), row);
481 lt = gtk_ctree_node_get_row_data(GTK_CTREE(w), node);
482 if(event->type == GDK_2BUTTON_PRESS && event->button == 1)
484 /* Double left click on an item */
486 /* this is only a branch, double click wil (un)expand. */
489 if(GTK_CTREE_ROW(node)->parent == hosts_ctn)
491 x = ((struct if_node_data*)(((node_t*)lt)->data))->hi_xml = glade_xml_new(INTERFACE_FILE, "HostInfoWindow");
495 _("Could not find widget `%s'"),
499 glade_xml_signal_autoconnect(x);
500 update_hostinfo_dialog(x, (node_t*)lt);
505 "WHERE did you click?!");
507 /* so now we have access to all the data we want. */
508 /* gldap_show_details(lt); */
512 /* if (event->button == 3) */
514 /* GtkWidget *temp_menu; */
515 /* temp_menu = gnome_popup_menu_new(data); */
516 /* gnome_popup_menu_do_popup_modal(temp_menu, NULL, NULL, event, NULL); */
517 /* gtk_widget_destroy(temp_menu); */
521 void on_exit1_activate(GtkMenuItem *mi, gpointer data)
523 close_network_connections();
527 void on_about1_activate(GtkMenuItem *mi, gpointer data)
530 x = glade_xml_new(INTERFACE_FILE, "AboutWindow");
534 _("Could not find widget `%s'"),
538 glade_xml_signal_autoconnect(x);
541 void on_graph_window1_activate(GtkMenuItem *mi, gpointer data)
547 canvas_xml = glade_xml_new(INTERFACE_FILE, "GraphWindow");
548 if(canvas_xml == NULL)
551 _("Could not find widget `%s'"),
555 glade_xml_signal_autoconnect(canvas_xml);
556 canvas = glade_xml_get_widget(canvas_xml, "canvas1");
557 if(canvas == NULL) { log(0, TLOG_ERROR, _("Could not find widget `%s'"), "canvas1"); return; }
559 for(i = 0, avlnode = node_tree->head; avlnode; avlnode = avlnode->next)
561 node_t *n = (node_t*)(avlnode->data);
563 if(!((struct if_node_data*)(n->data))->item)
566 if(!n->status.reachable)
569 newx = 250.0 + 200.0 * sin(i / 10.0 * M_PI);
570 newy = 150.0 - 100.0 * cos(i / 10.0 * M_PI);
571 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);
572 ((struct if_node_data*)(n->data))->x = newx;
573 ((struct if_node_data*)(n->data))->y = newy;
575 ((struct if_node_data*)(n->data))->id = i;
577 gnome_canvas_item_show(GNOME_CANVAS_ITEM(((struct if_node_data*)(n->data))->item));
578 gnome_canvas_update_now(GNOME_CANVAS(canvas));
590 void on_log_window1_activate(GtkMenuItem *mi, gpointer data)
595 x = glade_xml_new(INTERFACE_FILE, "LogWindow");
599 _("Could not find widget `%s'"),
603 log_window = glade_xml_get_widget(x, "Messages");
607 _("Could not find widget `%s'"),
611 w = glade_xml_get_widget(x, "DebugLevelSpinbutton");
615 _("Could not find widget `%s'"),
616 "DebugLevelSpinbutton");
619 gtk_spin_button_set_value(GTK_SPIN_BUTTON(w), (float)debug_lvl);
621 glade_xml_signal_autoconnect(x);
623 log_add_hook(log_gtk);
624 log(0, TLOG_NOTICE, "Logging started.\n");
628 void on_debug_level_changed(GtkSpinButton *sb, gpointer data)
630 debug_lvl = gtk_spin_button_get_value_as_int(sb);
633 void on_logwindow_close_clicked(GtkButton *b, gpointer data)
638 x = glade_xml_new(INTERFACE_FILE, "LogWindow");
642 _("Could not find widget `%s'"),
646 w = glade_xml_get_widget(x, "LogWindow");
650 _("Could not find widget `%s'"),
654 gtk_widget_destroy(w);
657 void on_spinbutton2_changed(GtkSpinButton *sb, gpointer data)
659 canvas_zoom = gtk_spin_button_get_value_as_float(sb) / 100.0;
660 gnome_canvas_set_pixels_per_unit(GNOME_CANVAS(canvas), canvas_zoom);
663 void on_checkbutton1_toggled(GtkCheckButton *cb, gpointer data)
665 keep_drawing = !keep_drawing;
668 void on_button19_clicked(GtkWidget *bt, GdkEventButton *ev, gpointer data)
673 void on_button18_clicked(GtkWidget *bt, GdkEventButton *ev, gpointer data)
677 w = glade_xml_get_widget(canvas_xml, "GraphWindow");
678 if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "GraphWindow"); return; }
679 gtk_object_destroy(GTK_OBJECT(w));
684 int init_interface(void)
690 xml = glade_xml_new("pokey.glade", "AppWindow");
695 _("Something bad happened while creating the interface.\n"));
699 nodetree = glade_xml_get_widget(xml, "NodeTree");
703 _("Could not find widget `%s'"),
708 gtk_clist_freeze(GTK_CLIST(nodetree));
710 hosts_ctn = gtk_ctree_insert_node(GTK_CTREE(nodetree),
712 NULL, NULL, NULL, NULL,
714 gtk_clist_thaw(GTK_CLIST(nodetree));
716 glade_xml_signal_autoconnect(xml);
718 log_del_hook(log_default);
720 add_hook("node-add", if_node_add);
721 add_hook("node-del", if_node_del);
722 add_hook("subnet-add", if_subnet_add);
723 add_hook("subnet-del", if_subnet_del);
724 add_hook("edge-add", if_edge_add);
725 add_hook("edge-del", if_edge_del);
726 add_hook("node-visible", if_node_visible);
727 add_hook("node-invisible", if_node_invisible);
732 static gint item_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data)
734 static double item_x, old_x, new_x, item_y, old_y, new_y;
735 static int dragging = FALSE;
739 item_x = event->button.x;
740 item_y = event->button.y;
741 gnome_canvas_item_w2i(item->parent, &item_x, &item_y);
745 case GDK_BUTTON_PRESS:
746 switch(event->button.button)
752 fleur = gdk_cursor_new(GDK_FLEUR);
753 gnome_canvas_item_grab(item, GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK, fleur, event->button.time);
754 gdk_cursor_destroy(fleur);
763 case GDK_MOTION_NOTIFY:
764 if(dragging && (event->motion.state & GDK_BUTTON1_MASK))
768 gnome_canvas_item_move(item, new_x - old_x, new_y - old_y);
774 case GDK_BUTTON_RELEASE:
775 gnome_canvas_item_ungrab(item, event->button.time);
777 n = (node_t *)gtk_object_get_user_data(GTK_OBJECT(item));
778 ((struct if_node_data*)(n->data))->x = item_x;
779 ((struct if_node_data*)(n->data))->y = item_y;
780 x[((struct if_node_data*)(n->data))->id] = item_x;
781 y[((struct if_node_data*)(n->data))->id] = item_y;
791 void if_node_create(node_t *n)
793 GnomeCanvasGroup *group;
795 group = gnome_canvas_root(GNOME_CANVAS(canvas));
796 group = GNOME_CANVAS_GROUP(gnome_canvas_item_new(group,
797 gnome_canvas_group_get_type(),
802 gnome_canvas_item_new(group, gnome_canvas_ellipse_get_type(),
807 "fill_color_rgba", 0x5f9ea080,
808 "outline_color", "black",
812 gnome_canvas_item_new(group,
813 gnome_canvas_text_get_type(),
817 "anchor", GTK_ANCHOR_CENTER,
818 "fill_color", "white",
819 "font", "-*-verdana-medium-r-*-*-10-*-*-*-*-*-iso8859-1",
822 ((struct if_node_data*)(n->data))->item = GNOME_CANVAS_ITEM(group);
823 ((struct if_node_data*)(n->data))->x = ((struct if_node_data*)(n->data))->y = 0.0;
824 gtk_object_set_user_data(GTK_OBJECT(group), (gpointer)n);
826 gtk_signal_connect(GTK_OBJECT(((struct if_node_data*)(n->data))->item), "event", (GtkSignalFunc) item_event, NULL);
828 gnome_canvas_item_hide(GNOME_CANVAS_ITEM(((struct if_node_data*)(n->data))->item));
831 void if_node_visible(const char *hooktype, va_list ap)
836 node_t *n = va_arg(ap, node_t*);
841 if(!((struct if_node_data*)(n->data))->item)
842 /* No GnomeCanvasItem has been created for this node yet */
845 if(((struct if_node_data*)(n->data))->visible)
846 /* This node is already shown */
849 ((struct if_node_data*)(n->data))->visible = 1;
851 newx = 250.0 + 200.0 * sin(number_of_nodes / 10.0 * M_PI);
852 newy = 150.0 - 100.0 * cos(number_of_nodes / 10.0 * M_PI);
853 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);
854 ((struct if_node_data*)(n->data))->x = newx;
855 ((struct if_node_data*)(n->data))->y = newy;
857 for(i = 0, avlnode = node_tree->head; avlnode; avlnode = avlnode->next, i++)
859 if(!((struct if_node_data*)(((node_t*)(avlnode->data))->data))->visible)
862 nodes[i] = (node_t *)(avlnode->data);
863 ((struct if_node_data*)(nodes[i]->data))->id = i;
867 gnome_canvas_item_show(GNOME_CANVAS_ITEM(((struct if_node_data*)(n->data))->item));
868 gnome_canvas_update_now(GNOME_CANVAS(canvas));
870 /* (Re)start calculations */
875 void if_node_invisible(const char *hooktype, va_list ap)
879 node_t *n = va_arg(ap, node_t*);
881 if(!((struct if_node_data*)(n->data))->item)
884 if(!((struct if_node_data*)(n->data))->visible)
885 /* This node is already invisible */
888 ((struct if_node_data*)(n->data))->visible = 0;
890 for(i = 0, avlnode = node_tree->head; avlnode; avlnode = avlnode->next, i++)
892 if(!((struct if_node_data*)((node_t*)(avlnode->data))->data)->visible)
895 nodes[i] = (node_t *)(avlnode->data);
896 ((struct if_node_data*)(nodes[i]->data))->id = i;
900 gnome_canvas_item_hide(GNOME_CANVAS_ITEM(((struct if_node_data*)(n->data))->item));
901 gnome_canvas_update_now(GNOME_CANVAS(canvas));
903 /* (Re)start calculations */
908 void if_node_add(const char *hooktype, va_list ap)
910 node_t *n = va_arg(ap, node_t*);
912 struct if_node_data *nd;
917 nd = xmalloc_and_zero(sizeof(*nd));
919 gtk_clist_freeze(GTK_CLIST(nodetree));
920 nd->ctn = gtk_ctree_insert_node(GTK_CTREE(nodetree),
921 hosts_ctn, NULL, l, 1,
922 NULL, NULL, NULL, NULL,
924 gtk_clist_thaw(GTK_CLIST(nodetree));
925 gtk_ctree_node_set_row_data(GTK_CTREE(nodetree), nd->ctn, n);
932 if_node_visible(hooktype, ap);
936 void if_node_del(const char *hooktype, va_list ap)
938 node_t *n = va_arg(ap, node_t*);
939 struct if_node_data *nd;
941 nd = (struct if_node_data*)(n->data);
944 gtk_clist_freeze(GTK_CLIST(nodetree));
945 gtk_ctree_remove_node(GTK_CTREE(nodetree), nd->ctn);
946 gtk_clist_thaw(GTK_CLIST(nodetree));
951 if_node_invisible(hooktype, ap);
958 void if_subnet_add(const char *hooktype, va_list ap)
961 subnet_t *subnet = va_arg(ap, subnet_t*);
962 struct if_subnet_data *sd;
963 GtkCTreeNode *parent;
965 sd = xmalloc_and_zero(sizeof(*sd));
966 l[0] = net2str(subnet);
967 parent = subnet->owner->data ?
968 ((struct if_subnet_data*)(subnet->owner->data))->ctn
971 gtk_clist_freeze(GTK_CLIST(nodetree));
972 sd->ctn = gtk_ctree_insert_node(GTK_CTREE(nodetree),
974 NULL, NULL, NULL, NULL,
976 gtk_clist_thaw(GTK_CLIST(nodetree));
977 gtk_ctree_node_set_row_data(GTK_CTREE(nodetree), sd->ctn, subnet);
979 subnet->data = (void*)sd;
982 void if_subnet_del(const char *hooktype, va_list ap)
984 subnet_t *subnet = va_arg(ap, subnet_t*);
985 struct if_subnet_data *sd;
987 sd = (struct if_subnet_data*)(subnet->data);
990 gtk_clist_freeze(GTK_CLIST(nodetree));
991 gtk_ctree_remove_node(GTK_CTREE(nodetree), sd->ctn);
992 gtk_clist_thaw(GTK_CLIST(nodetree));
999 void redraw_edges(void)
1001 GnomeCanvasGroup *group;
1002 GnomeCanvasPoints *points;
1003 avl_node_t *avlnode;
1005 struct if_node_data *fd, *td;
1008 gtk_object_destroy(GTK_OBJECT(edge_group));
1010 group = gnome_canvas_root(GNOME_CANVAS(canvas));
1011 group = GNOME_CANVAS_GROUP(gnome_canvas_item_new(group,
1012 gnome_canvas_group_get_type(),
1017 for(avlnode = edge_tree->head; avlnode; avlnode = avlnode->next)
1019 e = (edge_t *)avlnode->data;
1020 fd = (struct if_node_data*)(e->from.node->data);
1021 td = (struct if_node_data*)(e->to.node->data);
1023 /* if(!e->from.node->status.visible || */
1024 /* !e->to.node->status.visible) */
1025 /* /\* We shouldn't draw this line *\/ */
1028 points = gnome_canvas_points_new(2);
1030 points->coords[0] = fd->x;
1031 points->coords[1] = fd->y;
1032 points->coords[2] = td->x;
1033 points->coords[3] = td->y;
1034 gnome_canvas_item_new(group,
1035 gnome_canvas_line_get_type(),
1037 "fill_color_rgba", 0xe080c080,
1040 gnome_canvas_points_unref(points);
1043 gnome_canvas_update_now(GNOME_CANVAS(canvas));
1048 void if_edge_add(const char *hooktype, va_list ap)
1056 void if_edge_del(const char *hooktype, va_list ap)
1064 void if_move_node(node_t *n, double dx, double dy)
1068 newx = ((struct if_node_data*)(n->data))->x + dx;
1069 newy = ((struct if_node_data*)(n->data))->y + dy;
1070 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);
1071 ((struct if_node_data*)(n->data))->x = newx;
1072 ((struct if_node_data*)(n->data))->y = newy;
1075 #define X_MARGIN 50.0
1076 #define X_MARGIN_BUFFER 25.0
1077 #define Y_MARGIN 20.0
1078 #define Y_MARGIN_BUFFER 10.0
1080 void set_zooming(void)
1083 double minx, miny, maxx, maxy;
1084 static double ominx = 0.0, ominy = 0.0, omaxx = 0.0, omaxy = 0.0;
1086 minx = miny = maxx = maxy = 0.0;
1087 for(i = 0; i < number_of_nodes; i++)
1089 if(((struct if_node_data*)(nodes[i]->data))->x < minx)
1090 minx = ((struct if_node_data*)(nodes[i]->data))->x;
1092 if(((struct if_node_data*)(nodes[i]->data))->x > maxx)
1093 maxx = ((struct if_node_data*)(nodes[i]->data))->x;
1095 if(((struct if_node_data*)(nodes[i]->data))->y < miny)
1096 miny = ((struct if_node_data*)(nodes[i]->data))->y;
1098 if(((struct if_node_data*)(nodes[i]->data))->y > maxy)
1099 maxy = ((struct if_node_data*)(nodes[i]->data))->y;
1102 if(minx > ominx - X_MARGIN_BUFFER && ominx > minx)
1104 if(maxx < omaxx + X_MARGIN_BUFFER && omaxx < maxx)
1106 if(miny > ominy - Y_MARGIN_BUFFER && ominy > miny)
1108 if(maxy < omaxy + Y_MARGIN_BUFFER && omaxy < maxy)
1111 ominx = minx; ominy = miny; omaxx = maxx; omaxy = maxy;
1113 /* ppux = canvas_width / (maxx - minx); */
1114 /* ppuy = canvas_height / (maxy - miny); */
1115 /* if(ppux < ppuy) */
1120 /* gnome_canvas_set_pixels_per_unit(GNOME_CANVAS(canvas), ppu); */
1121 gnome_canvas_set_scroll_region(GNOME_CANVAS(canvas), minx - X_MARGIN, miny - Y_MARGIN, maxx + X_MARGIN, maxy + Y_MARGIN);
1122 gnome_canvas_update_now(GNOME_CANVAS(canvas));
1125 double calculate_delta_m(int m)
1127 double dedxm, dedym, xmxi, ymyi;
1130 dedxm = dedym = 0.0;
1131 for(i = 0; i < number_of_nodes; i++)
1139 dedxm += k[m][i] * (xmxi - ((l[m][i] * xmxi) / sqrt(xmxi * xmxi + ymyi * ymyi)));
1140 dedym += k[m][i] * (xmxi - ((l[m][i] * xmxi) / sqrt(xmxi * xmxi + ymyi * ymyi)));
1143 return sqrt(dedxm * dedxm + dedym * dedym);
1146 void move_node(int m, double *dx, double *dy)
1148 double d2edxm2, d2edym2, d2edxmdym, dedxm, dedym;
1149 double xmxi, ymyi, denominator;
1152 d2edxm2 = d2edym2 = d2edxmdym = dedxm = dedym = 0.0;
1153 for(i = 0; i < number_of_nodes; i++)
1161 denominator = pow(sqrt(xmxi * xmxi + ymyi * ymyi), 3.0);
1163 d2edxm2 += k[m][i] * (1 - ((l[m][i] * ymyi * ymyi) / denominator));
1164 d2edxmdym += k[m][i] * l[m][i] * xmxi * ymyi / denominator;
1165 d2edym2 += k[m][i] * (1 - ((l[m][i] * xmxi * xmxi) / denominator));
1166 dedxm += k[m][i] * (xmxi - ((l[m][i] * xmxi) / sqrt(xmxi * xmxi + ymyi * ymyi)));
1167 dedym += k[m][i] * (ymyi - ((l[m][i] * ymyi) / sqrt(xmxi * xmxi + ymyi * ymyi)));
1170 denominator = ((d2edxm2 * d2edym2) - (d2edxmdym * d2edxmdym));
1171 *dx = (-(d2edym2 * dedxm) + (d2edxmdym * dedym)) / denominator;
1172 *dy = ((d2edxmdym * dedxm) - (d2edxm2 * dedym)) / denominator;
1175 void if_build_graph(void)
1178 double delta_m, max_delta_m;
1179 double dx, dy, s, L, min_d, old_x, old_y;
1187 for(i = 0; i < number_of_nodes; i++)
1189 x[i] = ((struct if_node_data*)(nodes[i]->data))->x;
1190 y[i] = ((struct if_node_data*)(nodes[i]->data))->y;
1193 /* Initialize Floyd */
1194 for(i = 0; i < number_of_nodes; i++)
1197 for(j = i + 1; j < number_of_nodes; j++)
1199 e = lookup_edge(nodes[i], nodes[j]);
1201 d[i][j] = d[j][i] = (double)e->weight;
1203 d[i][j] = d[j][i] = INFINITY;
1207 /* Floyd's shortest path algorithm */
1208 for(i = 0; i < number_of_nodes; i++)
1210 for(j = 0; j < number_of_nodes; j++)
1215 if(d[j][i] < INFINITY)
1217 for(p = 0; p < number_of_nodes; p++)
1219 if(d[i][j] < INFINITY)
1221 s = d[j][i] + d[i][p];
1233 for(i = 0; i < number_of_nodes; i++)
1234 for(j = i + 1; j < number_of_nodes; j++)
1235 if(d[i][j] < min_d && d[i][j] > 0.0)
1238 L = 5.0 / sqrt(min_d + 1.0);
1240 for(i = 0; i < number_of_nodes; i++)
1242 for(j = i + 1; j < number_of_nodes; j++)
1244 d[i][j] = d[j][i] = sqrt(d[i][j]+1.0);
1245 l[i][j] = l[j][i] = L * d[i][j];
1246 k[i][j] = k[j][i] = K / (d[i][j] * d[i][j]);
1254 /* Find node with maximal local energy */
1255 for(i = 0; i < number_of_nodes; i++)
1257 delta_m = calculate_delta_m(i);
1258 if(delta_m > max_delta_m)
1260 max_delta_m = delta_m;
1265 if(max_delta_m <= epsilon)
1267 fprintf(stderr, "Graph building is done; max_delta_m = %f\n", max_delta_m);
1272 int iter = 0, maxiter = 20;
1273 delta_m = max_delta_m;
1276 while(delta_m > epsilon && iter < maxiter)
1278 move_node(max_i, &dx, &dy);
1281 delta_m = calculate_delta_m(max_i);
1285 if_move_node(nodes[max_i], x[max_i] - old_x, y[max_i] - old_y);
1292 /* build_graph = 0; */