/* * ni-window-interface.c * This file is part of NetworkInador * * Copyright (C) 2021 - Gatuno * * NetworkInador 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. * * NetworkInador 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 NetworkInador; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include #include #include #include "ni-window-interface.h" #include "ni-client.h" #include "ni-interface.h" #include "ni-ip.h" #include "ni-ip-add-dialog.h" struct _NIWindowInterfacePrivate { NIInterface *ni_interface; GtkWidget *vbox, *notebook; GtkWidget *vbox_ipv4, *vbox_ipv6, *vbox_info; GtkWidget *info_name, *info_updown; GtkWidget *button_name_apply, *button_name_revert; GtkWidget *button_up, *button_down; GtkListStore *ipv4_store, *ipv6_store; GtkWidget *del_ipv4_button, *del_ipv6_button; GtkWidget *tree_ipv4, *tree_ipv6; }; enum { PROP_NI_INTERFACE = 1, N_PROPERTIES }; enum { IP_STORE_COL_MAIN_IP, IP_STORE_COL_BROADCAST, IP_STORE_COL_OBJECT, NUM_IP_STORE_COLS }; static void ni_window_interface_addr_added_cb (NIWindowInterface *window_iface, NIIP *ni_ip); void ni_window_interface_update_state_from_flags (NIWindowInterface *window_iface); static void ni_window_interface_name_cancel_cb (GtkWidget *widget, gpointer data); G_DEFINE_TYPE_WITH_PRIVATE (NIWindowInterface, ni_window_interface, GTK_TYPE_WINDOW) static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, }; #if 0 static GObject *ni_interface_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties) { GObject *obj; GObjectClass *parent_class = G_OBJECT_CLASS (g_type_class_peek (GTK_TYPE_WINDOW)); NIInterface *ni_interface; obj = parent_class->constructor (type, n_construct_properties, construct_properties); ni_interface = NI_INTERFACE (obj); { int g; for (g = 0; g < n_construct_properties; g++) { GParamSpec *pspec = construct_properties[g].pspec; GValue *value = construct_properties[g].value; /* Manejar el valor */ if (strcmp (g_param_spec_get_name (pspec), "index") == 0) { printf ("Estableciendo sobre el constructor, el index\n"); ni_interface->priv->index = g_value_get_uint (value); ni_interface_check_and_connect_signal (ni_interface); } else if (strcmp (g_param_spec_get_name (pspec), "ni-client") == 0) { ni_interface->priv->ni_client = NI_CLIENT (g_value_get_object (value)); } } } return obj; } #endif static gboolean ni_window_interface_delete_event (GtkWidget *widget, GdkEventAny *event) { /* Restaurar la caja original del nombre de la interfaz, si está cambiada */ ni_window_interface_name_cancel_cb (NULL, widget); return gtk_widget_hide_on_delete (widget); } static void has_ip_selected_v4_cb (GtkTreeSelection *selection, gpointer user_data) { NIWindowInterface *window_iface = (NIWindowInterface *) user_data; if (gtk_tree_selection_count_selected_rows (selection) > 0) { gtk_widget_set_sensitive (window_iface->priv->del_ipv4_button, TRUE); } else { gtk_widget_set_sensitive (window_iface->priv->del_ipv4_button, FALSE); } } static void has_ip_selected_v6_cb (GtkTreeSelection *selection, gpointer user_data) { NIWindowInterface *window_iface = (NIWindowInterface *) user_data; if (gtk_tree_selection_count_selected_rows (selection) > 0) { gtk_widget_set_sensitive (window_iface->priv->del_ipv6_button, TRUE); } else { gtk_widget_set_sensitive (window_iface->priv->del_ipv6_button, FALSE); } } static void ni_window_interface_addr_button_add_cb (GtkWidget *widget, int family, gpointer data) { NIWindowInterface *window_iface = (NIWindowInterface *) data; GtkWidget *dialog; gint response; NIClient *ni_client; struct_addr addr, p2p_addr; int prefix; gboolean has_p2p; uint32_t flags = 0; dialog = ni_ip_add_dialog_new (family); gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (window_iface)); gtk_window_set_modal (GTK_WINDOW (dialog), TRUE); response = gtk_dialog_run (GTK_DIALOG (dialog)); if (response == GTK_RESPONSE_OK) { /* Mandar la ip al network-inador */ ni_client = ni_interface_get_client (window_iface->priv->ni_interface); ni_ip_add_dialog_get_address (NI_IP_ADD_DIALOG (dialog), &addr, &prefix); has_p2p = ni_ip_add_dialog_has_p2p_address (NI_IP_ADD_DIALOG (dialog)); if (has_p2p) { memcpy (&p2p_addr, &addr, sizeof (p2p_addr)); ni_ip_add_dialog_get_p2p_address (NI_IP_ADD_DIALOG (dialog), &addr); } flags |= IFA_F_PERMANENT; if (ni_ip_add_dialog_get_noprefix (NI_IP_ADD_DIALOG (dialog))) { flags |= IFA_F_NOPREFIXROUTE; } //void ni_client_ask_ip_new (NIClient *ni_client, NIInterface *ni_interface, int family, int prefix, struct_addr *addr, uint32_t flags, unsigned char scope, int has_local, struct_addr *local_addr, int has_brd, struct_addr *brd_addr) { ni_client_ask_ip_new (ni_client, window_iface->priv->ni_interface, family, prefix, &addr, flags, 0, has_p2p, (has_p2p ? &p2p_addr : NULL), FALSE, NULL); } gtk_widget_destroy (dialog); } static void ni_window_interface_addr_button_del_cb (GtkWidget *widget, int family, gpointer data) { NIWindowInterface *window_iface = (NIWindowInterface *) data; GtkTreeIter iter; GtkTreeModel *model; GtkTreeSelection *selection; NIIP *ni_ip; if (family == AF_INET) { selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (window_iface->priv->tree_ipv4)); } else if (family == AF_INET6) { selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (window_iface->priv->tree_ipv6)); } gtk_tree_selection_get_selected (selection, &model, &iter); gtk_tree_model_get (model, &iter, IP_STORE_COL_OBJECT, &ni_ip, -1); ni_client_ask_ip_delete (ni_interface_get_client (window_iface->priv->ni_interface), window_iface->priv->ni_interface, ni_ip); } static void ni_window_interface_addr_v4_button_add_cb (GtkWidget *widget, gpointer data) { ni_window_interface_addr_button_add_cb (widget, AF_INET, data); } static void ni_window_interface_addr_v6_button_add_cb (GtkWidget *widget, gpointer data) { ni_window_interface_addr_button_add_cb (widget, AF_INET6, data); } static void ni_window_interface_addr_v4_button_del_cb (GtkWidget *widget, gpointer data) { ni_window_interface_addr_button_del_cb (widget, AF_INET, data); } static void ni_window_interface_addr_v6_button_del_cb (GtkWidget *widget, gpointer data) { ni_window_interface_addr_button_del_cb (widget, AF_INET6, data); } /* Evento cuando cambian el nombre de la interfaz en el entry */ static void ni_window_interface_name_edit_cb (GtkEditable *editable, gpointer data) { NIWindowInterface *window_iface = (NIWindowInterface *) data; const gchar *original_name = ni_interface_get_name (window_iface->priv->ni_interface); const gchar *current_name = gtk_entry_get_text (GTK_ENTRY (window_iface->priv->info_name)); if (current_name[0] == 0) { gtk_widget_set_sensitive (window_iface->priv->button_name_apply, FALSE); gtk_widget_set_sensitive (window_iface->priv->button_name_revert, TRUE); } else if (strcmp (original_name, current_name) == 0) { gtk_widget_set_sensitive (window_iface->priv->button_name_apply, FALSE); gtk_widget_set_sensitive (window_iface->priv->button_name_revert, FALSE); } else { gtk_widget_set_sensitive (window_iface->priv->button_name_apply, TRUE); gtk_widget_set_sensitive (window_iface->priv->button_name_revert, TRUE); } } static void ni_window_interface_name_cancel_cb (GtkWidget *widget, gpointer data) { NIWindowInterface *window_iface = (NIWindowInterface *) data; gtk_entry_set_text (GTK_ENTRY (window_iface->priv->info_name), ni_interface_get_name (window_iface->priv->ni_interface)); gtk_widget_set_sensitive (window_iface->priv->button_name_apply, FALSE); gtk_widget_set_sensitive (window_iface->priv->button_name_revert, FALSE); } static void ni_window_interface_name_apply_cb (GtkWidget *widget, gpointer data) { NIWindowInterface *window_iface = (NIWindowInterface *) data; const gchar *new_name; if (gtk_widget_get_sensitive (window_iface->priv->button_name_apply) == FALSE) { return; } new_name = gtk_entry_get_text (GTK_ENTRY (window_iface->priv->info_name)); ni_interface_set_name (window_iface->priv->ni_interface, new_name); /* TODO: Activar el ícono de "cargando" en el entry gtk_entry_set_icon_from_gicon (GTK_ENTRY (window_iface->priv->info_name), GTK_ENTRY_ICON_SECONDARY, */ gtk_widget_set_sensitive (window_iface->priv->button_name_apply, FALSE); gtk_widget_set_sensitive (window_iface->priv->button_name_revert, FALSE); } static void ni_window_interface_down_cb (GtkWidget *widget, gpointer data) { NIWindowInterface *window_iface = (NIWindowInterface *) data; ni_interface_set_down (window_iface->priv->ni_interface); } static void ni_window_interface_up_cb (GtkWidget *widget, gpointer data) { NIWindowInterface *window_iface = (NIWindowInterface *) data; ni_interface_set_up (window_iface->priv->ni_interface); } /* Eventos que vienen del network-inador */ static void ni_window_interface_addr_added_cb (NIWindowInterface *window_iface, NIIP *ni_ip) { GtkTreeIter iter; char buffer[256], ip[128], local[128]; guint prefix, family, family_size; family = ni_ip_get_family (ni_ip); inet_ntop (family, ni_ip_get_addr (ni_ip), ip, sizeof (ip)); prefix = ni_ip_get_prefix (ni_ip); if (family == AF_INET) { family_size = sizeof (struct in_addr); } else if (family == AF_INET6) { family_size = sizeof (struct in6_addr); } if (ni_ip_has_local (ni_ip) && memcmp (ni_ip_get_local_addr (ni_ip), ni_ip_get_addr (ni_ip), family_size) != 0) { inet_ntop (family, ni_ip_get_local_addr (ni_ip), local, sizeof (local)); snprintf (buffer, sizeof (buffer), "%s peer %s/%u", local, ip, prefix); } else { snprintf (buffer, sizeof (buffer), "%s/%u", ip, prefix); } if (family == AF_INET) { gtk_list_store_insert (window_iface->priv->ipv4_store, &iter, -1); gtk_list_store_set (window_iface->priv->ipv4_store, &iter, IP_STORE_COL_MAIN_IP, buffer, IP_STORE_COL_OBJECT, ni_ip, -1); } else if (family == AF_INET6) { gtk_list_store_insert (window_iface->priv->ipv6_store, &iter, -1); gtk_list_store_set (window_iface->priv->ipv6_store, &iter, IP_STORE_COL_MAIN_IP, buffer, IP_STORE_COL_OBJECT, ni_ip, -1); } } static void ni_window_interface_new_ip_cb (NIInterface *ni_interface, NIIP *ni_ip, gpointer data) { NIWindowInterface *window_iface = NI_WINDOW_INTERFACE (data); ni_window_interface_addr_added_cb (window_iface, ni_ip); } static void ni_window_interface_delete_ip_cb (NIInterface *ni_interface, NIIP *ni_ip, gpointer data) { GtkTreeIter iter; NIWindowInterface *window_iface = NI_WINDOW_INTERFACE (data); gboolean has; guint family; GtkListStore *p; void *iter_obj; family = ni_ip_get_family (ni_ip); if (family == AF_INET) { p = window_iface->priv->ipv4_store; } else if (family == AF_INET6) { p = window_iface->priv->ipv6_store; } has = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (p), &iter); while (has) { gtk_tree_model_get (GTK_TREE_MODEL (p), &iter, IP_STORE_COL_OBJECT, &iter_obj, -1); if (iter_obj == ni_ip) { /* Eliminar este objeto */ gtk_list_store_remove (p, &iter); return; } has = gtk_tree_model_iter_next (GTK_TREE_MODEL (p), &iter); } } static void ni_window_interface_changed_name_cb (GObject *object, GParamSpec *sp, gpointer data) { NIInterface *ni_interface = NI_INTERFACE (object); NIWindowInterface *window_iface = NI_WINDOW_INTERFACE (data); gchar *name; /* Cambiar el título */ name = g_strdup_printf ("Interfaz %s", ni_interface_get_name (window_iface->priv->ni_interface)); gtk_window_set_title (GTK_WINDOW (window_iface), name); /* Cambiar la label que corresponde al nombre */ gtk_entry_set_text (GTK_ENTRY (window_iface->priv->info_name), ni_interface_get_name (window_iface->priv->ni_interface)); gtk_widget_set_sensitive (window_iface->priv->button_name_apply, FALSE); gtk_widget_set_sensitive (window_iface->priv->button_name_revert, FALSE); g_free (name); } static void ni_window_interface_changed_flags_cb (GObject *object, GParamSpec *sp, gpointer data) { NIWindowInterface *window_iface = NI_WINDOW_INTERFACE (data); ni_window_interface_update_state_from_flags (window_iface); } void ni_window_interface_update_state_from_flags (NIWindowInterface *window_iface) { guint flags; /* Recuperar las flags */ flags = ni_interface_get_flags (window_iface->priv->ni_interface); if (flags & IFF_UP) { gtk_widget_set_sensitive (window_iface->priv->info_name, FALSE); gtk_widget_set_sensitive (window_iface->priv->button_name_apply, FALSE); gtk_widget_set_sensitive (window_iface->priv->button_name_revert, FALSE); gtk_entry_set_text (GTK_ENTRY (window_iface->priv->info_name), ni_interface_get_name (window_iface->priv->ni_interface)); gtk_label_set_text (GTK_LABEL (window_iface->priv->info_updown), "UP"); } else { gtk_widget_set_sensitive (window_iface->priv->info_name, TRUE); gtk_label_set_text (GTK_LABEL (window_iface->priv->info_updown), "DOWN"); } } /* Construcción del objeto */ static void ni_window_interface_constructed (GObject *obj) { GObjectClass *parent_class = G_OBJECT_CLASS (g_type_class_peek (GTK_TYPE_WINDOW)); NIWindowInterface *window_iface = NI_WINDOW_INTERFACE (obj); const GList *ip_list, *g; NIIP *ni_ip; gchar *name; guint flags; parent_class->constructed (obj); if (window_iface->priv->ni_interface == NULL) return; /* Cambiar el título */ name = g_strdup_printf ("Interfaz %s", ni_interface_get_name (window_iface->priv->ni_interface)); gtk_window_set_title (GTK_WINDOW (obj), name); g_free (name); /* TODO: Recorrer las ips, y procesar la información */ ip_list = ni_interface_get_ip_list (window_iface->priv->ni_interface); for (g = ip_list; g != NULL; g = g->next) { ni_ip = (NIIP *) g->data; ni_window_interface_addr_added_cb (window_iface, ni_ip); } /* Conectar la señal de IP agregada y la señal de IP eliminada */ g_signal_connect (window_iface->priv->ni_interface, "new-ip", G_CALLBACK (ni_window_interface_new_ip_cb), window_iface); g_signal_connect (window_iface->priv->ni_interface, "delete-ip", G_CALLBACK (ni_window_interface_delete_ip_cb), window_iface); g_signal_connect (window_iface->priv->ni_interface, "notify::name", G_CALLBACK (ni_window_interface_changed_name_cb), window_iface); g_signal_connect (window_iface->priv->ni_interface, "notify::flags", G_CALLBACK (ni_window_interface_changed_flags_cb), window_iface); gtk_entry_set_text (GTK_ENTRY (window_iface->priv->info_name), ni_interface_get_name (window_iface->priv->ni_interface)); ni_window_interface_update_state_from_flags (window_iface); } static void ni_window_interface_dispose (GObject *obj) { NIWindowInterface *window_iface; GObjectClass *parent_class = G_OBJECT_CLASS (g_type_class_peek (GTK_TYPE_WINDOW)); window_iface = NI_WINDOW_INTERFACE (obj); g_object_unref (window_iface->priv->ni_interface); window_iface->priv->ni_interface = NULL; parent_class->dispose (obj); } #if 0 static void ni_window_interface_finalize (GObject *obj) { NIWindowInterface *window_iface; GObjectClass *parent_class = G_OBJECT_CLASS (g_type_class_peek (GTK_TYPE_WINDOW)); window_iface = NI_WINDOW_INTERFACE (obj); /* Nada que hacer, por el momento */ parent_class->finalize (obj); } #endif static void ni_window_interface_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { NIWindowInterface *window_iface = NI_WINDOW_INTERFACE (object); g_return_if_fail (NI_IS_WINDOW_INTERFACE (object)); switch (prop_id) { case PROP_NI_INTERFACE: window_iface->priv->ni_interface = NI_INTERFACE (g_value_get_object (value)); g_object_ref (window_iface->priv->ni_interface); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void ni_window_interface_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { NIWindowInterface *window_iface = NI_WINDOW_INTERFACE (object); g_return_if_fail (NI_IS_WINDOW_INTERFACE (object)); switch (prop_id) { case PROP_NI_INTERFACE: g_value_set_object (value, window_iface->priv->ni_interface); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void ni_window_interface_class_init (NIWindowInterfaceClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWindowClass *window_class = GTK_WINDOW_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->set_property = ni_window_interface_set_property; object_class->get_property = ni_window_interface_get_property; object_class->constructed = ni_window_interface_constructed; object_class->dispose = ni_window_interface_dispose; widget_class->delete_event = ni_window_interface_delete_event; obj_properties[PROP_NI_INTERFACE] = g_param_spec_object ( "ni-interface", "Network Inador Client Interface", "The interface object", NI_TYPE_INTERFACE, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE); g_object_class_install_properties (object_class, N_PROPERTIES, obj_properties); } GtkWidget *ni_window_interface_create_tree (GtkListStore *store, GtkWidget **tree) { GtkWidget *scrolled; GtkAdjustment *h, *v; GtkTreeViewColumn *column; GtkCellRenderer *renderer; *tree = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store)); h = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (*tree)); v = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (*tree)); scrolled = gtk_scrolled_window_new (h, v); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); renderer = gtk_cell_renderer_text_new (); column = gtk_tree_view_column_new_with_attributes ("Dirección", renderer, "text", IP_STORE_COL_MAIN_IP, NULL); gtk_tree_view_append_column (GTK_TREE_VIEW (*tree), column); gtk_container_add (GTK_CONTAINER (scrolled), *tree); return scrolled; } static void ni_window_interface_init (NIWindowInterface *window_iface) { NIWindowInterfacePrivate *priv = ni_window_interface_get_instance_private (window_iface); window_iface->priv = priv; GtkWindow *window = GTK_WINDOW (window_iface); GtkWidget *hbox, *label, *button, *image; GtkWidget *vbox, *scrolled, *vbox2; GtkTreeSelection *selection; GtkSizeGroup *size_l; /* initialize all public and private members to reasonable default values. * They are all automatically initialized to 0 to begin with. */ priv->ni_interface = NULL; gtk_window_set_title (window, "Interfaz"); priv->vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5); gtk_container_add (GTK_CONTAINER (window), priv->vbox); priv->notebook = gtk_notebook_new (); gtk_box_pack_start (GTK_BOX (priv->vbox), priv->notebook, TRUE, TRUE, 0); /* Página de la información general de la interfaz */ priv->vbox_info = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5); label = gtk_label_new ("Info"); gtk_notebook_append_page (GTK_NOTEBOOK (priv->notebook), priv->vbox_info, label); gtk_container_set_border_width (GTK_CONTAINER (priv->vbox_info), 5); size_l = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL); /* Poner las labels de información de la propia interfaz */ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5); gtk_box_pack_start (GTK_BOX (priv->vbox_info), hbox, FALSE, FALSE, 0); label = gtk_label_new ("Interfaz name:"); gtk_label_set_xalign (GTK_LABEL (label), 0.0); gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); gtk_size_group_add_widget (size_l, label); priv->button_name_revert = gtk_button_new_from_icon_name ("view-refresh", GTK_ICON_SIZE_BUTTON); gtk_widget_set_sensitive (priv->button_name_revert, FALSE); g_signal_connect (priv->button_name_revert, "clicked", G_CALLBACK (ni_window_interface_name_cancel_cb), window_iface); gtk_box_pack_end (GTK_BOX (hbox), priv->button_name_revert, FALSE, FALSE, 0); priv->button_name_apply = gtk_button_new_from_icon_name ("document-save", GTK_ICON_SIZE_BUTTON); gtk_widget_set_sensitive (priv->button_name_apply, FALSE); g_signal_connect (priv->button_name_apply, "clicked", G_CALLBACK (ni_window_interface_name_apply_cb), window_iface); gtk_box_pack_end (GTK_BOX (hbox), priv->button_name_apply, FALSE, FALSE, 0); priv->info_name = gtk_entry_new (); gtk_entry_set_text (GTK_ENTRY (priv->info_name), ""); gtk_widget_set_sensitive (priv->info_name, FALSE); g_signal_connect (priv->info_name, "changed", G_CALLBACK (ni_window_interface_name_edit_cb), window_iface); g_signal_connect (priv->info_name, "activate", G_CALLBACK (ni_window_interface_name_apply_cb), window_iface); gtk_box_pack_end (GTK_BOX (hbox), priv->info_name, TRUE, TRUE, 0); /* Las banderas de la intefaz */ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5); gtk_box_pack_start (GTK_BOX (priv->vbox_info), hbox, FALSE, FALSE, 0); label = gtk_label_new ("Estado:"); gtk_label_set_xalign (GTK_LABEL (label), 0.0); gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); gtk_size_group_add_widget (size_l, label); priv->button_down = gtk_button_new_from_icon_name ("go-down", GTK_ICON_SIZE_BUTTON); g_signal_connect (priv->button_down, "clicked", G_CALLBACK (ni_window_interface_down_cb), window_iface); gtk_box_pack_end (GTK_BOX (hbox), priv->button_down, FALSE, FALSE, 0); priv->button_up = gtk_button_new_from_icon_name ("go-up", GTK_ICON_SIZE_BUTTON); g_signal_connect (priv->button_up, "clicked", G_CALLBACK (ni_window_interface_up_cb), window_iface); gtk_box_pack_end (GTK_BOX (hbox), priv->button_up, FALSE, FALSE, 0); priv->info_updown = gtk_label_new (""); gtk_box_pack_end (GTK_BOX (hbox), priv->info_updown, FALSE, FALSE, 0); /* Página de IPv4 */ priv->vbox_ipv4 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5); label = gtk_label_new ("IPv4"); gtk_notebook_append_page (GTK_NOTEBOOK (priv->notebook), priv->vbox_ipv4, label); gtk_container_set_border_width (GTK_CONTAINER (priv->vbox_ipv4), 5); /* Preparar el list store */ priv->ipv4_store = gtk_list_store_new (NUM_IP_STORE_COLS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER); vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5); gtk_box_pack_start (GTK_BOX (priv->vbox_ipv4), vbox, TRUE, TRUE, 5); label = gtk_label_new ("Direcciones:"); gtk_label_set_xalign (GTK_LABEL (label), 0.0); gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0); hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5); gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0); scrolled = ni_window_interface_create_tree (priv->ipv4_store, &priv->tree_ipv4); gtk_box_pack_start (GTK_BOX (hbox), scrolled, TRUE, TRUE, 0); /* Botonera del tree view */ vbox2 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5); gtk_box_pack_start (GTK_BOX (hbox), vbox2, FALSE, FALSE, 0); button = gtk_button_new_from_icon_name ("list-add", GTK_ICON_SIZE_LARGE_TOOLBAR); gtk_box_pack_start (GTK_BOX (vbox2), button, FALSE, FALSE, 0); g_signal_connect (button, "clicked", G_CALLBACK (ni_window_interface_addr_v4_button_add_cb), window_iface); priv->del_ipv4_button = gtk_button_new_from_icon_name ("list-remove", GTK_ICON_SIZE_LARGE_TOOLBAR); gtk_box_pack_start (GTK_BOX (vbox2), priv->del_ipv4_button, FALSE, FALSE, 0); g_signal_connect (priv->del_ipv4_button, "clicked", G_CALLBACK (ni_window_interface_addr_v4_button_del_cb), window_iface); gtk_widget_set_sensitive (priv->del_ipv4_button, FALSE); /* Conectar la señal de cambio de selección del tree view */ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->tree_ipv4)); g_signal_connect (selection, "changed", G_CALLBACK (has_ip_selected_v4_cb), window_iface); /* Página de IPv6 */ priv->vbox_ipv6 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5); label = gtk_label_new ("IPv6"); gtk_notebook_append_page (GTK_NOTEBOOK (priv->notebook), priv->vbox_ipv6, label); gtk_container_set_border_width (GTK_CONTAINER (priv->vbox_ipv6), 5); /* Preparar el list store */ priv->ipv6_store = gtk_list_store_new (NUM_IP_STORE_COLS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER); vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5); gtk_box_pack_start (GTK_BOX (priv->vbox_ipv6), vbox, TRUE, TRUE, 5); label = gtk_label_new ("Direcciones:"); gtk_label_set_xalign (GTK_LABEL (label), 0.0); gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0); hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5); gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0); scrolled = ni_window_interface_create_tree (priv->ipv6_store, &priv->tree_ipv6); gtk_box_pack_start (GTK_BOX (hbox), scrolled, TRUE, TRUE, 0); /* Botonera del tree view */ vbox2 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5); gtk_box_pack_start (GTK_BOX (hbox), vbox2, FALSE, FALSE, 0); button = gtk_button_new_from_icon_name ("list-add", GTK_ICON_SIZE_LARGE_TOOLBAR); gtk_box_pack_start (GTK_BOX (vbox2), button, FALSE, FALSE, 0); g_signal_connect (button, "clicked", G_CALLBACK (ni_window_interface_addr_v6_button_add_cb), window_iface); priv->del_ipv6_button = gtk_button_new_from_icon_name ("list-remove", GTK_ICON_SIZE_LARGE_TOOLBAR); gtk_box_pack_start (GTK_BOX (vbox2), priv->del_ipv6_button, FALSE, FALSE, 0); g_signal_connect (priv->del_ipv6_button, "clicked", G_CALLBACK (ni_window_interface_addr_v6_button_del_cb), window_iface); gtk_widget_set_sensitive (priv->del_ipv6_button, FALSE); /* Conectar la señal de cambio de selección del tree view */ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->tree_ipv6)); g_signal_connect (selection, "changed", G_CALLBACK (has_ip_selected_v6_cb), window_iface); /* La botonera inferior */ hbox = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL); gtk_button_box_set_layout (GTK_BUTTON_BOX (hbox), GTK_BUTTONBOX_END); gtk_box_pack_start (GTK_BOX (priv->vbox), hbox, FALSE, FALSE, 0); /* El boton de cerrar */ button = gtk_button_new_with_label ("Cerrar"); g_signal_connect_swapped (button, "clicked", G_CALLBACK (gtk_widget_hide_on_delete), window); image = gtk_image_new_from_icon_name ("window-close", GTK_ICON_SIZE_BUTTON); gtk_button_set_image (GTK_BUTTON (button), image); gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0); gtk_widget_show_all (priv->vbox); } GtkWidget* ni_window_interface_new (NIInterface *ni_interface) { NIWindowInterface *window_iface; window_iface = g_object_new (NI_TYPE_WINDOW_INTERFACE, "type", GTK_WINDOW_TOPLEVEL, "ni-interface", ni_interface, NULL); return GTK_WIDGET (window_iface); }