+struct gopt_str_multi {
+ struct gopt gopt;
+ GtkWidget *checks[PARSE_MAX_VP];
+};
+
+static GtkWidget *gopt_widgets[FIO_MAX_OPTS];
+
+struct gopt_frame_widget {
+ GtkWidget *vbox[2];
+ unsigned int nr;
+};
+static struct gopt_frame_widget gopt_g_widgets[__FIO_OPT_G_NR];
+
+static GNode *gopt_dep_tree;
+
+static GtkWidget *gopt_get_group_frame(GtkWidget *box, unsigned int groupmask)
+{
+ unsigned int mask, group;
+ struct opt_group *og;
+ GtkWidget *frame, *hbox;
+ struct gopt_frame_widget *gfw;
+
+ if (!groupmask)
+ return 0;
+
+ mask = groupmask;
+ og = opt_group_cat_from_mask(&mask);
+ if (!og)
+ return NULL;
+
+ group = ffz(~groupmask);
+ gfw = &gopt_g_widgets[group];
+ if (!gfw->vbox[0]) {
+ frame = gtk_frame_new(og->name);
+ gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 3);
+ hbox = gtk_hbox_new(FALSE, 0);
+ gtk_container_add(GTK_CONTAINER(frame), hbox);
+ gfw->vbox[0] = gtk_vbox_new(TRUE, 5);
+ gfw->vbox[1] = gtk_vbox_new(TRUE, 5);
+ gtk_box_pack_start(GTK_BOX(hbox), gfw->vbox[0], TRUE, TRUE, 5);
+ gtk_box_pack_start(GTK_BOX(hbox), gfw->vbox[1], TRUE, TRUE, 5);
+ }
+
+ hbox = gtk_hbox_new(FALSE, 3);
+ gtk_box_pack_start(GTK_BOX(gfw->vbox[gfw->nr++ & 1]), hbox, FALSE, FALSE, 5);
+ return hbox;
+}
+
+/*
+ * Mark children as invisible, if needed.
+ */
+static void gopt_set_children_visible(struct fio_option *parent,
+ gboolean visible)
+{
+ GNode *child, *node;
+
+ if (parent->hide_on_set)
+ visible = !visible;
+
+ node = g_node_find(gopt_dep_tree, G_IN_ORDER, G_TRAVERSE_ALL, parent);
+ child = g_node_first_child(node);
+ while (child) {
+ struct fio_option *o = child->data;
+ struct gopt *g = o->gui_data;
+
+ /*
+ * Recurse into child, if it also has children
+ */
+ if (g_node_n_children(child))
+ gopt_set_children_visible(o, visible);
+
+ if (gopt_widgets[g->opt_index])
+ gtk_widget_set_sensitive(gopt_widgets[g->opt_index], visible);
+
+ child = g_node_next_sibling(child);
+ }
+}
+
+static void gopt_str_changed(GtkEntry *entry, gpointer data)
+{
+ struct gopt_str *s = (struct gopt_str *) data;
+ struct fio_option *o = &fio_options[s->gopt.opt_index];
+ const gchar *text;
+ int set;
+
+ text = gtk_entry_get_text(GTK_ENTRY(s->entry));
+ set = strcmp(text, "") != 0;
+ gopt_set_children_visible(o, set);
+}
+
+static void gopt_mark_index(struct gopt *gopt, unsigned int idx)
+{
+ assert(!gopt_widgets[idx]);
+ gopt->opt_index = idx;
+ gopt_widgets[idx] = gopt->box;
+}
+
+static void gopt_str_destroy(GtkWidget *w, gpointer data)
+{
+ struct gopt_str *s = (struct gopt_str *) data;
+
+ free(s);
+ gtk_widget_destroy(w);
+}
+
+static struct gopt *gopt_new_str_store(struct fio_option *o, const char *text,
+ unsigned int idx)