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.4 2002/04/28 12:46:26 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"
59 #define MAXBUFSIZE 1024
63 static GdkColormap *colormap = NULL;
64 static GdkColor timecolor;
72 #define INFINITY 1.0e10
74 node_t *nodes[MAX_NODES];
77 double k[MAX_NODES][MAX_NODES];
78 double d[MAX_NODES][MAX_NODES];
79 double l[MAX_NODES][MAX_NODES];
80 const double epsilon = 0.001;
82 static int inited = 0;
84 static int number_of_nodes = 0;
86 static GtkWidget *nodetree;
87 static GtkCTreeNode *hosts_ctn;
89 static GnomeCanvasGroup *edge_group = NULL;
91 static int canvas_width;
92 static int canvas_height;
94 static GtkWidget *canvas = NULL;
96 static int log_inited = 0;
97 static int follow_log = 1;
99 static int keep_drawing = 1;
101 static GtkCList *connlist = NULL;
103 static double canvas_zoom = 1.00;
105 void if_node_add(const char *hooktype, va_list ap);
106 void if_node_del(const char *hooktype, va_list ap);
107 void if_subnet_add(const char *hooktype, va_list ap);
108 void if_subnet_del(const char *hooktype, va_list ap);
109 void if_edge_add(const char *hooktype, va_list ap);
110 void if_edge_del(const char *hooktype, va_list ap);
111 void if_node_visible(const char *hooktype, va_list ap);
112 void if_node_invisible(const char *hooktype, va_list ap);
114 GtkWidget *create_canvas(void)
116 canvas = glade_xml_get_widget(xml, "canvas1");
119 fprintf(stderr, "Could not find widget `canvas1'\n");
123 gnome_canvas_set_scroll_region(GNOME_CANVAS(canvas), -00.0, -00.0, 700, 500);
125 canvas_width = 300.0;
126 canvas_height = 500.0;
131 void log_gtk(int level, int priority, char *fmt, va_list ap)
133 char buffer1[MAXBUFSIZE];
134 char buffer2[MAXBUFSIZE];
144 w = glade_xml_get_widget(xml, "Messages");
148 /* Use vsnprintf instead of vasprintf: faster, no memory
149 fragmentation, cleanup is automatic, and there is a limit on the
150 input buffer anyway */
151 len = vsnprintf(buffer1, MAXBUFSIZE, fmt, ap);
153 buffer1[MAXBUFSIZE-1] = '\0';
154 if((p = strrchr(buffer1, '\n')))
159 snprintf(buffer2, MAXBUFSIZE, "%02d:%02d:%02d ",
160 tm->tm_hour, tm->tm_min, tm->tm_sec);
164 colormap = gdk_colormap_new(gdk_visual_get_system(), FALSE);
165 timecolor.red = 0xffff;
168 if(gdk_colormap_alloc_color(colormap, &timecolor, FALSE, TRUE) != TRUE)
170 fprintf(stderr, "Failed to allocate color\n");
175 gtk_text_freeze(GTK_TEXT(w));
178 gtk_text_insert(GTK_TEXT(w), NULL, NULL, NULL, "\n", 1);
180 gtk_text_insert(GTK_TEXT(w), NULL, &timecolor, NULL, buffer2, strlen(buffer2));
181 gtk_text_insert(GTK_TEXT(w), NULL, NULL, NULL, buffer1, len);
182 gtk_text_thaw(GTK_TEXT(w));
186 /* gtk_text_set_point(GTK_TEXT(w), -1); */
187 gtk_editable_set_position(GTK_EDITABLE(w), gtk_text_get_length(GTK_TEXT(w)));
190 void if_hostinfoclosebutton_clicked(GtkWidget *w, gpointer data)
192 gtk_widget_destroy(GTK_WIDGET(data));
195 void update_hostinfo_dialog(GladeXML *x, node_t *n)
202 w = glade_xml_get_widget(x, "HostInfoNameEntry");
203 if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "HostInfoNameEntry"); return; }
204 gtk_entry_set_text(GTK_ENTRY(w), n->name);
206 w = glade_xml_get_widget(x, "HostInfoHostnameEntry");
207 if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "HostInfoHostnameEntry"); return; }
208 gtk_entry_set_text(GTK_ENTRY(w), n->hostname);
210 w = glade_xml_get_widget(x, "HostInfoPortEntry");
211 if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "HostInfoPortEntry"); return; }
212 /* snprintf(s, sizeof(s)-1, "%hd", "0"); */
213 gtk_entry_set_text(GTK_ENTRY(w), "port");
215 w = glade_xml_get_widget(x, "HostInfoVersionEntry");
216 if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "HostInfoVersionEntry"); return; }
217 gtk_entry_set_text(GTK_ENTRY(w), n->name);
219 w = glade_xml_get_widget(x, "HostInfoStatusEntry");
220 if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "HostInfoStatusEntry"); return; }
221 /* snprintf(s, sizeof(s)-1, "%x", n->status); */
222 gtk_entry_set_text(GTK_ENTRY(w), "0");
224 w = glade_xml_get_widget(x, "HostInfoActiveCheckbutton");
225 if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "HostInfoActiveCheckbutton"); return; }
226 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), n->status.active);
228 w = glade_xml_get_widget(x, "HostInfoValidkeyCheckbutton");
229 if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "HostInfoValidkeyCheckbutton"); return; }
230 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), n->status.validkey);
232 w = glade_xml_get_widget(x, "HostInfoWaitingforkeyCheckbutton");
233 if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "HostInfoWaitingforkeyCheckbutton"); return; }
234 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), n->status.waitingforkey);
236 w = glade_xml_get_widget(x, "HostInfoVisitedCheckbutton");
237 if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "HostInfoVisitedCheckbutton"); return; }
238 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), n->status.visited);
240 w = glade_xml_get_widget(x, "HostInfoReachableCheckbutton");
241 if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "HostInfoReachableCheckbutton"); return; }
242 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), n->status.reachable);
244 w = glade_xml_get_widget(x, "HostInfoIndirectCheckbutton");
245 if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "HostInfoIndirectCheckbutton"); return; }
246 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), n->status.indirect);
248 w = glade_xml_get_widget(x, "HostInfoVisibleCheckbutton");
249 if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "HostInfoVisibleCheckbutton"); return; }
250 /* gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), n->status.visible); */
252 w = glade_xml_get_widget(x, "HostInfoTCPOnlyCheckbutton");
253 if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "HostInfoTCPOnlyCheckbutton"); return; }
254 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), (n->options & OPTION_TCPONLY) != 0);
256 w = glade_xml_get_widget(x, "HostInfoIndirectdataCheckbutton");
257 if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "HostInfoIndirectdataCheckbutton"); return; }
258 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), (n->options & OPTION_INDIRECT) != 0);
260 /* w = glade_xml_get_widget(x, "HostInfoWindow"); */
261 /* if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "HostInfoWindow"); return; } */
262 /* glade_xml_signal_connect_data(x, "on_HostInfoCloseButton_clicked", if_hostinfoclosebutton_clicked, (gpointer)w); */
263 w = glade_xml_get_widget(x, "HostConnectionsCList");
264 if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "HostConnectionsCList"); return; }
265 for(avlnode = n->edge_tree->head; avlnode; avlnode = avlnode->next)
267 if(((edge_t*)(avlnode->data))->to.node == n)
268 l[0] = ((edge_t*)(avlnode->data))->from.node->name;
270 l[0] = ((edge_t*)(avlnode->data))->to.node->name;
271 gtk_clist_append(GTK_CLIST(w), l);
275 void on_settings1_activate(GtkMenuItem *mi, gpointer data)
280 x = glade_xml_new(INTERFACE_FILE, "PropertyBox");
284 _("Could not find widget `%s'"),
289 w = glade_xml_get_widget(x, "PropertyBox");
290 if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "PropertyBox"); return; }
291 glade_xml_signal_autoconnect(x);
294 void on_logcontext_clear_activate(GtkMenuItem *mi, gpointer data)
296 GtkWidget *l = glade_xml_get_widget(xml, "Messages");
297 if(!l) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "Messages"); return; }
298 gtk_editable_delete_text(GTK_EDITABLE(l), 0, -1); /* Delete from 0 to end of buffer */
302 void on_logcontext_follow_activate(GtkMenuItem *mi, gpointer data)
304 follow_log = !follow_log;
307 void on_messages_button_press_event(GtkWidget *w, GdkEventButton *event, gpointer data)
312 if (event->button == 3)
314 x = glade_xml_new(INTERFACE_FILE, "LogContextMenu");
318 _("Could not find widget `%s'"),
323 menu = glade_xml_get_widget(x, "LogContextMenu");
324 if(!menu) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "LogContextMenu"); return; }
326 glade_xml_signal_connect_data(x, "on_logcontext_clear_activate", on_logcontext_clear_activate, (gpointer)x);
327 glade_xml_signal_connect_data(x, "on_logcontext_follow_activate", on_logcontext_follow_activate, (gpointer)x);
328 w = glade_xml_get_widget(x, "LogContextFollow");
329 if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "LogContextFollow"); return; }
330 GTK_CHECK_MENU_ITEM(w)->active = follow_log;
331 gnome_popup_menu_do_popup_modal(menu, NULL, NULL, event, NULL);
332 gtk_widget_destroy(menu);
336 void on_canvascontext_shuffle_activate(GtkMenuItem *mi, gpointer data)
341 for(avlnode = node_tree->head; avlnode; avlnode = avlnode->next)
343 newx = ((double)random()) / ((double)RAND_MAX) * 500.0;
344 newy = ((double)random()) / ((double)RAND_MAX) * 300.0;
345 ((struct if_node_data*)((node_t *)(avlnode->data))->data)->x = newx;
346 ((struct if_node_data*)((node_t *)(avlnode->data))->data)->y = newy;
348 if(!((struct if_node_data*)((node_t*)(avlnode->data)))->visible)
351 x[((struct if_node_data*)((node_t*)(avlnode->data))->data)->id] = newx;
352 y[((struct if_node_data*)((node_t*)(avlnode->data))->data)->id] = newy;
358 void on_canvascontext_keep_drawing_activate(GtkMenuItem *mi, gpointer data)
360 keep_drawing = !keep_drawing;
363 void on_canvascontext_minus50_activate(GtkMenuItem *mi, gpointer data)
366 gnome_canvas_set_pixels_per_unit(GNOME_CANVAS(canvas), canvas_zoom);
369 void on_canvascontext_minus25_activate(GtkMenuItem *mi, gpointer data)
372 gnome_canvas_set_pixels_per_unit(GNOME_CANVAS(canvas), canvas_zoom);
375 void on_canvascontext_minus10_activate(GtkMenuItem *mi, gpointer data)
378 gnome_canvas_set_pixels_per_unit(GNOME_CANVAS(canvas), canvas_zoom);
381 void on_canvascontext_default_activate(GtkMenuItem *mi, gpointer data)
384 gnome_canvas_set_pixels_per_unit(GNOME_CANVAS(canvas), 1.00);
387 void on_canvascontext_plus10_activate(GtkMenuItem *mi, gpointer data)
390 gnome_canvas_set_pixels_per_unit(GNOME_CANVAS(canvas), canvas_zoom);
393 void on_canvascontext_plus25_activate(GtkMenuItem *mi, gpointer data)
396 gnome_canvas_set_pixels_per_unit(GNOME_CANVAS(canvas), canvas_zoom);
399 void on_canvascontext_plus50_activate(GtkMenuItem *mi, gpointer data)
402 gnome_canvas_set_pixels_per_unit(GNOME_CANVAS(canvas), canvas_zoom);
405 void on_canvas_button_press_event(GtkWidget *w, GdkEventButton *event, gpointer data)
410 if (event->button == 3)
412 x = glade_xml_new(INTERFACE_FILE, "CanvasContextMenu");
416 _("Could not find widget `%s'"),
417 "CanvasContextMenu");
421 menu = glade_xml_get_widget(x, "CanvasContextMenu");
422 if(!menu) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "CanvasContextMenu"); return; }
424 glade_xml_signal_autoconnect(x);
425 glade_xml_signal_connect_data(x, "on_canvascontext_shuffle_activate", on_canvascontext_shuffle_activate, (gpointer)x);
426 glade_xml_signal_connect_data(x, "on_canvascontext_keep_drawing_activate", on_canvascontext_keep_drawing_activate, (gpointer)x);
427 w = glade_xml_get_widget(x, "CanvasContextKeepDrawing");
428 if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "CanvasContextKeepDrawing"); return; }
429 GTK_CHECK_MENU_ITEM(w)->active = keep_drawing;
430 gnome_popup_menu_do_popup_modal(menu, NULL, NULL, event, NULL);
431 gtk_widget_destroy(menu);
435 void on_nodetree_button_press_event(GtkWidget *w, GdkEventButton *event, gpointer data)
442 gtk_clist_get_selection_info(GTK_CLIST(w), event->x, event->y,
445 node = gtk_ctree_node_nth(GTK_CTREE(w), row);
448 lt = gtk_ctree_node_get_row_data(GTK_CTREE(w), node);
449 if(event->type == GDK_2BUTTON_PRESS && event->button == 1)
451 /* Double left click on an item */
453 /* this is only a branch, double click wil (un)expand. */
456 if(GTK_CTREE_ROW(node)->parent == hosts_ctn)
458 x = ((struct if_node_data*)(((node_t*)lt)->data))->hi_xml = glade_xml_new(INTERFACE_FILE, "HostInfoWindow");
462 _("Could not find widget `%s'"),
466 glade_xml_signal_autoconnect(x);
467 update_hostinfo_dialog(x, (node_t*)lt);
472 "WHERE did you click?!");
474 /* so now we have access to all the data we want. */
475 /* gldap_show_details(lt); */
479 /* if (event->button == 3) */
481 /* GtkWidget *temp_menu; */
482 /* temp_menu = gnome_popup_menu_new(data); */
483 /* gnome_popup_menu_do_popup_modal(temp_menu, NULL, NULL, event, NULL); */
484 /* gtk_widget_destroy(temp_menu); */
488 void on_exit1_activate(GtkMenuItem *mi, gpointer data)
490 close_network_connections();
494 void on_info1_activate(GtkMenuItem *mi, gpointer data)
497 x = glade_xml_new(INTERFACE_FILE, "AboutWindow");
501 _("Could not find widget `%s'"),
507 int init_interface(void)
513 xml = glade_xml_new("pokey.glade", "AppWindow");
518 _("Something bad happened while creating the interface.\n"));
522 nodetree = glade_xml_get_widget(xml, "NodeTree");
526 _("Could not find widget `%s'"),
531 gtk_clist_freeze(GTK_CLIST(nodetree));
533 hosts_ctn = gtk_ctree_insert_node(GTK_CTREE(nodetree),
535 NULL, NULL, NULL, NULL,
537 gtk_clist_thaw(GTK_CLIST(nodetree));
541 glade_xml_signal_autoconnect(xml);
543 log_add_hook(log_gtk);
544 log_del_hook(log_default);
546 add_hook("node-add", if_node_add);
547 add_hook("node-del", if_node_del);
548 add_hook("subnet-add", if_subnet_add);
549 add_hook("subnet-del", if_subnet_del);
550 add_hook("edge-add", if_edge_add);
551 add_hook("edge-del", if_edge_del);
552 add_hook("node-visible", if_node_visible);
553 add_hook("node-invisible", if_node_invisible);
558 static gint item_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data)
560 static double item_x, old_x, new_x, item_y, old_y, new_y;
561 static int dragging = FALSE;
565 item_x = event->button.x;
566 item_y = event->button.y;
567 gnome_canvas_item_w2i(item->parent, &item_x, &item_y);
571 case GDK_BUTTON_PRESS:
572 switch(event->button.button)
578 fleur = gdk_cursor_new(GDK_FLEUR);
579 gnome_canvas_item_grab(item, GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK, fleur, event->button.time);
580 gdk_cursor_destroy(fleur);
589 case GDK_MOTION_NOTIFY:
590 if(dragging && (event->motion.state & GDK_BUTTON1_MASK))
594 gnome_canvas_item_move(item, new_x - old_x, new_y - old_y);
600 case GDK_BUTTON_RELEASE:
601 gnome_canvas_item_ungrab(item, event->button.time);
603 n = (node_t *)gtk_object_get_user_data(GTK_OBJECT(item));
604 ((struct if_node_data*)(n->data))->x = item_x;
605 ((struct if_node_data*)(n->data))->y = item_y;
606 x[((struct if_node_data*)(n->data))->id] = item_x;
607 y[((struct if_node_data*)(n->data))->id] = item_y;
617 void if_node_create(node_t *n)
619 GnomeCanvasGroup *group;
621 group = gnome_canvas_root(GNOME_CANVAS(canvas));
622 group = GNOME_CANVAS_GROUP(gnome_canvas_item_new(group,
623 gnome_canvas_group_get_type(),
628 gnome_canvas_item_new(group, gnome_canvas_ellipse_get_type(),
633 "fill_color_rgba", 0x5f9ea080,
634 "outline_color", "black",
638 gnome_canvas_item_new(group,
639 gnome_canvas_text_get_type(),
643 "anchor", GTK_ANCHOR_CENTER,
644 "fill_color", "white",
645 "font", "-*-verdana-medium-r-*-*-10-*-*-*-*-*-iso8859-1",
648 ((struct if_node_data*)(n->data))->item = GNOME_CANVAS_ITEM(group);
649 ((struct if_node_data*)(n->data))->x = ((struct if_node_data*)(n->data))->y = 0.0;
650 gtk_object_set_user_data(GTK_OBJECT(group), (gpointer)n);
652 gtk_signal_connect(GTK_OBJECT(((struct if_node_data*)(n->data))->item), "event", (GtkSignalFunc) item_event, NULL);
654 gnome_canvas_item_hide(GNOME_CANVAS_ITEM(((struct if_node_data*)(n->data))->item));
657 void if_node_visible(const char *hooktype, va_list ap)
662 node_t *n = va_arg(ap, node_t*);
664 if(!((struct if_node_data*)(n->data))->item)
667 if(((struct if_node_data*)(n->data))->visible)
668 /* This node is already shown */
671 ((struct if_node_data*)(n->data))->visible = 1;
673 newx = 250.0 + 200.0 * sin(number_of_nodes / 10.0 * M_PI);
674 newy = 150.0 - 100.0 * cos(number_of_nodes / 10.0 * M_PI);
675 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);
676 ((struct if_node_data*)(n->data))->x = newx;
677 ((struct if_node_data*)(n->data))->y = newy;
679 for(i = 0, avlnode = node_tree->head; avlnode; avlnode = avlnode->next, i++)
681 if(!((struct if_node_data*)(((node_t*)(avlnode->data))->data))->visible)
684 nodes[i] = (node_t *)(avlnode->data);
685 ((struct if_node_data*)(nodes[i]->data))->id = i;
689 gnome_canvas_item_show(GNOME_CANVAS_ITEM(((struct if_node_data*)(n->data))->item));
690 gnome_canvas_update_now(GNOME_CANVAS(canvas));
692 /* (Re)start calculations */
697 void if_node_invisible(const char *hooktype, va_list ap)
701 node_t *n = va_arg(ap, node_t*);
703 if(!((struct if_node_data*)(n->data))->item)
706 if(!((struct if_node_data*)(n->data))->visible)
707 /* This node is already invisible */
710 ((struct if_node_data*)(n->data))->visible = 0;
712 for(i = 0, avlnode = node_tree->head; avlnode; avlnode = avlnode->next, i++)
714 if(!((struct if_node_data*)((node_t*)(avlnode->data))->data)->visible)
717 nodes[i] = (node_t *)(avlnode->data);
718 ((struct if_node_data*)(nodes[i]->data))->id = i;
722 gnome_canvas_item_hide(GNOME_CANVAS_ITEM(((struct if_node_data*)(n->data))->item));
723 gnome_canvas_update_now(GNOME_CANVAS(canvas));
725 /* (Re)start calculations */
730 void if_node_add(const char *hooktype, va_list ap)
732 node_t *n = va_arg(ap, node_t*);
734 struct if_node_data *nd;
739 nd = xmalloc(sizeof(*nd));
741 gtk_clist_freeze(GTK_CLIST(nodetree));
742 nd->ctn = gtk_ctree_insert_node(GTK_CTREE(nodetree),
743 hosts_ctn, NULL, l, 1,
744 NULL, NULL, NULL, NULL,
746 gtk_clist_thaw(GTK_CLIST(nodetree));
747 gtk_ctree_node_set_row_data(GTK_CTREE(nodetree), nd->ctn, n);
752 if_node_visible(hooktype, ap);
755 void if_node_del(const char *hooktype, va_list ap)
757 node_t *n = va_arg(ap, node_t*);
758 struct if_node_data *nd;
760 nd = (struct if_node_data*)(n->data);
763 gtk_clist_freeze(GTK_CLIST(nodetree));
764 gtk_ctree_remove_node(GTK_CTREE(nodetree), nd->ctn);
765 gtk_clist_thaw(GTK_CLIST(nodetree));
768 if_node_invisible(hooktype, ap);
774 void if_subnet_add(const char *hooktype, va_list ap)
777 subnet_t *subnet = va_arg(ap, subnet_t*);
778 struct if_subnet_data *sd;
779 GtkCTreeNode *parent;
781 sd = xmalloc(sizeof(*sd));
782 l[0] = net2str(subnet);
783 parent = subnet->owner->data ?
784 ((struct if_subnet_data*)(subnet->owner->data))->ctn
787 gtk_clist_freeze(GTK_CLIST(nodetree));
788 sd->ctn = gtk_ctree_insert_node(GTK_CTREE(nodetree),
790 NULL, NULL, NULL, NULL,
792 gtk_clist_thaw(GTK_CLIST(nodetree));
793 gtk_ctree_node_set_row_data(GTK_CTREE(nodetree), sd->ctn, subnet);
795 subnet->data = (void*)sd;
798 void if_subnet_del(const char *hooktype, va_list ap)
800 subnet_t *subnet = va_arg(ap, subnet_t*);
801 struct if_subnet_data *sd;
803 sd = (struct if_subnet_data*)(subnet->data);
806 gtk_clist_freeze(GTK_CLIST(nodetree));
807 gtk_ctree_remove_node(GTK_CTREE(nodetree), sd->ctn);
808 gtk_clist_thaw(GTK_CLIST(nodetree));
815 void redraw_edges(void)
817 GnomeCanvasGroup *group;
818 GnomeCanvasPoints *points;
821 struct if_node_data *fd, *td;
824 gtk_object_destroy(GTK_OBJECT(edge_group));
826 group = gnome_canvas_root(GNOME_CANVAS(canvas));
827 group = GNOME_CANVAS_GROUP(gnome_canvas_item_new(group,
828 gnome_canvas_group_get_type(),
833 for(avlnode = edge_tree->head; avlnode; avlnode = avlnode->next)
835 e = (edge_t *)avlnode->data;
836 fd = (struct if_node_data*)(e->from.node->data);
837 td = (struct if_node_data*)(e->to.node->data);
839 /* if(!e->from.node->status.visible || */
840 /* !e->to.node->status.visible) */
841 /* /\* We shouldn't draw this line *\/ */
844 points = gnome_canvas_points_new(2);
846 points->coords[0] = fd->x;
847 points->coords[1] = fd->y;
848 points->coords[2] = td->x;
849 points->coords[3] = td->y;
850 gnome_canvas_item_new(group,
851 gnome_canvas_line_get_type(),
853 "fill_color_rgba", 0xe080c080,
856 gnome_canvas_points_unref(points);
859 gnome_canvas_update_now(GNOME_CANVAS(canvas));
864 void if_edge_add(const char *hooktype, va_list ap)
872 void if_edge_del(const char *hooktype, va_list ap)
880 void if_move_node(node_t *n, double dx, double dy)
884 newx = ((struct if_node_data*)(n->data))->x + dx;
885 newy = ((struct if_node_data*)(n->data))->y + dy;
886 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);
887 ((struct if_node_data*)(n->data))->x = newx;
888 ((struct if_node_data*)(n->data))->y = newy;
891 #define X_MARGIN 50.0
892 #define X_MARGIN_BUFFER 25.0
893 #define Y_MARGIN 20.0
894 #define Y_MARGIN_BUFFER 10.0
896 void set_zooming(void)
899 double minx, miny, maxx, maxy;
900 static double ominx = 0.0, ominy = 0.0, omaxx = 0.0, omaxy = 0.0;
902 minx = miny = maxx = maxy = 0.0;
903 for(i = 0; i < number_of_nodes; i++)
905 if(((struct if_node_data*)(nodes[i]->data))->x < minx)
906 minx = ((struct if_node_data*)(nodes[i]->data))->x;
908 if(((struct if_node_data*)(nodes[i]->data))->x > maxx)
909 maxx = ((struct if_node_data*)(nodes[i]->data))->x;
911 if(((struct if_node_data*)(nodes[i]->data))->y < miny)
912 miny = ((struct if_node_data*)(nodes[i]->data))->y;
914 if(((struct if_node_data*)(nodes[i]->data))->y > maxy)
915 maxy = ((struct if_node_data*)(nodes[i]->data))->y;
918 if(minx > ominx - X_MARGIN_BUFFER && ominx > minx)
920 if(maxx < omaxx + X_MARGIN_BUFFER && omaxx < maxx)
922 if(miny > ominy - Y_MARGIN_BUFFER && ominy > miny)
924 if(maxy < omaxy + Y_MARGIN_BUFFER && omaxy < maxy)
927 ominx = minx; ominy = miny; omaxx = maxx; omaxy = maxy;
929 /* ppux = canvas_width / (maxx - minx); */
930 /* ppuy = canvas_height / (maxy - miny); */
931 /* if(ppux < ppuy) */
936 /* gnome_canvas_set_pixels_per_unit(GNOME_CANVAS(canvas), ppu); */
937 gnome_canvas_set_scroll_region(GNOME_CANVAS(canvas), minx - X_MARGIN, miny - Y_MARGIN, maxx + X_MARGIN, maxy + Y_MARGIN);
938 gnome_canvas_update_now(GNOME_CANVAS(canvas));
941 double calculate_delta_m(int m)
943 double dedxm, dedym, xmxi, ymyi;
947 for(i = 0; i < number_of_nodes; i++)
955 dedxm += k[m][i] * (xmxi - ((l[m][i] * xmxi) / sqrt(xmxi * xmxi + ymyi * ymyi)));
956 dedym += k[m][i] * (xmxi - ((l[m][i] * xmxi) / sqrt(xmxi * xmxi + ymyi * ymyi)));
959 return sqrt(dedxm * dedxm + dedym * dedym);
962 void move_node(int m, double *dx, double *dy)
964 double d2edxm2, d2edym2, d2edxmdym, dedxm, dedym;
965 double xmxi, ymyi, denominator;
968 d2edxm2 = d2edym2 = d2edxmdym = dedxm = dedym = 0.0;
969 for(i = 0; i < number_of_nodes; i++)
977 denominator = pow(sqrt(xmxi * xmxi + ymyi * ymyi), 3.0);
979 d2edxm2 += k[m][i] * (1 - ((l[m][i] * ymyi * ymyi) / denominator));
980 d2edxmdym += k[m][i] * l[m][i] * xmxi * ymyi / denominator;
981 d2edym2 += k[m][i] * (1 - ((l[m][i] * xmxi * xmxi) / denominator));
982 dedxm += k[m][i] * (xmxi - ((l[m][i] * xmxi) / sqrt(xmxi * xmxi + ymyi * ymyi)));
983 dedym += k[m][i] * (ymyi - ((l[m][i] * ymyi) / sqrt(xmxi * xmxi + ymyi * ymyi)));
986 denominator = ((d2edxm2 * d2edym2) - (d2edxmdym * d2edxmdym));
987 *dx = (-(d2edym2 * dedxm) + (d2edxmdym * dedym)) / denominator;
988 *dy = ((d2edxmdym * dedxm) - (d2edxm2 * dedym)) / denominator;
991 void if_build_graph(void)
994 double delta_m, max_delta_m;
995 double dx, dy, s, L, min_d, old_x, old_y;
1003 for(i = 0; i < number_of_nodes; i++)
1005 x[i] = ((struct if_node_data*)(nodes[i]->data))->x;
1006 y[i] = ((struct if_node_data*)(nodes[i]->data))->y;
1009 /* Initialize Floyd */
1010 for(i = 0; i < number_of_nodes; i++)
1013 for(j = i + 1; j < number_of_nodes; j++)
1015 e = lookup_edge(nodes[i], nodes[j]);
1017 d[i][j] = d[j][i] = (double)e->weight;
1019 d[i][j] = d[j][i] = INFINITY;
1023 /* Floyd's shortest path algorithm */
1024 for(i = 0; i < number_of_nodes; i++)
1026 for(j = 0; j < number_of_nodes; j++)
1031 if(d[j][i] < INFINITY)
1033 for(p = 0; p < number_of_nodes; p++)
1035 if(d[i][j] < INFINITY)
1037 s = d[j][i] + d[i][p];
1049 for(i = 0; i < number_of_nodes; i++)
1050 for(j = i + 1; j < number_of_nodes; j++)
1051 if(d[i][j] < min_d && d[i][j] > 0)
1054 L = 5.0 / sqrt(min_d + 1.0);
1056 for(i = 0; i < number_of_nodes; i++)
1058 for(j = i + 1; j < number_of_nodes; j++)
1060 d[i][j] = d[j][i] = sqrt(d[i][j]+1.0);
1061 l[i][j] = l[j][i] = L * d[i][j];
1062 k[i][j] = k[j][i] = K / (d[i][j] * d[i][j]);
1070 /* Find node with maximal local energy */
1071 for(i = 0; i < number_of_nodes; i++)
1073 delta_m = calculate_delta_m(i);
1074 if(delta_m > max_delta_m)
1076 max_delta_m = delta_m;
1081 if(max_delta_m <= epsilon)
1083 fprintf(stderr, "Graph building is done; max_delta_m = %f\n", max_delta_m);
1088 int iter = 0, maxiter = 20;
1089 delta_m = max_delta_m;
1092 while(delta_m > epsilon && iter < maxiter)
1094 move_node(max_i, &dx, &dy);
1097 delta_m = calculate_delta_m(max_i);
1101 if_move_node(nodes[max_i], x[max_i] - old_x, y[max_i] - old_y);
1108 /* build_graph = 0; */