+ ge->host = strdup(gtk_entry_get_text(GTK_ENTRY(cw.hentry)));
+ ge->port = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(pentry));
+
+ typeentry = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(cw.combo));
+ if (!typeentry || !strncmp(typeentry, "IPv4", 4))
+ ge->type = Fio_client_ipv4;
+ else if (!strncmp(typeentry, "IPv6", 4))
+ ge->type = Fio_client_ipv6;
+ else
+ ge->type = Fio_client_socket;
+ g_free(typeentry);
+
+ ge->server_start = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cw.button));
+
+ gtk_widget_destroy(dialog);
+ return 0;
+}
+
+static void gfio_set_client(struct gfio_client *gc, struct fio_client *client)
+{
+ gc->client = fio_get_client(client);
+ client->client_data = gc;
+}
+
+static void gfio_client_added(struct gui_entry *ge, struct fio_client *client)
+{
+ struct gfio_client_options *gco;
+ struct gfio_client *gc;
+
+ gc = calloc(1, sizeof(*gc));
+ INIT_FLIST_HEAD(&gc->o_list);
+ gc->ge = ge;
+ ge->client = gc;
+ gfio_set_client(gc, client);
+
+ /*
+ * Just add a default set of options, need to consider how best
+ * to handle this
+ */
+ gco = calloc(1, sizeof(*gco));
+ INIT_FLIST_HEAD(&gco->list);
+ options_default_fill(&gco->o);
+ flist_add_tail(&gco->list, &gc->o_list);
+ gc->o_list_nr++;
+}
+
+static void gfio_clear_graph_data(struct gfio_graphs *g)
+{
+ graph_clear_values(g->iops_graph);
+ graph_clear_values(g->bandwidth_graph);
+}
+
+static void connect_clicked(GtkWidget *widget, gpointer data)
+{
+ struct gui_entry *ge = data;
+ struct gfio_client *gc = ge->client;
+
+ if (ge->state == GE_STATE_NEW) {
+ int ret;
+
+ if (!ge->job_file)
+ file_open(widget, ge->ui);
+ if (!ge->job_file)
+ return;
+
+ gc = ge->client;
+
+ if (!gc->client) {
+ struct fio_client *client;
+
+ if (get_connection_details(ge)) {
+ gfio_report_error(ge, "Failed to get connection details\n");
+ return;
+ }
+
+ client = fio_client_add_explicit(&gfio_client_ops, ge->host, ge->type, ge->port);
+ if (!client) {
+ gfio_report_error(ge, "Failed to add client %s\n", ge->host);
+ free(ge->host);
+ ge->host = NULL;
+ return;
+ }
+ gfio_set_client(gc, client);
+ }
+
+ gtk_progress_bar_set_text(GTK_PROGRESS_BAR(ge->thread_status_pb), "No jobs running");
+ gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(ge->thread_status_pb), 0.0);
+ ret = fio_client_connect(gc->client);
+ if (!ret) {
+ if (!ge->ui->handler_running)
+ pthread_create(&ge->ui->t, NULL, job_thread, ge->ui);
+ gfio_set_state(ge, GE_STATE_CONNECTED);
+ gfio_clear_graph_data(&ge->graphs);
+ } else {
+ gfio_report_error(ge, "Failed to connect to %s: %s\n", ge->client->client->hostname, strerror(-ret));
+ }
+ } else {
+ fio_client_terminate(gc->client);
+ gfio_set_state(ge, GE_STATE_NEW);
+ clear_ge_ui_info(ge);
+ }
+}
+
+static void send_clicked(GtkWidget *widget, gpointer data)
+{
+ struct gui_entry *ge = data;
+
+ if (send_job_file(ge))
+ gtk_widget_set_sensitive(ge->button[GFIO_BUTTON_START], 1);
+}
+
+static GtkWidget *new_client_page(struct gui_entry *ge);
+
+static struct gui_entry *alloc_new_gui_entry(struct gui *ui)
+{
+ struct gui_entry *ge;
+
+ ge = malloc(sizeof(*ge));
+ memset(ge, 0, sizeof(*ge));
+ ge->state = GE_STATE_NEW;
+ ge->ui = ui;
+ return ge;
+}
+
+static struct gui_entry *get_new_ge_with_tab(struct gui *ui, const char *name)
+{
+ struct gui_entry *ge;
+
+ ge = alloc_new_gui_entry(ui);
+
+ ge->vbox = new_client_page(ge);
+ g_signal_connect(ge->vbox, "destroy", G_CALLBACK(ge_widget_destroy), ge);
+
+ ge->page_label = gtk_label_new(name);
+ ge->page_num = gtk_notebook_append_page(GTK_NOTEBOOK(ui->notebook), ge->vbox, ge->page_label);
+
+ g_hash_table_insert(ui->ge_hash, &ge->page_num, ge);
+
+ gtk_widget_show_all(ui->window);
+ return ge;
+}
+
+static void file_new(GtkWidget *w, gpointer data)
+{
+ struct gui *ui = (struct gui *) data;
+ struct gui_entry *ge;
+
+ ge = get_new_ge_with_tab(ui, "Untitled");
+ gtk_notebook_set_current_page(GTK_NOTEBOOK(ui->notebook), ge->page_num);
+}
+
+/*
+ * Return the 'ge' corresponding to the tab. If the active tab is the
+ * main tab, open a new tab.
+ */
+static struct gui_entry *get_ge_from_page(struct gui *ui, gint cur_page,
+ int *created)
+{
+ if (!cur_page) {
+ if (created)
+ *created = 1;
+ return get_new_ge_with_tab(ui, "Untitled");
+ }
+
+ if (created)
+ *created = 0;
+
+ return g_hash_table_lookup(ui->ge_hash, &cur_page);
+}
+
+static struct gui_entry *get_ge_from_cur_tab(struct gui *ui)
+{
+ gint cur_page;
+
+ /*
+ * Main tab is tab 0, so any current page other than 0 holds
+ * a ge entry.
+ */
+ cur_page = gtk_notebook_get_current_page(GTK_NOTEBOOK(ui->notebook));
+ if (cur_page)
+ return get_ge_from_page(ui, cur_page, NULL);
+
+ return NULL;
+}
+
+static void file_close(GtkWidget *w, gpointer data)
+{
+ struct gui *ui = (struct gui *) data;
+ struct gui_entry *ge;
+
+ /*
+ * Can't close the main tab
+ */
+ ge = get_ge_from_cur_tab(ui);
+ if (ge) {
+ gtk_widget_destroy(ge->vbox);
+ return;
+ }
+
+ if (g_hash_table_size(ui->ge_hash)) {
+ gfio_report_info(ui, "Error", "The main page view cannot be closed\n");
+ return;
+ }
+
+ gfio_quit(ui);
+}
+
+static void file_add_recent(struct gui *ui, const gchar *uri)
+{
+ GtkRecentData grd;
+
+ memset(&grd, 0, sizeof(grd));
+ grd.display_name = strdup("gfio");
+ grd.description = strdup("Fio job file");
+ grd.mime_type = strdup(GFIO_MIME);
+ grd.app_name = strdup(g_get_application_name());
+ grd.app_exec = strdup("gfio %f/%u");
+
+ gtk_recent_manager_add_full(ui->recentmanager, uri, &grd);
+}
+
+static gchar *get_filename_from_uri(const gchar *uri)
+{
+ if (strncmp(uri, "file://", 7))
+ return strdup(uri);
+
+ return strdup(uri + 7);
+}
+
+static int do_file_open(struct gui_entry *ge, const gchar *uri)
+{
+ struct fio_client *client;
+
+ assert(!ge->job_file);
+
+ ge->job_file = get_filename_from_uri(uri);
+
+ client = fio_client_add_explicit(&gfio_client_ops, ge->host, ge->type, ge->port);
+ if (client) {
+ char *label = strdup(uri);
+
+ basename(label);
+ gtk_label_set_text(GTK_LABEL(ge->page_label), basename(label));
+ free(label);
+
+ gfio_client_added(ge, client);
+ file_add_recent(ge->ui, uri);
+ return 0;
+ }
+
+ gfio_report_error(ge, "Failed to add client %s\n", ge->host);
+ free(ge->host);
+ ge->host = NULL;
+ free(ge->job_file);
+ ge->job_file = NULL;
+ return 1;
+}
+
+static int do_file_open_with_tab(struct gui *ui, const gchar *uri)
+{
+ struct gui_entry *ge;
+ gint cur_page;
+ int ret, ge_is_new = 0;
+
+ /*
+ * Creates new tab if current tab is the main window, or the
+ * current tab already has a client.
+ */
+ cur_page = gtk_notebook_get_current_page(GTK_NOTEBOOK(ui->notebook));
+ ge = get_ge_from_page(ui, cur_page, &ge_is_new);
+ if (ge->client) {
+ ge = get_new_ge_with_tab(ui, "Untitled");
+ ge_is_new = 1;
+ }
+
+ gtk_notebook_set_current_page(GTK_NOTEBOOK(ui->notebook), ge->page_num);
+
+ if (get_connection_details(ge)) {
+ if (ge_is_new)
+ gtk_widget_destroy(ge->vbox);
+
+ return 1;
+ }
+
+ ret = do_file_open(ge, uri);