diff options
author | Jeremias Stotter <jeremias@stotter.eu> | 2023-10-01 23:32:15 +0200 |
---|---|---|
committer | Jeremias Stotter <jeremias@stotter.eu> | 2023-10-01 23:32:15 +0200 |
commit | d77caf955f15e1f28c26b6657c1727ac138bf0ed (patch) | |
tree | 8eaf4f75e5847ee9020233c2259be282a9f9e3e2 | |
parent | 0da079272c273871e3fa568bef3a6092d4339b3f (diff) | |
download | network-simulator-d77caf955f15e1f28c26b6657c1727ac138bf0ed.tar.gz network-simulator-d77caf955f15e1f28c26b6657c1727ac138bf0ed.tar.bz2 network-simulator-d77caf955f15e1f28c26b6657c1727ac138bf0ed.zip |
Use functions not deprecated in GTK 4.10
This will propably break building with anything below gtk 4.10 tho
-rw-r--r-- | Project.ede | 2 | ||||
-rw-r--r-- | device.c | 2 | ||||
-rw-r--r-- | files.c | 2 | ||||
-rw-r--r-- | gui.c | 250 | ||||
-rw-r--r-- | gui_device.c | 52 | ||||
-rw-r--r-- | interface.c | 26 | ||||
-rw-r--r-- | interface.h | 3 |
7 files changed, 186 insertions, 151 deletions
diff --git a/Project.ede b/Project.ede index 20d326e..06b56ba 100644 --- a/Project.ede +++ b/Project.ede @@ -18,4 +18,4 @@ :object-name "netsim" :makefile-type Makefile :variables '(("LUA_VERSION" . "lua5.4") ("PKG_CONFIG" . "pkgconf") ("CFLAGS" . "-std=c99 $(shell $(PKG_CONFIG) --cflags $(LUA_VERSION) json-c gtk4)") ("LDFLAGS" . "$(shell $(PKG_CONFIG) --libs $(LUA_VERSION) json-c gtk4) -lm")) - :configuration-variables '(("debug" ("CFLAGS" . "-O0 -Wno-deprecated-declarations -Wall -g")) ("release" ("CFLAGS" . "-O2")))) + :configuration-variables '(("debug" ("CFLAGS" . "-O0 -Wall -g")) ("release" ("CFLAGS" . "-O2")))) @@ -225,7 +225,7 @@ struct device* new_device(struct device** start, char* device_name, struct dev_t for(int i = 0; i < cur_template->slots; i++) { char* int_template_name = cur_template->interfaces[i]; if(int_template_name) { - new_interface(new_device, i, int_template_name); + new_interface_from_template_name(new_device, i, int_template_name); } } @@ -221,7 +221,7 @@ int load_file(char* filename) { json_object* int_name_json = json_object_array_get_idx(slots, j); const char* int_name = json_object_get_string(int_name_json); if(!int_name) continue; - new_interface(load_dev, j, int_name); + new_interface_from_template_name(load_dev, j, int_name); } } @@ -92,8 +92,10 @@ GtkWidget* text_button = NULL; GtkWidget* rect_button = NULL; GtkWidget* circle_button = NULL; -// The packet list -GtkListStore* packet_list = NULL; +GListStore* file_filter_list = NULL; + +// The packet list store +GListStore* packet_list_store = NULL; enum { PACKET_COL_DEV1, PACKET_COL_DEV2, @@ -437,16 +439,6 @@ void update_main_drawing_area(GtkDrawingArea* drawing_area, cairo_surface_destroy(image_surface); } -// Remove a row from the list -int free_packet_data(GtkTreeModel* model, GtkTreePath* path, GtkTreeIter* iter, gpointer data) { - void* free_data = NULL; - gtk_tree_model_get(model, iter, PACKET_COL_DATA, &free_data, -1); - free(free_data); - gtk_list_store_remove(GTK_LIST_STORE(model), iter); - return true; -} - - // Call after a packet drawing has completed to make the packet disapear from the gui int clean_draw() { // Free what we don't need @@ -488,14 +480,13 @@ int clean_draw() { void sidebar_select_current() { if(!drawing_entries) return; // Set the active element in the list to the current entry - GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(packet_tree)); + GtkSelectionModel* selection = gtk_column_view_get_model(GTK_COLUMN_VIEW(packet_tree)); // See how many indices we have - gtk_tree_selection_unselect_all(selection); + gtk_selection_model_unselect_all(selection); struct timestep_entry_ll* sel_entry = drawing_entries; unsigned long sel_time = sel_entry->send_timestamp; do { - GtkTreePath* select_path = gtk_tree_path_new_from_indices(sel_entry->send_entry->gui_index, -1); - gtk_tree_selection_select_path(selection, select_path); + gtk_selection_model_select_item(selection, sel_entry->send_entry->gui_index, true); sel_entry = sel_entry->next; } while(sel_entry && sel_entry->send_timestamp == sel_time); } @@ -530,7 +521,7 @@ void toggle_fast_mode(GtkWidget* self, gpointer data) { NULL ); fastmode = true; - gtk_widget_hide(packet_tree_scroll); + gtk_widget_set_visible(packet_tree_scroll, false); // Make the buttons inacetive gtk_widget_set_sensitive(rewind_button, false); gtk_widget_set_sensitive(play_button, false); @@ -538,7 +529,7 @@ void toggle_fast_mode(GtkWidget* self, gpointer data) { gtk_widget_set_sensitive(speed_slider, false); // Clear the packet list // Kinda shitty way to manually free this, maybe look into g_boxed someday? - gtk_tree_model_foreach(GTK_TREE_MODEL(packet_list), free_packet_data, NULL); + g_list_store_remove_all(packet_list_store); while(allocated_entries != drawing_entries && drawing_entries) { free(drawing_entries->send_entry); struct timestep_entry_ll* old_entry = drawing_entries; @@ -1182,7 +1173,7 @@ void copy_selection_clipboard(struct device_selection* selection) { for(int i = 0; i < dev->template->slots; i++) { if(!dev->interfaces[i].parent_device) continue; - new_interface(new_dev, i, dev->interfaces[i].template->name); + new_interface(new_dev, i, dev->interfaces[i].template); // Check in the originial how the neighbour device is called if(dev->interfaces[i].connection) { char* neigh_name; @@ -1280,7 +1271,8 @@ int gui_send_info(struct interface* send_interface, const char* send_data, int d if(!fastmode) { if(!send_interface || !send_interface->connection) return -1; struct connection* con = send_interface->connection; - GtkTreeIter packet_iter; + + /*GtkTreeIter packet_iter; gtk_list_store_append(packet_list, &packet_iter); // Copy the data to a buffer so that is stays persistent char* data_buffer = malloc_or_abort(data_len); @@ -1296,7 +1288,27 @@ int gui_send_info(struct interface* send_interface, const char* send_data, int d con ? "Buffered" : "Disconected", -1); // Get the index of the packet in the list GtkTreePath* new_path = gtk_tree_model_get_path(GTK_TREE_MODEL(packet_list), &packet_iter); - int index = *(gtk_tree_path_get_indices(new_path)); + int index = *(gtk_tree_path_get_indices(new_path));*/ + + GObject* data_object = g_object_new(G_TYPE_OBJECT, NULL); + g_object_set_data(data_object, "Status", con ? "Buffered" : "Disconected"); + g_object_set_data(data_object, "Device1", send_interface->parent_device->name); + g_object_set_data(data_object, "Device2", send_interface == send_interface->connection->interface1 ? + send_interface->connection->interface2->parent_device->name : + send_interface->connection->interface1->parent_device->name); + char* data_buffer = malloc_or_abort(data_len); + memcpy(data_buffer, send_data, data_len); + g_object_set_data_full(data_object, "Data", data_buffer, free); + + int* size_buffer = malloc_or_abort(sizeof(int)); + *size_buffer = data_len; + g_object_set_data_full(data_object, "Size", size_buffer, free); + + g_object_set_data(data_object, "Type", (char*)type); + + g_list_store_append(packet_list_store, data_object); + int index = g_list_model_get_n_items(G_LIST_MODEL(packet_list_store))-1; + return index; } else return 0; } @@ -1306,10 +1318,9 @@ void gui_con_send(struct connection* con, int send_side) { if(!fastmode) { struct interface* inter = (send_side == 1) ? con->interface1 : con->interface2; int gui_index = inter->start_queue->gui_index; - GtkTreeIter set_iter; - GtkTreePath* set_path = gtk_tree_path_new_from_indices(gui_index, -1); - gtk_tree_model_get_iter(GTK_TREE_MODEL(packet_list), &set_iter, set_path); - gtk_list_store_set(packet_list, &set_iter, PACKET_COL_STATUS, "Sent\0", -1); + GObject* data_object = g_list_model_get_object(G_LIST_MODEL(packet_list_store), gui_index); + + g_object_set_data(data_object, "Status", "Sent"); } } @@ -1362,18 +1373,14 @@ void update_zoom(GtkWidget* self, const int* change) { } // === Called when a packet in the list is selected -void packet_selected(GtkTreeView* self, GtkTreePath* path, GtkTreeViewColumn* column, gpointer user_data) { - GtkTreeModel* select_model = gtk_tree_view_get_model(self); - GtkTreeIter selected_iter; - if(!gtk_tree_model_get_iter(select_model, &selected_iter, path)) { - fprintf(stderr, "Couldn't get iter for packet\n"); - return; - } - int data_size = 0; - char* data = NULL; - char* data_type; - gtk_tree_model_get(select_model, &selected_iter, PACKET_COL_SIZE, &data_size, PACKET_COL_DATA, &data, PACKET_COL_TYPE, &data_type, -1); - show_packet_window(data_size, data, data_type); +void packet_selected(GtkColumnView* self, int position, gpointer user_data) { + GObject* data_object = g_list_model_get_object(G_LIST_MODEL(packet_list_store) + , position); + char* data = g_object_get_data(data_object, "Data"); + char* data_type = g_object_get_data(data_object, "Type"); + int* data_size = g_object_get_data(data_object, "Size"); + + show_packet_window(*data_size, data, data_type); } void forward_timestep(GtkButton* self, gpointer user_data) { @@ -1397,31 +1404,30 @@ void rewind_timestep(GtkButton* self, gpointer user_data) { sidebar_select_current(); } -char* file_chooser_get_path(GtkFileChooser* dialog) { - GFile* selected_file = gtk_file_chooser_get_file(dialog); - char* path = g_file_get_path(selected_file); - g_object_unref(selected_file); - return path; -} - -void save_response(GtkDialog* dialog, int response_id) { - if(response_id == 1) { +void save_response(GObject* save_dialog, GAsyncResult* res, gpointer data) { + GFile* result_file = gtk_file_dialog_save_finish (GTK_FILE_DIALOG(save_dialog), + res, + NULL); + if(result_file) { + if(save_path) + g_free(save_path); + save_path = g_file_get_path(result_file); + g_object_unref(result_file); + g_object_unref(result_file); if(save_path) g_free(save_path); //@todo: check for errors when saving - save_path = file_chooser_get_path(GTK_FILE_CHOOSER(dialog)); save_file(save_path); actions_since_save = 0; + } - gtk_window_destroy(GTK_WINDOW(dialog)); gtk_widget_queue_draw(main_drawing_area); } void gui_save_as_action(GSimpleAction* self, GVariant* parameter, gpointer user_data) { - GtkWidget* save_dialog = gtk_file_chooser_dialog_new("Save", GTK_WINDOW(window), - GTK_FILE_CHOOSER_ACTION_SAVE, "Save", 1, NULL); - g_signal_connect(save_dialog, "response", G_CALLBACK(save_response), NULL); - gtk_widget_set_visible(save_dialog, true); + + GtkFileDialog* save_dialog = gtk_file_dialog_new(); + gtk_file_dialog_save(save_dialog, GTK_WINDOW(window), NULL, save_response, NULL); } void gui_save_action(GSimpleAction* self, GVariant* parameter, gpointer user_data) { @@ -1433,8 +1439,11 @@ void gui_save_action(GSimpleAction* self, GVariant* parameter, gpointer user_dat } } -void load_response(GtkDialog* dialog, int response_id) { - if(response_id == 1) { +void load_response(GObject* load_dialog, GAsyncResult* res, gpointer data) { + GFile* result_file = gtk_file_dialog_open_finish (GTK_FILE_DIALOG(load_dialog), + res, + NULL); + if(result_file) { // Free all devices for(struct device* cur_dev = start_device; cur_dev;) { struct device* free_dev = cur_dev; @@ -1450,40 +1459,29 @@ void load_response(GtkDialog* dialog, int response_id) { if(save_path) g_free(save_path); - save_path = file_chooser_get_path(GTK_FILE_CHOOSER(dialog)); + save_path = g_file_get_path(result_file); + g_object_unref(result_file); load_file(save_path); } - gtk_window_destroy(GTK_WINDOW(dialog)); gtk_widget_queue_draw(main_drawing_area); } void do_load() { - GtkFileFilter* json_filter = gtk_file_filter_new(); - gtk_file_filter_add_suffix(json_filter, "json"); - GtkWidget* load_dialog = gtk_file_chooser_dialog_new("Load", GTK_WINDOW(window), GTK_FILE_CHOOSER_ACTION_OPEN, - "Load", 1, NULL); - gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(load_dialog), json_filter); - g_signal_connect(load_dialog, "response", G_CALLBACK(load_response), NULL); - gtk_widget_set_visible(load_dialog, true); - + GtkFileDialog* load_dialog = gtk_file_dialog_new(); + gtk_file_dialog_set_filters(load_dialog, G_LIST_MODEL(file_filter_list)); + gtk_file_dialog_open(load_dialog, GTK_WINDOW(window), NULL, load_response, NULL); } -void load_yn_response(GtkDialog* self, int response_id, gpointer user_data) { - if(response_id == GTK_RESPONSE_YES) { - gtk_window_close(GTK_WINDOW(self)); +void load_yn_response(GObject* self, GAsyncResult* response_id, gpointer data) { + int result = gtk_alert_dialog_choose_finish(GTK_ALERT_DIALOG(self), response_id, NULL); + if(result == 0) do_load(); - } else - gtk_window_close(GTK_WINDOW(self)); } void gui_load_action(GSimpleAction* self, GVariant* parameter, gpointer user_data) { // File filter for only allowing json files if(actions_since_save > 0) { - // If there have been any changes ask if we should discard before loading - GtkWidget* load_yn_dialog = gtk_message_dialog_new(GTK_WINDOW(window), - GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL, - GTK_MESSAGE_QUESTION, - GTK_BUTTONS_YES_NO, - "You made changes since you last saved, do you really want to load another file and overwrite those changes?"); - g_signal_connect(G_OBJECT(load_yn_dialog), "response", G_CALLBACK(load_yn_response), NULL); - gtk_widget_set_visible(load_yn_dialog, true); + GtkAlertDialog* load_yn_dialog = gtk_alert_dialog_new("You made changes since you last saved, do you really want to load another file and overwrite those changes?"); + gtk_alert_dialog_set_buttons(load_yn_dialog, (const char*[]){"Yes", "No", NULL}); + gtk_alert_dialog_set_cancel_button(load_yn_dialog, 1); + gtk_alert_dialog_choose(load_yn_dialog, GTK_WINDOW(window), NULL, load_yn_response, NULL); } else // No changes have been made, just load do_load(); @@ -1500,26 +1498,19 @@ void gui_redo_action(GSimpleAction* self, GVariant* parameter, gpointer user_dat } // Ask the user if he wants to close without saving -void close_response(GtkDialog* self, int response_id, gpointer user_data) { - if(response_id == GTK_RESPONSE_YES) { - actions_since_save = 0; +void close_yn_response(GObject* self, GAsyncResult* response_id, gpointer data) { + int result = gtk_alert_dialog_choose_finish(GTK_ALERT_DIALOG(self), response_id, NULL); + if(result == 0) // I don't know why this won't just accept a normal gtk_window_close... gtk_application_remove_window(gtk_window_get_application(GTK_WINDOW(window)), GTK_WINDOW(window)); - } - gtk_window_close(GTK_WINDOW(self)); } bool gui_close(GtkWindow* window) { if(actions_since_save) { - GtkWidget* close_yn_dialog = gtk_message_dialog_new( - window, - GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL, - GTK_MESSAGE_QUESTION, - GTK_BUTTONS_YES_NO, - "You made changes since you last saved, do you really want to close the application?" - ); - g_signal_connect(G_OBJECT(close_yn_dialog), "response", G_CALLBACK(close_response), NULL); - gtk_widget_set_visible(close_yn_dialog, true); + GtkAlertDialog* close_yn_dialog = gtk_alert_dialog_new("You made changes since you last saved, do you really want to close the application?"); + gtk_alert_dialog_set_buttons(close_yn_dialog, (const char*[]){"Yes", "No", NULL}); + gtk_alert_dialog_set_cancel_button(close_yn_dialog, 1); + gtk_alert_dialog_choose(close_yn_dialog, GTK_WINDOW(window), NULL, close_yn_response, NULL); return true; } return false; @@ -1569,11 +1560,45 @@ void gui_toggle_interface_nums_action(GSimpleAction* action, GVariant* value, gp gtk_widget_queue_draw(main_drawing_area); } +void packet_list_item_text_factory_bind(GtkSignalListItemFactory* self, GObject* object, gpointer user_data) { + gtk_list_item_set_child(GTK_LIST_ITEM(object), gtk_label_new(g_object_get_data(gtk_list_item_get_item(GTK_LIST_ITEM(object)), user_data))); +} + + +GtkListItemFactory* packet_list_string_data_factory_new(char* key) { + GtkListItemFactory* new_factory = gtk_signal_list_item_factory_new(); + g_signal_connect(G_OBJECT(new_factory), "bind", G_CALLBACK(packet_list_item_text_factory_bind), key); + return new_factory; +} + +void packet_list_item_int_factory_bind(GtkSignalListItemFactory* self, GObject* object, gpointer user_data) { + char text[16] = ""; + sprintf(text, "%d", *(int*)g_object_get_data(gtk_list_item_get_item(GTK_LIST_ITEM(object)), user_data)); + gtk_list_item_set_child(GTK_LIST_ITEM(object), gtk_label_new(text)); +} + +GtkListItemFactory* packet_list_int_data_factory_new(char* key) { + GtkListItemFactory* new_factory = gtk_signal_list_item_factory_new(); + g_signal_connect(G_OBJECT(new_factory), "bind", G_CALLBACK(packet_list_item_int_factory_bind), key); + return new_factory; +} + /* * ====== GTK INITIALIZATION ====== */ extern int sim_flag; void activate_main_window(GtkApplication* app, gpointer user_data) { + // Initialize filter list + file_filter_list = g_list_store_new(GTK_TYPE_FILE_FILTER); + GtkFileFilter* json_filter = gtk_file_filter_new(); + gtk_file_filter_add_suffix(json_filter, "json"); + gtk_file_filter_set_name(json_filter, "JSON"); + g_list_store_append(file_filter_list, json_filter); + GtkFileFilter* all_filter = gtk_file_filter_new(); + gtk_file_filter_add_pattern(all_filter, "*"); + gtk_file_filter_set_name(all_filter, "ALL"); + g_list_store_append(file_filter_list, all_filter); + window = gtk_application_window_new(app); // Needed for gui_packet GtkCssProvider* css_prov = gtk_css_provider_new(); @@ -1779,36 +1804,27 @@ void activate_main_window(GtkApplication* app, gpointer user_data) { gtk_stack_add_titled(GTK_STACK(sidebar_stack), connection_view_scroll, NULL, "Connections"); // === Packet details - // Create a list - packet_list = gtk_list_store_new(PACKET_N_COL, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT, G_TYPE_POINTER, G_TYPE_STRING, G_TYPE_STRING); // Create a tree view packet_tree_scroll = gtk_scrolled_window_new(); - packet_tree = gtk_tree_view_new_with_model(GTK_TREE_MODEL(packet_list)); + //packet_tree = gtk_tree_view_new_with_model(GTK_TREE_MODEL(packet_list)); + packet_list_store = g_list_store_new(G_TYPE_OBJECT); + + GtkSingleSelection* packet_list_selection = gtk_single_selection_new(G_LIST_MODEL(packet_list_store)); + + packet_tree = gtk_column_view_new(GTK_SELECTION_MODEL(packet_list_selection)); + gtk_column_view_set_single_click_activate(GTK_COLUMN_VIEW(packet_tree), true); gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(packet_tree_scroll), packet_tree); - GtkCellRenderer* text_render = gtk_cell_renderer_text_new(); - // Status - GtkTreeViewColumn* status_col = gtk_tree_view_column_new_with_attributes("status", text_render, "text", PACKET_COL_STATUS, NULL); - gtk_tree_view_append_column(GTK_TREE_VIEW(packet_tree), status_col); - // Sending device column - GtkTreeViewColumn* dev_col1 = gtk_tree_view_column_new_with_attributes("from device", text_render, "text", PACKET_COL_DEV1, NULL); - gtk_tree_view_append_column(GTK_TREE_VIEW(packet_tree), dev_col1); - // Receiving device column - GtkTreeViewColumn* dev_col2 = gtk_tree_view_column_new_with_attributes("to device", text_render, "text", PACKET_COL_DEV2, NULL); - gtk_tree_view_append_column(GTK_TREE_VIEW(packet_tree), dev_col2); - // Type - GtkTreeViewColumn* type_col = gtk_tree_view_column_new_with_attributes("protocol", text_render, "text", PACKET_COL_TYPE, NULL); - gtk_tree_view_append_column(GTK_TREE_VIEW(packet_tree), type_col); - // Size - GtkTreeViewColumn* p_size_col = gtk_tree_view_column_new_with_attributes("size", text_render, "text", PACKET_COL_SIZE, NULL); - gtk_tree_view_append_column(GTK_TREE_VIEW(packet_tree), p_size_col); - // Make a packet window appear when clicked - g_signal_connect(G_OBJECT(packet_tree), "row-activated", G_CALLBACK(packet_selected), NULL); + g_signal_connect(G_OBJECT(packet_tree), "activate", G_CALLBACK(packet_selected), NULL); - // Activate on single click - gtk_tree_view_set_activate_on_single_click(GTK_TREE_VIEW(packet_tree), true); - // Allow only one packet to be activated - GtkTreeSelection* packet_selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(packet_tree)); - gtk_tree_selection_set_mode(packet_selection, GTK_SELECTION_MULTIPLE); + gtk_column_view_append_column(GTK_COLUMN_VIEW(packet_tree), gtk_column_view_column_new("Status", packet_list_string_data_factory_new("Status"))); + gtk_column_view_append_column(GTK_COLUMN_VIEW(packet_tree), gtk_column_view_column_new("Device1", packet_list_string_data_factory_new("Device1"))); + gtk_column_view_append_column(GTK_COLUMN_VIEW(packet_tree), gtk_column_view_column_new("Device2", packet_list_string_data_factory_new("Device2"))); + + gtk_column_view_append_column(GTK_COLUMN_VIEW(packet_tree), gtk_column_view_column_new("Protocols", packet_list_string_data_factory_new("Type"))); + + gtk_column_view_append_column(GTK_COLUMN_VIEW(packet_tree), gtk_column_view_column_new("Size", packet_list_int_data_factory_new("Size"))); + + // Set the data with g_object_set_data gtk_paned_set_end_child(GTK_PANED(right_pane), packet_tree_scroll); diff --git a/gui_device.c b/gui_device.c index 32676be..f9b3799 100644 --- a/gui_device.c +++ b/gui_device.c @@ -42,21 +42,23 @@ void cmd_entry_changed(GtkEditable* self, gpointer user_data) { gtk_entry_buffer_set_text(buffer, "", 0); } -void interface_selection_updated(GtkComboBox* self, gpointer user_data) { +void interface_selection_updated(GtkDropDown* self, void* pspec, gpointer user_data) { struct device* parent_device = (struct device*)user_data; assert(parent_device); // Get the slot index - int* index = g_object_get_data(G_OBJECT(self), "index"); + int* index = g_object_get_data(G_OBJECT(self), "int_index"); if(!index) { fprintf(stderr, "Could not find the index for interface_selection_updated\n"); return; } - const char* new_template = gtk_combo_box_get_active_id(self); - if(!strcmp(new_template, "none")) { + int template_index = gtk_drop_down_get_selected(GTK_DROP_DOWN(self)); + if(template_index == 0) { + printf("DELETE INTERFACE\n"); // delete if the user selects none delete_interface(&parent_device->interfaces[*index]); } else { - new_interface(parent_device, *index, gtk_combo_box_get_active_id(self) + 1); + template_index--; + new_interface(parent_device, *index, &interface_templates[template_index]); } actions_since_save++; // Redraw the drawing area @@ -106,7 +108,11 @@ bool entry_key_pressed(GtkEventControllerKey* self, } void help_clicked(GtkButton* self, gpointer user_data) { - gtk_show_uri(NULL, (char*)user_data, GDK_CURRENT_TIME); + GFile* help_file = g_file_new_for_uri((char*)user_data); + GtkFileLauncher* help_file_launcher = gtk_file_launcher_new(help_file); + gtk_file_launcher_launch(help_file_launcher, NULL, NULL, NULL, NULL); + g_object_unref(help_file_launcher); + g_object_unref(help_file); } // Show the gui for the device dev @@ -174,32 +180,34 @@ void show_device_window(struct device* dev) { gtk_label_set_markup(GTK_LABEL(slot_label), slot_index); gtk_box_append(GTK_BOX(interface_box), slot_label); // Add the dropdown - GtkWidget* slot_selection = gtk_combo_box_text_new(); - gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(slot_selection), "none", "None"); - // Add the index to the dropdown so we can set things later - int* index = malloc_or_abort(sizeof(int)); - *index = i; - g_object_set_data_full(G_OBJECT(slot_selection), "index", index, free); + char** interface_template_list = malloc_or_abort(interface_template_n + 2); + interface_template_list[0] = "None"; // Fill up the dropdown for(int j = 0; j < interface_template_n; j++) { // Prepend a _ to the name of the device so that a template can not take the id none by mistake - char* template_id = malloc_or_abort(strlen(interface_templates[j].name) + 2); - sprintf(template_id, "_%s", interface_templates[j].name); - gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(slot_selection), template_id, interface_templates[j].name); - free(template_id); + interface_template_list[j+1] = (char*)interface_templates[j].name; } + interface_template_list[interface_template_n+1] = NULL; + + GtkWidget* slot_selection = gtk_drop_down_new_from_strings((const char* const *)interface_template_list); + free(interface_template_list); + + // Add the index to the dropdown so we can set things later + int* index = malloc_or_abort(sizeof(int)); + *index = i; + g_object_set_data_full(G_OBJECT(slot_selection), "int_index", index, free); + // Set the interface that is in the slot if(dev->interfaces[i].template) { // The slot is used - char* template_id = malloc_or_abort(strlen(dev->interfaces[i].template->name) + 2); - sprintf(template_id, "_%s", dev->interfaces[i].template->name); - gtk_combo_box_set_active_id(GTK_COMBO_BOX(slot_selection), template_id); - free(template_id); + int template_index = (dev->interfaces[i].template - interface_templates) / sizeof(struct interface_template) + 1; + gtk_drop_down_set_selected(GTK_DROP_DOWN(slot_selection), template_index); + } else { // The slot is unused - gtk_combo_box_set_active_id(GTK_COMBO_BOX(slot_selection), "none"); + gtk_drop_down_set_selected(GTK_DROP_DOWN(slot_selection), 0); } - g_signal_connect(G_OBJECT(slot_selection), "changed", G_CALLBACK(interface_selection_updated), dev); + g_signal_connect(G_OBJECT(slot_selection), "notify::selected", G_CALLBACK(interface_selection_updated), dev); gtk_box_append(GTK_BOX(interface_box), slot_selection); // Add the interface to the flow box gtk_flow_box_append(GTK_FLOW_BOX(interfaces_box), interface_box); diff --git a/interface.c b/interface.c index a836025..79510c9 100644 --- a/interface.c +++ b/interface.c @@ -41,16 +41,10 @@ int delete_interface(struct interface* del_interface) { return 0; } -int new_interface(struct device* parent_device, int slot_index, const char* template_name) { - if(!parent_device) return -1; - if(slot_index > parent_device->template->slots - 1) { - fprintf(stderr, "Slot %d is not available in device %s with %d slots", slot_index, parent_device->name, parent_device->template->slots); - return -1; - } - +int new_interface_from_template_name(struct device* parent_device, int slot_index, const char* template_name) { struct interface_template* cur_template = interface_templates; bool template_found = false; - for(int i = 0; i < interface_template_n; i++, cur_template += sizeof(struct interface_template)) { + for(int i = 0; i < interface_template_n; i++, cur_template = &interface_templates[i]) { if(strcmp(cur_template->name, template_name) == 0) { template_found = true; break; @@ -61,6 +55,22 @@ int new_interface(struct device* parent_device, int slot_index, const char* temp fprintf(stderr, "Template %s was not found", template_name); return -1; } + + return new_interface(parent_device, slot_index, cur_template); +} + +int new_interface(struct device* parent_device, int slot_index, struct interface_template* cur_template) { + if(!parent_device) return -1; + if(slot_index > parent_device->template->slots - 1) { + fprintf(stderr, "Slot %d is not available in device %s with %d slots", slot_index, parent_device->name, parent_device->template->slots); + return -1; + } + + if(!cur_template) { + fprintf(stderr, "Invalid interface template\n"); + return -1; + } + // Remove any old interfaces still there delete_interface(&parent_device->interfaces[slot_index]); diff --git a/interface.h b/interface.h index 4c60264..5a1c137 100644 --- a/interface.h +++ b/interface.h @@ -14,7 +14,8 @@ #ifndef NETSIM_INTERFACE #define NETSIM_INTERFACE #include "shared.h" -int new_interface(struct device* parent_device, int slot_index, const char* template_name); +int new_interface(struct device* parent_device, int slot_index, struct interface_template* cur_template); +int new_interface_from_template_name(struct device* parent_device, int slot_index, const char* template_name); int delete_interface(struct interface* del_interface); int interface_send_frame(struct interface* send_interface, const char* frame, int frame_len, const char* frame_type); int interface_recv_data(struct interface* recv_interface, const char* data, int data_length, const char* data_type); |