#if HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include "rc.h" #include "socket.h" #include "ui_notif_dlg.h" #include "ui_main_screen.h" #include "ui_menu_bar.h" #include "ui_callbacks.h" #include "ui_interface.h" #include "ui_notifications.h" #include "ui_tree_view.h" #include "ui_signal_dissect_view.h" #include "ui_filters.h" #include "types.h" #include "locate_root.h" #include "xml_parse.h" static gboolean refresh_message_list = TRUE; static gboolean filters_changed = FALSE; gboolean ui_callback_on_open_messages (GtkWidget *widget, gpointer data) { gboolean refresh = (data != NULL) ? TRUE : FALSE; g_message("Open messages event occurred %d", refresh); if (refresh && (ui_main_data.messages_file_name != NULL)) { CHECK_FCT(ui_messages_read (ui_main_data.messages_file_name)); } else { CHECK_FCT(ui_messages_open_file_chooser()); } return TRUE; } gboolean ui_callback_on_save_messages (GtkWidget *widget, gpointer data) { g_message("Save messages event occurred"); // CHECK_FCT(ui_file_chooser()); return TRUE; } gboolean ui_callback_on_filters_enabled (GtkToolButton *button, gpointer data) { gboolean enabled; gboolean changed; enabled = gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(button)); g_debug("Filters enabled event occurred %d", enabled); changed = ui_filters_enable(enabled); if (changed) { /* Set the tool tip text */ if (enabled) { gtk_tool_item_set_tooltip_text(GTK_TOOL_ITEM(button), "Disable messages filtering"); } else { gtk_tool_item_set_tooltip_text(GTK_TOOL_ITEM(button), "Enable messages filtering"); } ui_tree_view_refilter(); if (ui_main_data.messages_list != NULL) { GtkTreePath *path_row; /* Get the currently selected message */ gtk_tree_view_get_cursor(GTK_TREE_VIEW(ui_main_data.messages_list), &path_row, NULL); if (path_row != NULL) { /* Center the message in the middle of the list if possible */ gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(ui_main_data.messages_list), path_row, NULL, TRUE, 0.5, 0.0); } } } return TRUE; } gboolean ui_callback_on_open_filters (GtkWidget *widget, gpointer data) { gboolean refresh = (data != NULL) ? TRUE : FALSE; g_message("Open filters event occurred"); if (refresh && (ui_main_data.filters_file_name != NULL)) { CHECK_FCT(ui_filters_read (ui_main_data.filters_file_name)); } else { CHECK_FCT(ui_filters_open_file_chooser()); } return TRUE; } gboolean ui_callback_on_save_filters (GtkWidget *widget, gpointer data) { g_message("Save filters event occurred"); CHECK_FCT(ui_filters_save_file_chooser()); return TRUE; } gboolean ui_callback_on_enable_filters (GtkWidget *widget, gpointer data) { gboolean enabled; enabled = gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(ui_main_data.filters_enabled)); gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(ui_main_data.filters_enabled), !enabled); return TRUE; } gboolean ui_callback_on_about (GtkWidget *widget, gpointer data) { #if defined(PACKAGE_STRING) ui_notification_dialog (GTK_MESSAGE_INFO, "about", "Eurecom %s", PACKAGE_STRING); #else ui_notification_dialog(GTK_MESSAGE_INFO, "about", "Eurecom itti_analyzer"); #endif return TRUE; } gboolean ui_callback_on_select_signal (GtkTreeSelection *selection, GtkTreeModel *model, GtkTreePath *path, gboolean path_currently_selected, gpointer user_data) { static gpointer buffer_current; ui_text_view_t *text_view; GtkTreeIter iter; g_debug("Message selected %d %p %p %s", path_currently_selected, buffer_current, path, gtk_tree_path_to_string(path)); if (!path_currently_selected) { text_view = (ui_text_view_t *) user_data; g_assert(text_view != NULL); if (gtk_tree_model_get_iter(model, &iter, path)) { gpointer buffer; uint32_t message_id; uint32_t origin_task_id; uint32_t destination_task_id; uint32_t instance; char label[100]; gtk_tree_model_get(model, &iter, COL_MESSAGE_ID, &message_id, COL_FROM_TASK_ID, &origin_task_id, COL_TO_TASK_ID, &destination_task_id, COL_INSTANCE, &instance, COL_BUFFER, &buffer, -1); g_debug(" Get iter %p %p", buffer_current, buffer); if (ui_tree_view_last_event) { g_debug("last_event %p %d %d", ui_tree_view_last_event, ui_tree_view_last_event->type, ui_tree_view_last_event->button); if (ui_tree_view_last_event->type == GDK_BUTTON_PRESS) { /* Callback is due to a button click */ ui_main_data.follow_last = FALSE; if (ui_tree_view_last_event->button == 3) { /* It was a right mouse click */ int item; /* Clear event */ ui_tree_view_last_event = NULL; if (ui_main_data.menu_filter_messages == NULL) { ui_create_filter_menus(); } g_debug("Message selected right click %d %d %d %d", message_id, origin_task_id, destination_task_id, instance); /* Message Id menu */ { /* Invalidate associated menu item to avoid issue with call back when updating the menu item check state */ ui_tree_view_menu_enable[MENU_MESSAGE].filter_item = NULL; item = ui_filters_search_id(&ui_filters.messages, message_id); /* Update the menu item check state based on message ID state */ gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM(ui_tree_view_menu_enable[MENU_MESSAGE].menu_enable), ui_filters.messages.items[item].enabled); /* Set menu item label */ sprintf(label, "Message: %s", message_id_to_string(message_id)); gtk_menu_item_set_label(GTK_MENU_ITEM(ui_tree_view_menu_enable[MENU_MESSAGE].menu_enable), label); /* Save menu item associated to this row */ ui_tree_view_menu_enable[MENU_MESSAGE].filter_item = &ui_filters.messages.items[item]; } /* Origin task id */ { /* Invalidate associated menu item to avoid issue with call back when updating the menu item check state */ ui_tree_view_menu_enable[MENU_FROM_TASK].filter_item = NULL; item = ui_filters_search_id(&ui_filters.origin_tasks, origin_task_id); /* Update the menu item check state based on message ID state */ gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM(ui_tree_view_menu_enable[MENU_FROM_TASK].menu_enable), ui_filters.origin_tasks.items[item].enabled); /* Set menu item label */ sprintf(label, "From: %s", task_id_to_string(origin_task_id, origin_task_id_type)); gtk_menu_item_set_label(GTK_MENU_ITEM(ui_tree_view_menu_enable[MENU_FROM_TASK].menu_enable), label); /* Save menu item associated to this row */ ui_tree_view_menu_enable[MENU_FROM_TASK].filter_item = &ui_filters.origin_tasks.items[item]; } /* Destination task id */ { /* Invalidate associated menu item to avoid issue with call back when updating the menu item check state */ ui_tree_view_menu_enable[MENU_TO_TASK].filter_item = NULL; item = ui_filters_search_id(&ui_filters.destination_tasks, destination_task_id); /* Update the menu item check state based on message ID state */ gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM(ui_tree_view_menu_enable[MENU_TO_TASK].menu_enable), ui_filters.destination_tasks.items[item].enabled); /* Set menu item label */ sprintf(label, "To: %s", task_id_to_string(destination_task_id, destination_task_id_type)); gtk_menu_item_set_label(GTK_MENU_ITEM(ui_tree_view_menu_enable[MENU_TO_TASK].menu_enable), label); /* Save menu item associated to this row */ ui_tree_view_menu_enable[MENU_TO_TASK].filter_item = &ui_filters.destination_tasks.items[item]; } /* Instance */ { /* Invalidate associated menu item to avoid issue with call back when updating the menu item check state */ ui_tree_view_menu_enable[MENU_INSTANCE].filter_item = NULL; item = ui_filters_search_id(&ui_filters.instances, instance); /* Update the menu item check state based on message ID state */ gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM(ui_tree_view_menu_enable[MENU_INSTANCE].menu_enable), ui_filters.instances.items[item].enabled); /* Set menu item label */ sprintf(label, "Instance: %d", instance); gtk_menu_item_set_label(GTK_MENU_ITEM(ui_tree_view_menu_enable[MENU_INSTANCE].menu_enable), label); /* Save menu item associated to this row */ ui_tree_view_menu_enable[MENU_INSTANCE].filter_item = &ui_filters.instances.items[item]; } gtk_menu_popup(GTK_MENU (ui_tree_view_menu), NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time()); } } /* Clear event */ ui_tree_view_last_event = NULL; } if (buffer_current != buffer) { buffer_current = buffer; /* Clear the view */ CHECK_FCT_DO(ui_signal_dissect_clear_view(text_view), return FALSE); if (ui_main_data.display_message_header) { CHECK_FCT_DO(dissect_signal_header((buffer_t*)buffer, ui_signal_set_text, text_view), return FALSE); } if ((strcmp(message_id_to_string(message_id), "ERROR_LOG") == 0) || (strcmp(message_id_to_string(message_id), "WARNING_LOG") == 0) || (strcmp(message_id_to_string(message_id), "NOTICE_LOG") == 0) || (strcmp(message_id_to_string(message_id), "INFO_LOG") == 0) || (strcmp(message_id_to_string(message_id), "DEBUG_LOG") == 0) || (strcmp(message_id_to_string(message_id), "GENERIC_LOG") == 0)) { gchar *data; gint data_size; uint32_t message_header_type_size; if (ui_main_data.display_message_header) { ui_signal_set_text(text_view, "\n", 1); } message_header_type_size = get_message_header_type_size(); data = (gchar *) buffer_at_offset((buffer_t*) buffer, message_header_type_size); data_size = get_message_size((buffer_t*) buffer); g_debug(" message header type size: %u, data size: %u %p %d", message_header_type_size, data_size, buffer, ui_main_data.follow_last); ui_signal_set_text(text_view, data, data_size); } else { g_debug(" dissect message %d %p %d", message_id, buffer, ui_main_data.follow_last); /* Dissect the signal */ CHECK_FCT_DO(dissect_signal((buffer_t*)buffer, ui_signal_set_text, text_view), return FALSE); } } } } return TRUE; } gboolean ui_callback_on_menu_enable (GtkWidget *widget, gpointer data) { ui_tree_view_menu_enable_t *menu_enable = data; if (menu_enable->filter_item != NULL) { gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu_enable->filter_item->menu_item), gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menu_enable->menu_enable))); menu_enable->filter_item = NULL; } return TRUE; } gboolean ui_callback_on_menu_color (GtkWidget *widget, gpointer data) { ui_tree_view_menu_enable_t *menu_enable = data; GdkRGBA color; GtkWidget *color_chooser; gint response; color_chooser = gtk_color_chooser_dialog_new("Select message background color", GTK_WINDOW(ui_main_data.window)); gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(color_chooser), FALSE); response = gtk_dialog_run(GTK_DIALOG (color_chooser)); if (response == GTK_RESPONSE_OK) { int red, green, blue; gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(color_chooser), &color); red = (int) (color.red * 255); green = (int) (color.green * 255); blue = (int) (color.blue * 255); g_debug("Selected color for %s %f->%02x %f->%02x %f->%02x", menu_enable->filter_item->name, color.red, red, color.green, green, color.blue, blue); snprintf(menu_enable->filter_item->background, BACKGROUND_SIZE, "#%02x%02x%02x", red, green, blue); ui_tree_view_refilter(); } gtk_widget_destroy(color_chooser); return TRUE; } void ui_signal_add_to_list (gpointer data, gpointer user_data) { gboolean goto_last = user_data ? TRUE : FALSE; buffer_t *signal_buffer; GtkTreePath *path; GtkTreeViewColumn *focus_column; uint32_t lte_frame; uint32_t lte_slot; uint32_t origin_task_id; uint32_t destination_task_id; uint32_t instance; char lte_time[15]; gtk_tree_view_get_cursor(GTK_TREE_VIEW(ui_main_data.messages_list), &path, &focus_column); signal_buffer = (buffer_t *) data; lte_frame = get_lte_frame(signal_buffer); lte_slot = get_lte_slot(signal_buffer); sprintf(lte_time, "%d.%02d", lte_frame, lte_slot); get_message_id(root, signal_buffer, &signal_buffer->message_id); origin_task_id = get_task_id(signal_buffer, origin_task_id_type); destination_task_id = get_task_id(signal_buffer, destination_task_id_type); instance = get_instance(signal_buffer); ui_tree_view_new_signal_ind(signal_buffer->message_number, lte_time, signal_buffer->message_id, message_id_to_string(signal_buffer->message_id), origin_task_id, task_id_to_string(origin_task_id, origin_task_id_type), destination_task_id, task_id_to_string(destination_task_id, destination_task_id_type), instance, data); /* Increment number of messages */ ui_main_data.nb_message_received++; if ((ui_main_data.follow_last) && (goto_last)) { /* Advance to the new last signal */ ui_tree_view_select_row(ui_tree_view_get_filtered_number() - 1); } } static gboolean ui_handle_update_signal_list (gint fd, void *data, size_t data_length) { pipe_new_signals_list_message_t *signal_list_message; /* Enable buttons to move in the list of signals */ ui_set_sensitive_move_buttons(TRUE); signal_list_message = (pipe_new_signals_list_message_t *) data; g_assert(signal_list_message != NULL); g_assert(signal_list_message->signal_list != NULL); g_list_foreach(signal_list_message->signal_list, ui_signal_add_to_list, (gpointer) TRUE); /* Free the list but not user data associated with each element */ g_list_free(signal_list_message->signal_list); /* Free the message */ free(signal_list_message); ui_gtk_flush_events(); return TRUE; } static gboolean ui_handle_socket_connection_failed (gint fd) { GtkWidget *dialogbox; dialogbox = gtk_message_dialog_new(GTK_WINDOW(ui_main_data.window), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "Failed to connect to provided host/ip address"); gtk_dialog_run(GTK_DIALOG(dialogbox)); gtk_widget_destroy(dialogbox); /* Re-enable connect button */ ui_enable_connect_button(); return TRUE; } static gboolean ui_handle_socket_connection_lost (gint fd) { GtkWidget *dialogbox; dialogbox = gtk_message_dialog_new(GTK_WINDOW(ui_main_data.window), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "Connection with remote host has been lost"); gtk_dialog_run(GTK_DIALOG(dialogbox)); gtk_widget_destroy(dialogbox); /* Re-enable connect button */ ui_enable_connect_button(); return TRUE; } static gboolean ui_handle_socket_xml_definition (gint fd, void *data, size_t data_length) { pipe_xml_definition_message_t *xml_definition_message; xml_definition_message = (pipe_xml_definition_message_t *) data; g_assert(xml_definition_message != NULL); g_assert(data_length == sizeof(pipe_xml_definition_message_t)); xml_parse_buffer(xml_definition_message->xml_definition, xml_definition_message->xml_definition_length); free(data); return TRUE; } gboolean ui_pipe_callback (gint source, gpointer user_data) { void *input_data = NULL; size_t input_data_length = 0; pipe_input_header_t input_header; /* Read the header */ if (read(source, &input_header, sizeof(input_header)) < 0) { g_warning("Failed to read from pipe %d: %s", source, g_strerror(errno)); return FALSE; } input_data_length = input_header.message_size - sizeof(input_header); /* Checking for non-header part */ if (input_data_length > 0) { input_data = malloc(input_data_length); if (read(source, input_data, input_data_length) < 0) { g_warning("Failed to read from pipe %d: %s", source, g_strerror(errno)); return FALSE; } } switch (input_header.message_type) { case UI_PIPE_CONNECTION_FAILED: return ui_handle_socket_connection_failed(source); case UI_PIPE_XML_DEFINITION: return ui_handle_socket_xml_definition(source, input_data, input_data_length); case UI_PIPE_CONNECTION_LOST: return ui_handle_socket_connection_lost(source); case UI_PIPE_UPDATE_SIGNAL_LIST: return ui_handle_update_signal_list(source, input_data, input_data_length); default: g_warning("[gui] Unhandled message type %u", input_header.message_type); g_assert_not_reached(); } return FALSE; } gboolean ui_callback_on_connect (GtkWidget *widget, gpointer data) { /* We have to retrieve the ip address and port of remote host */ const char *ip; uint16_t port; int pipe_fd[2]; port = atoi(gtk_entry_get_text(GTK_ENTRY(ui_main_data.port_entry))); ip = gtk_entry_get_text(GTK_ENTRY(ui_main_data.ip_entry)); g_message("Connect event occurred to %s:%d", ip, port); if (strlen(ip) == 0) { ui_notification_dialog(GTK_MESSAGE_WARNING, "Connect", "Empty host ip address"); return FALSE; } if (port == 0) { ui_notification_dialog(GTK_MESSAGE_WARNING, "Connect", "Invalid host port value"); return FALSE; } ui_pipe_new(pipe_fd, ui_pipe_callback, NULL); memcpy(ui_main_data.pipe_fd, pipe_fd, sizeof(int) * 2); /* Disable the connect button */ ui_disable_connect_button(); ui_callback_signal_clear_list(widget, data); if (socket_connect_to_remote_host(ip, port, pipe_fd[1]) != 0) { ui_enable_connect_button(); return FALSE; } ui_set_title("%s:%d", ip, port); return TRUE; } gboolean ui_callback_on_disconnect (GtkWidget *widget, gpointer data) { /* We have to retrieve the ip address and port of remote host */ g_message("Disconnect event occurred"); ui_pipe_write_message(ui_main_data.pipe_fd[0], UI_PIPE_DISCONNECT_EVT, NULL, 0); ui_enable_connect_button(); return TRUE; } gboolean ui_callback_signal_go_to_first (GtkWidget *widget, gpointer data) { ui_tree_view_select_row(0); ui_main_data.follow_last = FALSE; return TRUE; } gboolean ui_callback_signal_go_to (GtkWidget *widget, gpointer data) { gtk_window_set_focus(GTK_WINDOW(ui_main_data.window), ui_main_data.signals_go_to_entry); return TRUE; } gboolean ui_callback_signal_go_to_entry (GtkWidget *widget, gpointer data) { // gtk_entry_buffer_set_text(GTK_ENTRY(ui_main_data.signals_go_to_entry), ""); gtk_window_set_focus(GTK_WINDOW(ui_main_data.window), ui_main_data.messages_list); return TRUE; } gboolean ui_callback_signal_go_to_last (GtkWidget *widget, gpointer data) { ui_tree_view_select_row(ui_tree_view_get_filtered_number() - 1); ui_main_data.follow_last = TRUE; return TRUE; } gboolean ui_callback_display_message_header (GtkWidget *widget, gpointer data) { ui_main_data.display_message_header = !ui_main_data.display_message_header; // TODO refresh textview. return TRUE; } gboolean ui_callback_display_brace (GtkWidget *widget, gpointer data) { ui_main_data.display_brace = !ui_main_data.display_brace; // TODO refresh textview. return TRUE; } gboolean ui_callback_signal_clear_list (GtkWidget *widget, gpointer data) { /* Disable buttons to move in the list of signals */ ui_set_sensitive_move_buttons(FALSE); ui_set_title(""); /* Clear list of signals */ ui_tree_view_destroy_list(ui_main_data.messages_list); if (ui_main_data.text_view != NULL) { ui_signal_dissect_clear_view(ui_main_data.text_view); } return TRUE; } static void ui_callback_on_menu_items_selected (GtkWidget *widget, gpointer data) { gboolean active = data != NULL; if (GTK_IS_CHECK_MENU_ITEM(widget)) { gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(widget), active); } } gboolean ui_callback_on_menu_none (GtkWidget *widget, gpointer data) { GtkWidget *menu = (GtkWidget *) data; g_debug("ui_callback_on_menu_none occurred %lx %lx)", (long) widget, (long) data); refresh_message_list = FALSE; gtk_container_foreach(GTK_CONTAINER(menu), ui_callback_on_menu_items_selected, (gpointer) FALSE); refresh_message_list = TRUE; if (filters_changed) { ui_tree_view_refilter(); filters_changed = FALSE; } return TRUE; } gboolean ui_callback_on_menu_all (GtkWidget *widget, gpointer data) { GtkWidget *menu = (GtkWidget *) data; g_debug("ui_callback_on_menu_all occurred %lx %lx)", (long) widget, (long) data); refresh_message_list = FALSE; gtk_container_foreach(GTK_CONTAINER(menu), ui_callback_on_menu_items_selected, (gpointer) TRUE); refresh_message_list = TRUE; if (filters_changed) { ui_tree_view_refilter(); filters_changed = FALSE; } return TRUE; } gboolean ui_callback_on_menu_item_selected (GtkWidget *widget, gpointer data) { ui_filter_item_t *filter_entry = data; gboolean enabled; enabled = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget)); if (filter_entry->enabled != enabled) { filter_entry->enabled = enabled; if (refresh_message_list) { ui_tree_view_refilter(); } else { filters_changed = TRUE; } } g_debug("ui_callback_on_menu_item_selected occurred %p %p %s %d (%d messages to display)", widget, data, filter_entry->name, enabled, ui_tree_view_get_filtered_number()); return TRUE; } gboolean ui_callback_on_tree_column_header_click (GtkWidget *widget, gpointer data) { col_type_t col = (col_type_t) data; g_debug("ui_callback_on_tree_column_header_click %d", col); switch (col) { case COL_MESSAGE: ui_show_filter_menu(&ui_main_data.menu_filter_messages, &ui_filters.messages); break; case COL_FROM_TASK: ui_show_filter_menu(&ui_main_data.menu_filter_origin_tasks, &ui_filters.origin_tasks); break; case COL_TO_TASK: ui_show_filter_menu(&ui_main_data.menu_filter_destination_tasks, &ui_filters.destination_tasks); break; case COL_INSTANCE: ui_show_filter_menu(&ui_main_data.menu_filter_instances, &ui_filters.instances); break; default: g_warning("Unknown column filter %d in call to ui_callback_on_tree_column_header_click", col); return FALSE; } return TRUE; }