+static void view_log_destroy(GtkWidget *w, gpointer data)
+{
+ struct gui *ui = (struct gui *) data;
+
+ g_object_ref(G_OBJECT(ui->log_tree));
+ gtk_container_remove(GTK_CONTAINER(w), ui->log_tree);
+ gtk_widget_destroy(w);
+ ui->log_view = NULL;
+}
+
+void gfio_view_log(struct gui *ui)
+{
+ GtkWidget *win, *scroll, *vbox, *box;
+
+ if (ui->log_view)
+ return;
+
+ ui->log_view = win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_title(GTK_WINDOW(win), "Log");
+ gtk_window_set_default_size(GTK_WINDOW(win), 700, 500);
+
+ scroll = gtk_scrolled_window_new(NULL, NULL);
+
+ gtk_container_set_border_width(GTK_CONTAINER(scroll), 5);
+
+ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+
+ box = gtk_hbox_new(TRUE, 0);
+ gtk_box_pack_start(GTK_BOX(box), ui->log_tree, TRUE, TRUE, 0);
+ g_signal_connect(box, "destroy", G_CALLBACK(view_log_destroy), ui);
+ gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroll), box);
+
+ vbox = gtk_vbox_new(TRUE, 5);
+ gtk_box_pack_start(GTK_BOX(vbox), scroll, TRUE, TRUE, 0);
+
+ gtk_container_add(GTK_CONTAINER(win), vbox);
+ gtk_widget_show_all(win);
+}
+
+static void view_log(GtkWidget *w, gpointer data)
+{
+ struct gui *ui = (struct gui *) data;
+
+ gfio_view_log(ui);
+}
+
+static void connect_job_entry(GtkWidget *w, gpointer data)
+{
+ struct gui *ui = (struct gui *) data;
+ struct gui_entry *ge;
+
+ ge = get_ge_from_cur_tab(ui);
+ if (ge)
+ connect_clicked(w, ge);
+}
+
+static void send_job_entry(GtkWidget *w, gpointer data)
+{
+ struct gui *ui = (struct gui *) data;
+ struct gui_entry *ge;
+
+ ge = get_ge_from_cur_tab(ui);
+ if (ge)
+ send_clicked(w, ge);
+}
+
+static void edit_job_entry(GtkWidget *w, gpointer data)
+{
+ struct gui *ui = (struct gui *) data;
+ struct gui_entry *ge;
+
+ ge = get_ge_from_cur_tab(ui);
+ if (ge && ge->client)
+ gopt_get_options_window(ui->window, ge->client);
+}
+
+static void start_job_entry(GtkWidget *w, gpointer data)
+{
+ struct gui *ui = (struct gui *) data;
+ struct gui_entry *ge;
+
+ ge = get_ge_from_cur_tab(ui);
+ if (ge)
+ start_job_clicked(w, ge);
+}
+
+static void view_results(GtkWidget *w, gpointer data)
+{
+ struct gui *ui = (struct gui *) data;
+ struct gfio_client *gc;
+ struct gui_entry *ge;
+
+ ge = get_ge_from_cur_tab(ui);
+ if (!ge)
+ return;
+
+ if (ge->results_window)
+ return;
+
+ gc = ge->client;
+ if (gc && gc->nr_results)
+ gfio_display_end_results(gc);
+}
+
+static void __update_graph_settings(struct gfio_graphs *g)
+{
+ line_graph_set_data_count_limit(g->iops_graph, gfio_graph_limit);
+ graph_set_font(g->iops_graph, gfio_graph_font);
+ line_graph_set_data_count_limit(g->bandwidth_graph, gfio_graph_limit);
+ graph_set_font(g->bandwidth_graph, gfio_graph_font);
+}
+
+static void ge_update_settings_fn(gpointer key, gpointer value, gpointer data)
+{
+ struct gui_entry *ge = (struct gui_entry *) value;
+ GdkEvent *ev;
+
+ __update_graph_settings(&ge->graphs);
+
+ ev = gdk_event_new(GDK_EXPOSE);
+ g_signal_emit_by_name(G_OBJECT(ge->graphs.drawing_area), GFIO_DRAW_EVENT, GTK_WIDGET(ge->graphs.drawing_area), ev, &ge->graphs);
+ gdk_event_free(ev);
+}
+
+static void update_graph_limits(void)
+{
+ struct gui *ui = &main_ui;
+ GdkEvent *ev;
+
+ __update_graph_settings(&ui->graphs);
+
+ ev = gdk_event_new(GDK_EXPOSE);
+ g_signal_emit_by_name(G_OBJECT(ui->graphs.drawing_area), GFIO_DRAW_EVENT, GTK_WIDGET(ui->graphs.drawing_area), ev, &ui->graphs);
+ gdk_event_free(ev);
+
+ g_hash_table_foreach(ui->ge_hash, ge_update_settings_fn, NULL);
+}
+
+static void preferences(GtkWidget *w, gpointer data)
+{
+ GtkWidget *dialog, *frame, *box, **buttons, *vbox, *font;
+ GtkWidget *hbox, *spin, *entry, *spin_int;
+ struct gui *ui = (struct gui *) data;
+ int i;
+
+ dialog = gtk_dialog_new_with_buttons("Preferences",
+ GTK_WINDOW(ui->window),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
+ NULL);
+
+ frame = gtk_frame_new("Graphing");
+ vbox = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
+ gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
+ vbox = gtk_vbox_new(FALSE, 6);
+ gtk_container_add(GTK_CONTAINER(frame), vbox);
+
+ hbox = gtk_hbox_new(FALSE, 5);
+ gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 5);
+ entry = gtk_label_new("Font face to use for graph labels");
+ gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 5);
+
+ font = gtk_font_button_new_with_font(gfio_graph_font);
+ gtk_box_pack_start(GTK_BOX(hbox), font, FALSE, FALSE, 5);
+
+ box = gtk_vbox_new(FALSE, 6);
+ gtk_box_pack_start(GTK_BOX(vbox), box, FALSE, FALSE, 5);
+
+ hbox = gtk_hbox_new(FALSE, 5);
+ gtk_box_pack_start(GTK_BOX(box), hbox, TRUE, TRUE, 5);
+ entry = gtk_label_new("Maximum number of data points in graph (seconds)");
+ gtk_box_pack_start(GTK_BOX(hbox), entry, FALSE, FALSE, 5);
+
+ spin = create_spinbutton(hbox, 10, 1000000, gfio_graph_limit);
+
+ box = gtk_vbox_new(FALSE, 6);
+ gtk_box_pack_start(GTK_BOX(vbox), box, FALSE, FALSE, 5);
+
+ hbox = gtk_hbox_new(FALSE, 5);
+ gtk_box_pack_start(GTK_BOX(box), hbox, TRUE, TRUE, 5);
+ entry = gtk_label_new("Client ETA request interval (msec)");
+ gtk_box_pack_start(GTK_BOX(hbox), entry, FALSE, FALSE, 5);
+
+ spin_int = create_spinbutton(hbox, 100, 100000, gfio_client_ops.eta_msec);
+ frame = gtk_frame_new("Debug logging");
+ vbox = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
+ gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
+ vbox = gtk_vbox_new(FALSE, 6);
+ gtk_container_add(GTK_CONTAINER(frame), vbox);
+
+ box = gtk_hbox_new(FALSE, 6);
+ gtk_container_add(GTK_CONTAINER(vbox), box);
+
+ buttons = malloc(sizeof(GtkWidget *) * FD_DEBUG_MAX);
+
+ for (i = 0; i < FD_DEBUG_MAX; i++) {
+ if (i == 7) {
+ box = gtk_hbox_new(FALSE, 6);
+ gtk_container_add(GTK_CONTAINER(vbox), box);
+ }
+
+
+ buttons[i] = gtk_check_button_new_with_label(debug_levels[i].name);
+ gtk_widget_set_tooltip_text(buttons[i], debug_levels[i].help);
+ gtk_box_pack_start(GTK_BOX(box), buttons[i], FALSE, FALSE, 6);
+ }
+
+ gtk_widget_show_all(dialog);
+
+ if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT) {
+ gtk_widget_destroy(dialog);
+ return;
+ }
+
+ for (i = 0; i < FD_DEBUG_MAX; i++) {
+ int set;
+
+ set = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(buttons[i]));
+ if (set)
+ fio_debug |= (1UL << i);
+ }
+
+ gfio_graph_font = strdup(gtk_font_button_get_font_name(GTK_FONT_BUTTON(font)));
+ gfio_graph_limit = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spin));
+ update_graph_limits();
+ gfio_client_ops.eta_msec = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spin_int));
+
+ gtk_widget_destroy(dialog);
+}
+