Commit ecf07e38 authored by Cedric Roux's avatar Cedric Roux

- itti_analyzer v0.2:

	* Moved all GUI calls to main thread
	* Refine socket interface
	* Added origin/destination task id on message display list

git-svn-id: http://svn.eurecom.fr/openair4G/trunk@4258 818b1a75-f10b-46b9-bf7c-635c3b92a50f
parent 3dc3d6ae
...@@ -4,7 +4,7 @@ define([svnversion], esyscmd([sh -c "svnversion ..|tr -d '\n'"])) ...@@ -4,7 +4,7 @@ define([svnversion], esyscmd([sh -c "svnversion ..|tr -d '\n'"]))
AC_DEFINE(SVN_REVISION, "svnversion", [SVN Revision]) AC_DEFINE(SVN_REVISION, "svnversion", [SVN Revision])
AC_INIT([itti_debugger], [0.1.svnversion], [openair_admin@eurecom.fr]) AC_INIT([itti_debugger], [0.2.svnversion], [openair_admin@eurecom.fr])
AC_CANONICAL_BUILD AC_CANONICAL_BUILD
AC_CANONICAL_TARGET AC_CANONICAL_TARGET
AM_INIT_AUTOMAKE([1.11 silent-rules]) AM_INIT_AUTOMAKE([1.11 silent-rules])
...@@ -90,4 +90,4 @@ AC_CONFIG_FILES( ...@@ -90,4 +90,4 @@ AC_CONFIG_FILES(
libui/Makefile \ libui/Makefile \
Makefile \ Makefile \
) )
AC_OUTPUT AC_OUTPUT
\ No newline at end of file
...@@ -75,12 +75,6 @@ int main(int argc, char *argv[]) ...@@ -75,12 +75,6 @@ int main(int argc, char *argv[])
G_LOG_FLAG_FATAL | G_LOG_FLAG_FATAL |
G_LOG_FLAG_RECURSION); G_LOG_FLAG_RECURSION);
if (!g_thread_supported())
g_thread_init(NULL);
/* Secure gtk */
gdk_threads_init();
/* Initialize the widget set */ /* Initialize the widget set */
gtk_init(&argc, &argv); gtk_init(&argc, &argv);
......
...@@ -6,13 +6,23 @@ ...@@ -6,13 +6,23 @@
typedef struct { typedef struct {
pthread_t thread; pthread_t thread;
uint16_t port;
char *remote_ip;
int sd; int sd;
struct sockaddr_in si_me; char *ip_address;
uint16_t port;
/* The pipe used between main thread (running GTK) and the socket thread */
int pipe_fd;
/* Time used to avoid refreshing UI every time a new signal is incoming */
gint64 last_data_notification;
uint8_t nb_signals_since_last_update;
/* The last signals received which are not yet been updated in GUI */
GList *signal_list;
} socket_data_t; } socket_data_t;
int socket_connect_to_remote_host(const char *remote_ip, const uint16_t port); int socket_connect_to_remote_host(const char *remote_ip, const uint16_t port,
int pipe_fd);
int socket_disconnect_from_remote_host(void); int socket_disconnect_from_remote_host(void);
......
...@@ -6,6 +6,21 @@ ...@@ -6,6 +6,21 @@
#include "enum_type.h" #include "enum_type.h"
#include "ui_interface.h" #include "ui_interface.h"
char *enum_type_get_name_from_value(struct types_s *type, uint32_t value)
{
char *enum_name = "UNKNOWN";
types_t *enum_value;
/* Loop on eache enumeration values */
for (enum_value = type->child; enum_value; enum_value = enum_value->next) {
if (value == enum_value->init_value) {
enum_name = enum_value->name;
break;
}
}
return enum_name;
}
int enum_type_dissect_from_buffer( int enum_type_dissect_from_buffer(
struct types_s *type, buffer_t *buffer, uint32_t offset, struct types_s *type, buffer_t *buffer, uint32_t offset,
uint32_t parent_offset, int indent) uint32_t parent_offset, int indent)
......
...@@ -3,6 +3,8 @@ ...@@ -3,6 +3,8 @@
#ifndef ENUM_TYPE_H_ #ifndef ENUM_TYPE_H_
#define ENUM_TYPE_H_ #define ENUM_TYPE_H_
char *enum_type_get_name_from_value(struct types_s *type, uint32_t value);
int enum_type_dissect_from_buffer( int enum_type_dissect_from_buffer(
struct types_s *type, buffer_t *buffer, uint32_t offset, struct types_s *type, buffer_t *buffer, uint32_t offset,
uint32_t parent_offset, int indent); uint32_t parent_offset, int indent);
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "union_type.h" #include "union_type.h"
#include "ui_interface.h" #include "ui_interface.h"
#include "ui_notif_dlg.h"
#include "../libresolver/locate_root.h" #include "../libresolver/locate_root.h"
#include "../libresolver/resolvers.h" #include "../libresolver/resolvers.h"
...@@ -21,15 +22,15 @@ extern int debug_parser; ...@@ -21,15 +22,15 @@ extern int debug_parser;
# define INDENT_START 0 # define INDENT_START 0
#endif #endif
#define PARSER_DEBUG(fmt, args...) \ #define PARSER_DEBUG(fmt, args...) \
do { \ do { \
if (debug_parser) \ if (debug_parser) \
fprintf(stdout, "WARNING: "fmt, ##args); \ g_debug("WARNING: "fmt, ##args); \
} while(0) } while(0)
#define PARSER_ERROR(fmt, args...) \ #define PARSER_ERROR(fmt, args...) \
do { \ do { \
fprintf(stderr, "FATAL: "fmt, ##args); \ g_error("FATAL: "fmt, ##args); \
} while(0) } while(0)
types_t *root = NULL; types_t *root = NULL;
...@@ -582,66 +583,54 @@ static int parse_pointer_type(xmlNode *node, types_t **head) { ...@@ -582,66 +583,54 @@ static int parse_pointer_type(xmlNode *node, types_t **head) {
static int parse_elements(xmlNode * a_node, types_t **head) { static int parse_elements(xmlNode * a_node, types_t **head) {
xmlNode *cur_node = NULL; xmlNode *cur_node = NULL;
xmlNode *child_node = NULL; xmlNode *child_node = NULL;
unsigned long nb_nodes;
unsigned long node_count = 0;
nb_nodes = xmlChildElementCount (a_node);
for (cur_node = a_node; cur_node; cur_node = cur_node->next) { for (cur_node = a_node; cur_node; cur_node = cur_node->next) {
node_count++;
sleep (1);
ui_interface.ui_progress_bar_set_fraction ((double) node_count / nb_nodes);
for (child_node = cur_node->children; child_node; child_node = child_node->next) { for (child_node = cur_node->children; child_node; child_node = child_node->next) {
if (child_node->type == XML_ELEMENT_NODE) { if (child_node->type == XML_ELEMENT_NODE) {
if (strcmp ((char *) child_node->name, "Enumeration") == 0) { if (strcmp ((char *) child_node->name, "Enumeration") == 0) {
CHECK_FCT_DO(parse_enumeration(child_node, head), goto fail); CHECK_FCT_DO(parse_enumeration(child_node, head), return RC_FAIL);
} }
else else
if (strcmp ((char *) child_node->name, "FundamentalType") == 0) { if (strcmp ((char *) child_node->name, "FundamentalType") == 0) {
CHECK_FCT_DO(parse_fundamental(child_node, head), goto fail); CHECK_FCT_DO(parse_fundamental(child_node, head), return RC_FAIL);
} }
else else
if (strcmp ((char *) child_node->name, "Struct") == 0) { if (strcmp ((char *) child_node->name, "Struct") == 0) {
CHECK_FCT_DO(parse_struct(child_node, head), goto fail); CHECK_FCT_DO(parse_struct(child_node, head), return RC_FAIL);
} }
else else
if (strcmp ((char *) child_node->name, "Union") == 0) { if (strcmp ((char *) child_node->name, "Union") == 0) {
CHECK_FCT_DO(parse_union(child_node, head), goto fail); CHECK_FCT_DO(parse_union(child_node, head), return RC_FAIL);
} }
else else
if (strcmp ((char *) child_node->name, "Typedef") == 0) { if (strcmp ((char *) child_node->name, "Typedef") == 0) {
CHECK_FCT_DO(parse_typedef(child_node, head), goto fail); CHECK_FCT_DO(parse_typedef(child_node, head), return RC_FAIL);
} }
else else
if (strcmp ((char *) child_node->name, "File") == 0) { if (strcmp ((char *) child_node->name, "File") == 0) {
CHECK_FCT_DO(parse_file(child_node, head), goto fail); CHECK_FCT_DO(parse_file(child_node, head), return RC_FAIL);
} }
else else
if (strcmp ((char *) child_node->name, "Field") == 0) { if (strcmp ((char *) child_node->name, "Field") == 0) {
CHECK_FCT_DO(parse_field(child_node, head), goto fail); CHECK_FCT_DO(parse_field(child_node, head), return RC_FAIL);
} }
else else
if (strcmp ((char *) child_node->name, "ReferenceType") == 0) { if (strcmp ((char *) child_node->name, "ReferenceType") == 0) {
CHECK_FCT_DO(parse_reference_type(child_node, head), goto fail); CHECK_FCT_DO(parse_reference_type(child_node, head), return RC_FAIL);
} }
else else
if (strcmp ((char *) child_node->name, "ArrayType") == 0) { if (strcmp ((char *) child_node->name, "ArrayType") == 0) {
CHECK_FCT_DO(parse_array_type(child_node, head), goto fail); CHECK_FCT_DO(parse_array_type(child_node, head), return RC_FAIL);
} }
else else
if (strcmp ((char *) child_node->name, "PointerType") == 0) { if (strcmp ((char *) child_node->name, "PointerType") == 0) {
CHECK_FCT_DO(parse_pointer_type(child_node, head), goto fail); CHECK_FCT_DO(parse_pointer_type(child_node, head), return RC_FAIL);
} }
} }
} }
} }
ui_interface.ui_progress_bar_terminate ();
return RC_OK; return RC_OK;
fail: ui_interface.ui_progress_bar_terminate ();
return RC_FAIL;
} }
int xml_parse_buffer(const char *xml_buffer, const int size) { int xml_parse_buffer(const char *xml_buffer, const int size) {
...@@ -651,7 +640,7 @@ int xml_parse_buffer(const char *xml_buffer, const int size) { ...@@ -651,7 +640,7 @@ int xml_parse_buffer(const char *xml_buffer, const int size) {
return -1; return -1;
} }
fprintf(stdout, "Parsing XML definition from buffer\n"); g_debug("Parsing XML definition from buffer");
/* This initialize the library and check potential ABI mismatches /* This initialize the library and check potential ABI mismatches
* between the version it was compiled for and the actual shared * between the version it was compiled for and the actual shared
...@@ -662,8 +651,8 @@ int xml_parse_buffer(const char *xml_buffer, const int size) { ...@@ -662,8 +651,8 @@ int xml_parse_buffer(const char *xml_buffer, const int size) {
doc = xmlReadMemory(xml_buffer, size, NULL, NULL, 0); doc = xmlReadMemory(xml_buffer, size, NULL, NULL, 0);
if (doc == NULL) { if (doc == NULL) {
fprintf (stderr, "Failed to parse buffer: %s\n", xml_buffer); g_warning("Failed to parse buffer: %s", xml_buffer);
ui_interface.ui_notification_dialog (DIALOG_WARNING, "Fail to parse XML buffer"); // ui_notification_dialog(DIALOG_WARNING, "Fail to parse XML buffer");
return RC_FAIL; return RC_FAIL;
} }
...@@ -686,8 +675,8 @@ int xml_parse_file(const char *filename) { ...@@ -686,8 +675,8 @@ int xml_parse_file(const char *filename) {
doc = xmlReadFile (filename, NULL, 0); doc = xmlReadFile (filename, NULL, 0);
if (doc == NULL) { if (doc == NULL) {
fprintf (stderr, "Failed to parse %s\n", filename); g_warning("Failed to parse %s\n", filename);
ui_interface.ui_notification_dialog (DIALOG_WARNING, "Failed to parse file %s", filename); // ui_notification_dialog(DIALOG_WARNING, "Failed to parse file %s", filename);
return RC_FAIL; return RC_FAIL;
} }
...@@ -703,17 +692,17 @@ static int xml_parse_doc(xmlDocPtr doc) { ...@@ -703,17 +692,17 @@ static int xml_parse_doc(xmlDocPtr doc) {
dissect_file = fopen ("./dissect.xml", "w"); dissect_file = fopen ("./dissect.xml", "w");
/* Get the root element node */ /* Get the root element node */
root_element = xmlDocGetRootElement (doc); root_element = xmlDocGetRootElement(doc);
ret = parse_elements (root_element, &head); ret = parse_elements(root_element, &head);
/* Free the document */ /* Free the document */
xmlFreeDoc (doc); xmlFreeDoc(doc);
/* Free the global variables that may /* Free the global variables that may
* have been allocated by the parser. * have been allocated by the parser.
*/ */
xmlCleanupParser (); xmlCleanupParser();
if (ret == RC_OK) { if (ret == RC_OK) {
resolve_typedefs (&head); resolve_typedefs (&head);
...@@ -724,34 +713,38 @@ static int xml_parse_doc(xmlDocPtr doc) { ...@@ -724,34 +713,38 @@ static int xml_parse_doc(xmlDocPtr doc) {
resolve_struct (&head); resolve_struct (&head);
resolve_file (&head); resolve_file (&head);
resolve_union (&head); resolve_union (&head);
/* Locate the root element which corresponds to the MessageDef struct */
CHECK_FCT(locate_root("MessageDef", head, &root)); CHECK_FCT(locate_root("MessageDef", head, &root));
/* Locate the message id enumeration */
CHECK_FCT(locate_type("MessagesIds", head, &messages_id_enum));
CHECK_FCT(locate_type("originTaskId", head, &origin_task_id_type));
CHECK_FCT(locate_type("destinationTaskId", head, &destination_task_id_type));
// root->type_hr_display(root, 0); // root->type_hr_display(root, 0);
if (dissect_file != NULL) { if (dissect_file != NULL) {
root->type_file_print (root, 0, dissect_file); root->type_file_print (root, 0, dissect_file);
} }
ui_interface.dissector_ready = 1;
} }
fclose (dissect_file); fclose (dissect_file);
return ret; return ret;
} }
int dissect_signal(const uint32_t message_number) { int dissect_signal(buffer_t *buffer) {
buffer_t *buffer; // buffer_t *buffer;
if (root == NULL) { if (root == NULL) {
ui_interface.ui_notification_dialog (DIALOG_ERROR, "No message XML file provided"); // ui_notification_dialog(DIALOG_ERROR, "No message XML file provided");
return RC_FAIL; return RC_FAIL;
} }
CHECK_FCT(buffer_get_from_mn(message_number, &buffer)); // CHECK_FCT(buffer_get_from_mn(message_number, &buffer));
if (buffer == NULL) { if (buffer == NULL) {
fprintf (stderr, "Failed buffer %u in list\n", message_number); g_error("Failed buffer is NULL\n");
return RC_FAIL; return RC_FAIL;
} }
root->type_dissect_from_buffer (root, buffer, 0, 0, INDENT_START); root->type_dissect_from_buffer(root, buffer, 0, 0, INDENT_START);
return RC_OK; return RC_OK;
} }
...@@ -4,10 +4,12 @@ ...@@ -4,10 +4,12 @@
#ifndef XML_PARSE_H_ #ifndef XML_PARSE_H_
#define XML_PARSE_H_ #define XML_PARSE_H_
extern types_t *root;
int xml_parse_file(const char *filename); int xml_parse_file(const char *filename);
int xml_parse_buffer(const char *xml_buffer, const int size); int xml_parse_buffer(const char *xml_buffer, const int size);
int dissect_signal(const uint32_t message_number); int dissect_signal(buffer_t *buffer);
#endif /* XML_PARSE_H_ */ #endif /* XML_PARSE_H_ */
...@@ -6,9 +6,15 @@ ...@@ -6,9 +6,15 @@
#include "rc.h" #include "rc.h"
#include "types.h" #include "types.h"
#include "enum_type.h"
#include "locate_root.h" #include "locate_root.h"
#include "xml_parse.h"
int locate_root(const char *root_name, types_t *head, types_t **root) { types_t *messages_id_enum = NULL;
types_t *origin_task_id_type = NULL;
types_t *destination_task_id_type = NULL;
int locate_root(const char *root_name, types_t *head, types_t **root_elm) {
types_t *next_type; types_t *next_type;
/* The root element is for example : MessageDef. /* The root element is for example : MessageDef.
...@@ -22,7 +28,7 @@ int locate_root(const char *root_name, types_t *head, types_t **root) { ...@@ -22,7 +28,7 @@ int locate_root(const char *root_name, types_t *head, types_t **root) {
g_warning("Empty list detected"); g_warning("Empty list detected");
return -1; return -1;
} }
if (!root) { if (!root_elm) {
g_warning("NULL root reference"); g_warning("NULL root reference");
return -1; return -1;
} }
...@@ -35,7 +41,7 @@ int locate_root(const char *root_name, types_t *head, types_t **root) { ...@@ -35,7 +41,7 @@ int locate_root(const char *root_name, types_t *head, types_t **root) {
break; break;
} }
} }
*root = next_type; *root_elm = next_type;
return (next_type == NULL) ? -2 : 0; return (next_type == NULL) ? -2 : 0;
} }
...@@ -46,7 +52,7 @@ int locate_type(const char *type_name, types_t *head, types_t **type) { ...@@ -46,7 +52,7 @@ int locate_type(const char *type_name, types_t *head, types_t **type) {
* This element is the entry for other sub-types. * This element is the entry for other sub-types.
*/ */
if (!type_name) { if (!type_name) {
g_warning("FATAL: no root element name provided"); g_warning("FATAL: no element name provided");
return RC_BAD_PARAM; return RC_BAD_PARAM;
} }
if (!head) { if (!head) {
...@@ -69,16 +75,46 @@ int locate_type(const char *type_name, types_t *head, types_t **type) { ...@@ -69,16 +75,46 @@ int locate_type(const char *type_name, types_t *head, types_t **type) {
int get_message_id(types_t *head, buffer_t *buffer, uint32_t *message_id) { int get_message_id(types_t *head, buffer_t *buffer, uint32_t *message_id) {
uint32_t value; uint32_t value;
types_t *type_message_id;
if (!head || !message_id || !buffer)
return RC_BAD_PARAM;
CHECK_FCT(locate_type("messageId", head, &type_message_id)); g_assert(message_id != NULL);
g_assert(buffer != NULL);
/* MessageId is an offset from start of buffer */ /* MessageId is an offset from start of buffer */
value = buffer_get_uint32_t (buffer, type_message_id->offset); value = buffer_get_uint32_t(buffer, messages_id_enum->offset);
*message_id = value; *message_id = value;
return RC_OK; return RC_OK;
} }
char *get_origin_task_id(buffer_t *buffer) {
char *origin_task_id = "UNKNOWN";
uint32_t origin_task_id_value;
/* Fetch task id value */
if (buffer_fetch_bits(buffer, origin_task_id_type->offset,
origin_task_id_type->child->size, &origin_task_id_value) == RC_OK) {
origin_task_id = enum_type_get_name_from_value(origin_task_id_type->child,
origin_task_id_value);
}
return origin_task_id;
}
char *get_destination_task_id(buffer_t *buffer) {
char *destination_task_id = "UNKNOWN";
uint32_t destination_task_id_value;
/* Fetch task id value */
if (buffer_fetch_bits(buffer, destination_task_id_type->offset,
destination_task_id_type->child->size, &destination_task_id_value) == RC_OK) {
destination_task_id = enum_type_get_name_from_value(destination_task_id_type->child,
destination_task_id_value);
}
return destination_task_id;
}
char *message_id_to_string(uint32_t message_id)
{
return enum_type_get_name_from_value(messages_id_enum, message_id);
}
#ifndef LOCATE_ROOT_H_ #ifndef LOCATE_ROOT_H_
#define LOCATE_ROOT_H_ #define LOCATE_ROOT_H_
extern types_t *messages_id_enum;
extern types_t *origin_task_id_type;
extern types_t *destination_task_id_type;
int locate_root(const char *root_name, types_t *head, types_t **root); int locate_root(const char *root_name, types_t *head, types_t **root);
int locate_type(const char *type_name, types_t *head, types_t **type); int locate_type(const char *type_name, types_t *head, types_t **type);
int get_message_id(types_t *head, buffer_t *buffer, uint32_t *message_id); int get_message_id(types_t *head, buffer_t *buffer, uint32_t *message_id);
char *message_id_to_string(uint32_t message_id);
char *get_origin_task_id(buffer_t *buffer);
char *get_destination_task_id(buffer_t *buffer);
#endif /* LOCATE_ROOT_H_ */ #endif /* LOCATE_ROOT_H_ */
...@@ -2,17 +2,19 @@ AM_CFLAGS = \ ...@@ -2,17 +2,19 @@ AM_CFLAGS = \
@ADD_CFLAGS@ \ @ADD_CFLAGS@ \
-I$(top_srcdir)/common \ -I$(top_srcdir)/common \
-I$(top_srcdir)/libbuffers \ -I$(top_srcdir)/libbuffers \
-I$(top_srcdir)/libparser -I$(top_srcdir)/libparser \
-I$(top_srcdir)/libresolver
noinst_LTLIBRARIES = libui.la noinst_LTLIBRARIES = libui.la
libui_la_LDFLAGS = -all-static libui_la_LDFLAGS = -all-static
libui_la_SOURCES = \ libui_la_SOURCES = \
ui_main_screen.c ui_main_screen.h \ ui_main_screen.c ui_main_screen.h \
ui_menu_bar.c ui_menu_bar.h \ ui_menu_bar.c ui_menu_bar.h \
ui_callbacks.c ui_callbacks.h \ ui_callbacks.c ui_callbacks.h \
ui_tree_view.c ui_tree_view.h \ ui_tree_view.c ui_tree_view.h \
ui_signal_dissect_view.c ui_signal_dissect_view.h \ ui_signal_dissect_view.c ui_signal_dissect_view.h \
ui_notifications.c ui_notifications.h \ ui_notifications.c ui_notifications.h \
ui_interface.c ui_interface.h \ ui_notif_dlg.c ui_notif_dlg.h \
ui_notebook.c ui_notebook.h ui_interface.c ui_interface.h \
ui_notebook.c ui_notebook.h
...@@ -5,6 +5,9 @@ ...@@ -5,6 +5,9 @@
#include "rc.h" #include "rc.h"
#include "socket.h"
#include "ui_notif_dlg.h"
#include "ui_main_screen.h" #include "ui_main_screen.h"
#include "ui_callbacks.h" #include "ui_callbacks.h"
#include "ui_interface.h" #include "ui_interface.h"
...@@ -12,6 +15,12 @@ ...@@ -12,6 +15,12 @@
#include "ui_tree_view.h" #include "ui_tree_view.h"
#include "ui_signal_dissect_view.h" #include "ui_signal_dissect_view.h"
#include "types.h"
#include "locate_root.h"
#include "xml_parse.h"
static gboolean ui_handle_socket_connection_failed(gint fd);
gboolean ui_callback_on_open(GtkWidget *widget, gboolean ui_callback_on_open(GtkWidget *widget,
GdkEvent *event, GdkEvent *event,
gpointer data) gpointer data)
...@@ -41,23 +50,22 @@ ui_callback_on_select_signal(GtkTreeSelection *selection, ...@@ -41,23 +50,22 @@ ui_callback_on_select_signal(GtkTreeSelection *selection,
if (gtk_tree_model_get_iter(model, &iter, path)) if (gtk_tree_model_get_iter(model, &iter, path))
{ {
gchar *name; gchar *name;
GValue buffer_store = G_VALUE_INIT;
gpointer buffer;
// g_value_init (&buffer_store, G_TYPE_POINTER);
gtk_tree_model_get(model, &iter, 0, &name, -1); // gtk_tree_model_get(model, &iter, 0, &name, -1);
gtk_tree_model_get_value(model, &iter, COL_BUFFER, &buffer_store);
buffer = g_value_get_pointer(&buffer_store);
if (!path_currently_selected) if (!path_currently_selected)
{ {
if (ui_interface.dissector_ready != 0) { /* Clear the view */
uint32_t message_number; CHECK_FCT_DO(ui_signal_dissect_clear_view(), return FALSE);
CHECK_FCT_DO(dissect_signal((buffer_t*)buffer), return FALSE);
sscanf(name, "%u", &message_number);
/* Clear the view */
CHECK_FCT_DO(ui_signal_dissect_clear_view(), return FALSE);
// g_print ("%s is going to be selected.\n", name);
CHECK_FCT_DO(ui_interface.dissect_signal(message_number), return FALSE);
} else {
ui_notification_dialog(DIALOG_ERROR, "No XML signal description"
" provided\n");
}
} }
else else
{ {
...@@ -69,21 +77,162 @@ ui_callback_on_select_signal(GtkTreeSelection *selection, ...@@ -69,21 +77,162 @@ ui_callback_on_select_signal(GtkTreeSelection *selection,
return TRUE; return TRUE;
} }
void ui_signal_add_to_list(gpointer data, gpointer user_data)
{
buffer_t *signal_buffer;
signal_buffer = (buffer_t *)data;
get_message_id(root, signal_buffer, &signal_buffer->message_id);
ui_tree_view_new_signal_ind(signal_buffer->message_number,
message_id_to_string(signal_buffer->message_id),
get_origin_task_id(signal_buffer),
get_destination_task_id(signal_buffer),
data);
}
static gboolean ui_handle_update_signal_list(gint fd, const void *data,
size_t data_length)
{
pipe_new_signals_list_message_t *signal_list_message;
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, NULL);
free(data);
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, const 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_debug("[gui] Unhandled message type %u", input_header.message_type);
g_assert_not_reached();
}
return FALSE;
}
gboolean ui_callback_on_connect(GtkWidget *widget, gboolean ui_callback_on_connect(GtkWidget *widget,
GdkEvent *event, GdkEvent *event,
gpointer data) gpointer data)
{ {
/* We have to retrieve the ip address and port of remote host */ /* We have to retrieve the ip address and port of remote host */
uint16_t port;
const char *ip; const char *ip;
uint16_t port;
int pipe_fd[2];
g_debug("Connect event occurred"); g_debug("Connect event occurred");
port = atoi(gtk_entry_get_text(GTK_ENTRY(ui_main_data.portentry))); port = atoi(gtk_entry_get_text(GTK_ENTRY(ui_main_data.portentry)));
ip = gtk_entry_get_text(GTK_ENTRY(ui_main_data.ipentry)); ip = gtk_entry_get_text(GTK_ENTRY(ui_main_data.ipentry));
// ui_tree_view_destroy_list(); if ((ip == NULL) || (port == 0)) {
ui_interface.socket_connect(ip, port); g_warning("NULL parameter given for ip address or port = 0");
/* TODO: add dialog box here */
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();
if (socket_connect_to_remote_host(ip, port, pipe_fd[1]) != 0) {
ui_enable_connect_button();
return FALSE;
}
return TRUE; return TRUE;
} }
...@@ -95,7 +244,11 @@ gboolean ui_callback_on_disconnect(GtkWidget *widget, ...@@ -95,7 +244,11 @@ gboolean ui_callback_on_disconnect(GtkWidget *widget,
/* We have to retrieve the ip address and port of remote host */ /* We have to retrieve the ip address and port of remote host */
g_debug("Disconnect event occurred"); g_debug("Disconnect event occurred");
ui_interface.socket_disconnect();
ui_pipe_write_message(ui_main_data.pipe_fd[0], UI_PIPE_DISCONNECT_EVT,
NULL, 0);
ui_enable_connect_button();
return TRUE; return TRUE;
} }
...@@ -107,4 +260,3 @@ gboolean ui_callback_on_tree_view_select(GtkWidget *widget, ...@@ -107,4 +260,3 @@ gboolean ui_callback_on_tree_view_select(GtkWidget *widget,
g_debug("List selection event occurred"); g_debug("List selection event occurred");
return TRUE; return TRUE;
} }
...@@ -28,4 +28,6 @@ ui_callback_on_select_signal(GtkTreeSelection *selection, ...@@ -28,4 +28,6 @@ ui_callback_on_select_signal(GtkTreeSelection *selection,
gboolean path_currently_selected, gboolean path_currently_selected,
gpointer userdata); gpointer userdata);
gboolean ui_pipe_callback(gint source, gpointer user_data);
#endif /* UI_CALLBACKS_H_ */ #endif /* UI_CALLBACKS_H_ */
...@@ -14,21 +14,91 @@ ...@@ -14,21 +14,91 @@
#include "xml_parse.h" #include "xml_parse.h"
ui_interface_t ui_interface = { ui_interface_t ui_interface = {
.dissector_ready = 0,
/** core program -> UI **/
.ui_notification_dialog = ui_notification_dialog,
.ui_disable_connect_button = ui_disable_connect_button,
.ui_enable_connect_button = ui_enable_connect_button,
.ui_progress_bar_set_fraction = ui_progress_bar_set_fraction,
.ui_progress_bar_terminate = ui_progress_bar_terminate,
.ui_tree_view_new_signal_ind = ui_tree_view_new_signal_ind,
.ui_signal_set_text = ui_signal_set_text, .ui_signal_set_text = ui_signal_set_text,
};
/** UI -> core program **/ static
.socket_connect = socket_connect_to_remote_host, gboolean ui_callback_on_pipe_notification(
.socket_disconnect = socket_disconnect_from_remote_host, GIOChannel *source, GIOCondition condition, gpointer user_data)
{
pipe_input_t *pipe_input = (pipe_input_t *)user_data;
.parse_signal_file = xml_parse_file, /* avoid reentrancy problems and stack overflow */
.dissect_signal = dissect_signal, g_source_remove(pipe_input->pipe_input_id);
};
g_debug("Received new data on pipe %d", pipe_input->pipe_input_id);
if (pipe_input->input_cb(pipe_input->source_fd, pipe_input->user_data)) {
/* restore pipe handler */
pipe_input->pipe_input_id = g_io_add_watch_full(pipe_input->pipe_channel,
G_PRIORITY_HIGH,
(GIOCondition)(G_IO_IN|G_IO_ERR|G_IO_HUP),
ui_callback_on_pipe_notification,
pipe_input,
NULL);
}
return TRUE;
}
int ui_pipe_new(int pipe_fd[2], pipe_input_cb_t input_cb, gpointer user_data)
{
static pipe_input_t pipe_input;
g_assert(pipe_fd != NULL);
/* Create a pipe between GUI and a thread or a process */
if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pipe_fd) < 0) {
g_warning("Failed to create socketpair %s", g_strerror(errno));
return RC_FAIL;
}
/* Source taken from wireshark SVN repository */
pipe_input.source_fd = pipe_fd[0];
pipe_input.input_cb = input_cb;
pipe_input.user_data = user_data;
pipe_input.pipe_channel = g_io_channel_unix_new(pipe_fd[0]);
g_io_channel_set_encoding(pipe_input.pipe_channel, NULL, NULL);
pipe_input.pipe_input_id = g_io_add_watch_full(pipe_input.pipe_channel,
G_PRIORITY_HIGH,
G_IO_IN | G_IO_ERR | G_IO_HUP,
ui_callback_on_pipe_notification,
&pipe_input,
NULL);
return RC_OK;
}
int ui_pipe_write_message(int pipe_fd, const uint16_t message_type,
const void * const message, const uint16_t message_size)
{
int ret;
pipe_input_header_t pipe_input_header;
pipe_input_header.message_size = message_size + sizeof(pipe_input_header);
pipe_input_header.message_type = message_type;
if (message_size > 0 && message == NULL) {
g_error("message size = %u but message is NULL", message_size);
g_assert_not_reached();
}
ret = write(pipe_fd, &pipe_input_header, sizeof(pipe_input_header));
if (ret < 0) {
g_debug("Failed to write header to pipe: %s", g_strerror(errno));
return ret;
}
/* Only write the message to pipe if valid data to transmit */
if (message_size > 0) {
ret = write(pipe_fd, message, message_size);
if (ret < 0) {
g_debug("Failed to write message of size %u at 0x%p to pipe: %s",
message_size, message, g_strerror(errno));
return ret;
}
}
return 0;
}
#include <glib.h>
#ifndef UI_INTERFACE_H_ #ifndef UI_INTERFACE_H_
#define UI_INTERFACE_H_ #define UI_INTERFACE_H_
typedef enum dialog_type_e {
DIALOG_INFO,
DIALOG_WARNING,
DIALOG_QUESTION,
DIALOG_ERROR,
DIALOG_OTHER,
DIALOG_MAX
} dialog_type_t;
/**
* socket_connect_t
* @param remote_ip Remote ipv4 address
* @param port Remote port number
* @return RC_OK on Success, < 0 on failure
**/
typedef int (*socket_connect_t)(const char *remote_ip, const uint16_t port);
typedef int (*socket_disconnect_t)(void);
typedef int (*parse_signal_file_t)(const char *filename);
typedef int (*dissect_signal_t)(const uint32_t message_number);
/**
* ui_notification_dialog_t
* @param type Type for the new dialog box
* @param fmt String formater
* @param ... argument list
* @return RC_OK on Success, < 0 on failure
**/
typedef int (*ui_notification_dialog_t)(dialog_type_t type, const char *fmt, ...);
typedef int (*ui_disable_connect_button_t)(void);
typedef int (*ui_enable_connect_button_t)(void);
typedef int (*ui_progress_bar_set_fraction_t)(double fraction);
typedef int (*ui_progress_bar_terminate_t)(void);
typedef int (*ui_tree_view_new_signal_ind_t)(const uint32_t message_number, const char *signal_name);
typedef int (*ui_signal_set_text_t)(char *text, int length); typedef int (*ui_signal_set_text_t)(char *text, int length);
typedef struct { typedef struct {
/** UI -> core program */
socket_connect_t socket_connect;
socket_disconnect_t socket_disconnect;
parse_signal_file_t parse_signal_file;
dissect_signal_t dissect_signal;
/** core program -> UI */ /** core program -> UI */
int dissector_ready;
ui_notification_dialog_t ui_notification_dialog;
ui_disable_connect_button_t ui_disable_connect_button;
ui_enable_connect_button_t ui_enable_connect_button;
ui_progress_bar_set_fraction_t ui_progress_bar_set_fraction;
ui_progress_bar_terminate_t ui_progress_bar_terminate;
ui_tree_view_new_signal_ind_t ui_tree_view_new_signal_ind;
ui_signal_set_text_t ui_signal_set_text; ui_signal_set_text_t ui_signal_set_text;
} ui_interface_t; } ui_interface_t;
extern ui_interface_t ui_interface; extern ui_interface_t ui_interface;
/*******************************************************************************
* Pipe interface between GUI thread and other thread
******************************************************************************/
typedef gboolean (*pipe_input_cb_t) (gint source, gpointer user_data);
typedef struct {
int source_fd;
guint pipe_input_id;
GIOChannel *pipe_channel;
pipe_input_cb_t input_cb;
gpointer user_data;
} pipe_input_t;
int ui_pipe_new(int pipe_fd[2], pipe_input_cb_t input_cb, gpointer user_data);
int ui_pipe_write_message(int pipe_fd, const uint16_t message_type,
const void * const message, const uint16_t message_size);
typedef struct {
uint16_t message_size;
uint16_t message_type;
} pipe_input_header_t;
enum ui_pipe_messages_id_e {
/* Other thread -> GUI interface ids */
UI_PIPE_CONNECTION_FAILED,
UI_PIPE_CONNECTION_LOST,
UI_PIPE_XML_DEFINITION,
UI_PIPE_UPDATE_SIGNAL_LIST,
/* GUI -> other threads */
UI_PIPE_DISCONNECT_EVT
};
typedef struct {
char *xml_definition;
size_t xml_definition_length;
} pipe_xml_definition_message_t;
typedef struct {
GList *signal_list;
} pipe_new_signals_list_message_t;
#endif /* UI_INTERFACE_H_ */ #endif /* UI_INTERFACE_H_ */
...@@ -13,6 +13,8 @@ typedef struct { ...@@ -13,6 +13,8 @@ typedef struct {
/* Buttons */ /* Buttons */
GtkToolItem *connect; GtkToolItem *connect;
GtkToolItem *disconnect; GtkToolItem *disconnect;
int pipe_fd[2];
} ui_main_data_t; } ui_main_data_t;
extern ui_main_data_t ui_main_data; extern ui_main_data_t ui_main_data;
......
#include "rc.h"
#include "ui_notif_dlg.h"
#include "ui_main_screen.h"
int ui_notification_dialog(dialog_type_t type, const char *fmt, ...)
{
va_list args;
GtkWidget *dialogbox;
va_start(args, fmt);
dialogbox = gtk_message_dialog_new(GTK_WINDOW(ui_main_data.window),
GTK_DIALOG_MODAL, type,
GTK_BUTTONS_OK, fmt, args);
gtk_dialog_run(GTK_DIALOG (dialogbox));
gtk_widget_destroy (dialogbox);
va_end(args);
return RC_OK;
}
#include <gtk/gtk.h>
#ifndef UI_NOTIF_DLG_H_
#define UI_NOTIF_DLG_H_
typedef enum dialog_type_e {
DIALOG_INFO,
DIALOG_WARNING,
DIALOG_QUESTION,
DIALOG_ERROR,
DIALOG_OTHER,
DIALOG_MAX
} dialog_type_t;
extern int ui_notification_dialog(dialog_type_t type, const char *fmt, ...);
#endif /* UI_NOTIF_DLG_H_ */
...@@ -10,33 +10,7 @@ ...@@ -10,33 +10,7 @@
#include "ui_main_screen.h" #include "ui_main_screen.h"
#include "ui_notifications.h" #include "ui_notifications.h"
int ui_notification_dialog(dialog_type_t type, const char *fmt, ...) #include "xml_parse.h"
{
va_list ap;
GtkWidget *dialogbox;
va_start(ap, fmt);
/* In multi-threaded environnements gtk calls should be protected by
* gdk_threads_enter before calling the GTK function
* gdk_threads_leave when GTK function has exited
*/
gdk_threads_enter();
dialogbox = gtk_message_dialog_new(
GTK_WINDOW(ui_main_data.window), GTK_DIALOG_MODAL, type,
GTK_BUTTONS_OK, fmt, ap);
gtk_dialog_run(GTK_DIALOG (dialogbox));
gtk_widget_destroy (dialogbox);
gdk_threads_leave();
va_end(ap);
return RC_OK;
}
int ui_disable_connect_button(void) int ui_disable_connect_button(void)
{ {
...@@ -71,8 +45,8 @@ int ui_file_chooser(void) ...@@ -71,8 +45,8 @@ int ui_file_chooser(void)
char *filename; char *filename;
filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (filechooser)); filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (filechooser));
ui_interface.parse_signal_file(filename); xml_parse_file(filename);
g_free (filename); g_free(filename);
} }
gtk_widget_destroy (filechooser); gtk_widget_destroy (filechooser);
......
#ifndef UI_NOTIFICATIONS_H_ #ifndef UI_NOTIFICATIONS_H_
#define UI_NOTIFICATIONS_H_ #define UI_NOTIFICATIONS_H_
int ui_notification_dialog(dialog_type_t type, const char *fmt, ...);
int ui_disable_connect_button(void); int ui_disable_connect_button(void);
int ui_enable_connect_button(void); int ui_enable_connect_button(void);
......
...@@ -5,21 +5,16 @@ ...@@ -5,21 +5,16 @@
#include "rc.h" #include "rc.h"
#include "buffers.h"
#include "ui_main_screen.h" #include "ui_main_screen.h"
#include "ui_tree_view.h" #include "ui_tree_view.h"
#include "ui_callbacks.h" #include "ui_callbacks.h"
#include "ui_signal_dissect_view.h" #include "ui_signal_dissect_view.h"
enum
{
COL_MSG_NUM = 0,
COL_SIGNAL,
NUM_COLS
} ;
static void static void
init_list(GtkWidget *list) ui_tree_view_init_list(GtkWidget *list)
{ {
GtkCellRenderer *renderer; GtkCellRenderer *renderer;
GtkTreeViewColumn *column; GtkTreeViewColumn *column;
...@@ -27,22 +22,40 @@ init_list(GtkWidget *list) ...@@ -27,22 +22,40 @@ init_list(GtkWidget *list)
renderer = gtk_cell_renderer_text_new(); renderer = gtk_cell_renderer_text_new();
column = gtk_tree_view_column_new_with_attributes( column = gtk_tree_view_column_new_with_attributes(
"Message Number", renderer, "text", COL_MSG_NUM, NULL); "MN", renderer, "text", COL_MSG_NUM, NULL);
gtk_tree_view_append_column(GTK_TREE_VIEW(list), column); gtk_tree_view_append_column(GTK_TREE_VIEW(list), column);
column = gtk_tree_view_column_new_with_attributes( column = gtk_tree_view_column_new_with_attributes(
"Signal", renderer, "text", COL_SIGNAL, NULL); "Signal", renderer, "text", COL_SIGNAL, NULL);
gtk_tree_view_append_column(GTK_TREE_VIEW(list), column); gtk_tree_view_append_column(GTK_TREE_VIEW(list), column);
store = gtk_list_store_new(NUM_COLS, G_TYPE_STRING, G_TYPE_STRING); column = gtk_tree_view_column_new_with_attributes(
"From", renderer, "text", COL_FROM_TASK, NULL);
gtk_tree_view_append_column(GTK_TREE_VIEW(list), column);
column = gtk_tree_view_column_new_with_attributes(
"To", renderer, "text", COL_TO_TASK, NULL);
gtk_tree_view_append_column(GTK_TREE_VIEW(list), column);
store = gtk_list_store_new(NUM_COLS,
G_TYPE_STRING,
G_TYPE_STRING,
G_TYPE_STRING,
G_TYPE_STRING,
/* HACK: add a reference to the buffer here
* to avoid maintining multiple lists.
* The reference is not displayed
*/
G_TYPE_POINTER);
gtk_tree_view_set_model(GTK_TREE_VIEW(list), GTK_TREE_MODEL(store)); gtk_tree_view_set_model(GTK_TREE_VIEW(list), GTK_TREE_MODEL(store));
g_object_unref(store); g_object_unref(store);
} }
static void static void ui_tree_view_add_to_list(GtkWidget *list, const gchar *message_number,
add_to_list(GtkWidget *list, const gchar *message_number, const gchar *signal_name) const gchar *signal_name, const char *origin_task,
const char *to_task, gpointer buffer)
{ {
GtkListStore *store; GtkListStore *store;
GtkTreeIter iter; GtkTreeIter iter;
...@@ -51,8 +64,15 @@ add_to_list(GtkWidget *list, const gchar *message_number, const gchar *signal_na ...@@ -51,8 +64,15 @@ add_to_list(GtkWidget *list, const gchar *message_number, const gchar *signal_na
(GTK_TREE_VIEW(list))); (GTK_TREE_VIEW(list)));
gtk_list_store_append(store, &iter); gtk_list_store_append(store, &iter);
gtk_list_store_set(store, &iter, COL_MSG_NUM, message_number, gtk_list_store_set(store, &iter,
COL_SIGNAL, signal_name, -1); /* Columns */
COL_MSG_NUM , message_number,
COL_SIGNAL , signal_name,
COL_FROM_TASK , origin_task,
COL_TO_TASK , to_task,
COL_BUFFER , buffer,
/* End of columns */
-1);
} }
void ui_tree_view_destroy_list(GtkWidget *list) void ui_tree_view_destroy_list(GtkWidget *list)
...@@ -92,7 +112,7 @@ int ui_tree_view_create(GtkWidget *window, GtkWidget *vbox) ...@@ -92,7 +112,7 @@ int ui_tree_view_create(GtkWidget *window, GtkWidget *vbox)
gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled_window), gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled_window),
ui_main_data.signalslist); ui_main_data.signalslist);
init_list(ui_main_data.signalslist); ui_tree_view_init_list(ui_main_data.signalslist);
// gtk_widget_get_size_request(GTK_WIDGET(ui_main_data.signalslist), &width, NULL); // gtk_widget_get_size_request(GTK_WIDGET(ui_main_data.signalslist), &width, NULL);
gtk_widget_set_size_request(GTK_WIDGET(scrolled_window), 350, -1); gtk_widget_set_size_request(GTK_WIDGET(scrolled_window), 350, -1);
...@@ -110,13 +130,15 @@ int ui_tree_view_create(GtkWidget *window, GtkWidget *vbox) ...@@ -110,13 +130,15 @@ int ui_tree_view_create(GtkWidget *window, GtkWidget *vbox)
return 0; return 0;
} }
int ui_tree_view_new_signal_ind(const uint32_t message_number, const char *signal_name) int ui_tree_view_new_signal_ind(const uint32_t message_number, const char *signal_name,
const char *origin_task, const char *to_task, gpointer buffer)
{ {
gchar message_number_str[11]; gchar message_number_str[11];
sprintf(message_number_str, "%u", message_number); sprintf(message_number_str, "%u", message_number);
add_to_list(ui_main_data.signalslist, message_number_str, signal_name); ui_tree_view_add_to_list(ui_main_data.signalslist, message_number_str, signal_name,
origin_task, to_task, (buffer_t *)buffer);
return RC_OK; return RC_OK;
} }
#ifndef UI_TREE_VIEW_H_ #ifndef UI_TREE_VIEW_H_
#define UI_TREE_VIEW_H_ #define UI_TREE_VIEW_H_
enum
{
COL_MSG_NUM = 0,
COL_SIGNAL,
COL_FROM_TASK,
COL_TO_TASK,
COL_BUFFER,
NUM_COLS
};
int ui_tree_view_create(GtkWidget *window, GtkWidget *vbox); int ui_tree_view_create(GtkWidget *window, GtkWidget *vbox);
int ui_tree_view_new_signal_ind(const uint32_t message_number, const char *signal_name); int ui_tree_view_new_signal_ind(const uint32_t message_number, const char *signal_name,
const char *origin_task, const char *to_task, gpointer buffer);
void ui_tree_view_destroy_list(GtkWidget *list); void ui_tree_view_destroy_list(GtkWidget *list);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment