+ unsigned int *ip = td_var(gjv->o, o, o->off1);
+ struct value_pair *vp;
+ gboolean set;
+ guint val = 0;
+ int i;
+
+ i = 0;
+ vp = &o->posval[0];
+ while (vp->ival) {
+ if (!m->checks[i])
+ break;
+ set = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(m->checks[i]));
+ if (set) {
+ if (vp->or)
+ val |= vp->oval;
+ else
+ val = vp->oval;
+ }
+ i++;
+ vp++;
+ }
+
+ if (o->off1)
+ *ip = val;
+}
+
+static void gopt_handle_range_changed(struct gopt_job_view *gjv,
+ struct gopt_range *r,
+ struct fio_option *o)
+{
+ unsigned int *ip[4] = { td_var(gjv->o, o, o->off1),
+ td_var(gjv->o, o, o->off2),
+ td_var(gjv->o, o, o->off3),
+ td_var(gjv->o, o, o->off4) };
+ gint val;
+ int i;
+
+ for (i = 0; i < GOPT_RANGE_SPIN; i++) {
+ val = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(r->spins[i]));
+ *ip[i] = val;
+ }
+}
+
+static void gopt_handle_str_val_changed(struct gopt_job_view *gjv,
+ struct gopt_str_val *s,
+ struct fio_option *o)
+{
+ unsigned long long *ullp = td_var(gjv->o, o, o->off1);
+ GtkAdjustment *adj;
+ gint index;
+
+ if (!ullp)
+ return;
+
+ /*
+ * Numerical value
+ */
+ adj = gtk_spin_button_get_adjustment(GTK_SPIN_BUTTON(s->spin));
+ *ullp = gtk_adjustment_get_value(adj);
+
+ /*
+ * Multiplier
+ */
+ index = gtk_combo_box_get_active(GTK_COMBO_BOX(s->combo));
+ while (index--)
+ *ullp *= 1024ULL;
+}
+
+static void gopt_handle_str_changed(struct gopt_job_view *gjv,
+ struct gopt_str *s, struct fio_option *o)
+{
+ char **p = td_var(gjv->o, o, o->off1);
+
+ if (*p)
+ free(*p);
+
+ *p = strdup(gtk_entry_get_text(GTK_ENTRY(s->entry)));
+}
+
+static void gopt_handle_bool_changed(struct gopt_job_view *gjv,
+ struct gopt_bool *b, struct fio_option *o)
+{
+ unsigned int *ip = td_var(gjv->o, o, o->off1);
+ gboolean set;
+
+ set = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(b->check));
+ *ip = set;
+}
+
+static void gopt_handle_int_changed(struct gopt_job_view *gjv,
+ struct gopt_int *i, struct fio_option *o)
+{
+ unsigned int *ip = td_var(gjv->o, o, o->off1);
+ GtkAdjustment *adj;
+ guint val;
+
+ adj = gtk_spin_button_get_adjustment(GTK_SPIN_BUTTON(i->spin));
+ val = gtk_adjustment_get_value(adj);
+ *ip = val;
+}
+
+static void gopt_handle_combo_str_changed(struct gopt_job_view *gjv,
+ struct gopt_combo *c,
+ struct fio_option *o)
+{
+ char **p = td_var(gjv->o, o, o->off1);
+
+ if (*p)
+ free(*p);
+
+ *p = strdup(gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(c->combo)));
+}
+
+static void gopt_handle_combo_int_changed(struct gopt_job_view *gjv,
+ struct gopt_combo *c,
+ struct fio_option *o)
+{
+ unsigned int *ip = td_var(gjv->o, o, o->off1);
+ gint index;
+
+ index = gtk_combo_box_get_active(GTK_COMBO_BOX(c->combo));
+ *ip = o->posval[index].oval;
+}
+
+static void gopt_handle_changed(struct gopt *gopt)
+{
+ struct fio_option *o = &fio_options[gopt->opt_index];
+ struct gopt_job_view *gjv = gopt->gjv;
+
+ switch (gopt->opt_type) {
+ case GOPT_COMBO_INT: {
+ struct gopt_combo *c;
+
+ c = container_of(gopt, struct gopt_combo, gopt);
+ gopt_handle_combo_int_changed(gjv, c, o);
+ break;
+ }
+ case GOPT_COMBO_STR: {
+ struct gopt_combo *c;
+
+ c = container_of(gopt, struct gopt_combo, gopt);
+ gopt_handle_combo_str_changed(gjv, c, o);
+ break;
+ }
+ case GOPT_INT: {
+ struct gopt_int *i;
+
+ i = container_of(gopt, struct gopt_int, gopt);
+ gopt_handle_int_changed(gjv, i, o);
+ break;
+ }
+ case GOPT_BOOL: {
+ struct gopt_bool *b;
+
+ b = container_of(gopt, struct gopt_bool, gopt);
+ gopt_handle_bool_changed(gjv, b, o);
+ break;
+ }
+ case GOPT_STR: {
+ struct gopt_str *s;
+
+ s = container_of(gopt, struct gopt_str, gopt);
+ gopt_handle_str_changed(gjv, s, o);
+ break;
+ }
+ case GOPT_STR_VAL: {
+ struct gopt_str_val *s;
+
+ s = container_of(gopt, struct gopt_str_val, gopt);
+ gopt_handle_str_val_changed(gjv, s, o);
+ break;
+ }
+ case GOPT_RANGE: {
+ struct gopt_range *r;
+
+ r = container_of(gopt, struct gopt_range, gopt);
+ gopt_handle_range_changed(gjv, r, o);
+ break;
+ }
+ case GOPT_STR_MULTI: {
+ struct gopt_str_multi *m;
+
+ m = container_of(gopt, struct gopt_str_multi, gopt);
+ gopt_handle_str_multi_changed(gjv, m, o);
+ break;
+ }
+ default:
+ log_err("gfio: bad option type: %d\n", gopt->opt_type);
+ break;
+ }
+}
+
+static void gopt_report_update_status(struct gopt_job_view *gjv)
+{
+ struct gfio_client *gc = gjv->client;
+ char tmp[80];
+
+ sprintf(tmp, "\nCompleted with error: %d\n", gc->update_job_status);
+ gfio_report_info(gc->ge->ui, "Update job", tmp);
+}
+
+static int gopt_handle_changed_options(struct gopt_job_view *gjv)
+{
+ struct gfio_client *gc = gjv->client;
+ struct flist_head *entry;
+ uint64_t waitid = 0;
+ struct gopt *gopt;
+ int ret;
+
+ flist_for_each(entry, &gjv->changed_list) {
+ gopt = flist_entry(entry, struct gopt, changed_list);
+ gopt_handle_changed(gopt);
+ }
+
+ gc->update_job_status = 0;
+ gc->update_job_done = 0;
+
+ ret = fio_client_update_options(gc->client, gjv->o, &waitid);
+ if (ret)
+ goto done;
+
+ ret = fio_client_wait_for_reply(gc->client, waitid);
+ if (ret)
+ goto done;
+
+ assert(gc->update_job_done);
+ if (gc->update_job_status)
+ goto done;
+
+ while (!flist_empty(&gjv->changed_list)) {
+ gopt = flist_entry(gjv->changed_list.next, struct gopt, changed_list);
+ flist_del_init(&gopt->changed_list);
+ }
+
+done:
+ gopt_dialog_update_apply_button(gjv);
+ return ret;
+}
+
+static gint gopt_dialog_cancel(gint response)
+{
+ switch (response) {
+ case GTK_RESPONSE_NONE:
+ case GTK_RESPONSE_REJECT:
+ case GTK_RESPONSE_DELETE_EVENT:
+ case GTK_RESPONSE_CANCEL:
+ case GTK_RESPONSE_NO:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static gint gopt_dialog_done(gint response)
+{
+ switch (response) {
+ case GTK_RESPONSE_ACCEPT:
+ case GTK_RESPONSE_OK:
+ case GTK_RESPONSE_YES:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static void gopt_handle_option_dialog(struct gopt_job_view *gjv)
+{
+ gint response;
+
+ do {
+ response = gtk_dialog_run(GTK_DIALOG(gjv->dialog));
+
+ if (gopt_dialog_cancel(response) ||
+ gopt_dialog_done(response))
+ break;
+
+ /*
+ * Apply
+ */
+ gopt_handle_changed_options(gjv);
+ gopt_report_update_status(gjv);
+ } while (1);
+
+ if (gopt_dialog_cancel(response))
+ return;
+
+ gopt_handle_changed_options(gjv);
+}
+
+static void gopt_job_changed(GtkComboBox *box, gpointer data)
+{
+ struct gopt_job_view *gjv = (struct gopt_job_view *) data;
+ struct gfio_client_options *gco = NULL;
+ struct gfio_client *gc = gjv->client;
+ struct flist_head *entry;
+ gchar *job;
+
+ /*
+ * The switch act should be sensitized appropriately, so that we
+ * never get here with modified options.
+ */
+ if (!flist_empty(&gjv->changed_list)) {
+ gfio_report_info(gc->ge->ui, "Internal Error", "Modified options on job switch.\nThat should not be possible!\n");
+ return;
+ }
+
+ job = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(gjv->job_combo));
+ flist_for_each(entry, &gc->o_list) {
+ const char *name;
+
+ gco = flist_entry(entry, struct gfio_client_options, list);
+ name = gco->o.name;
+ if (!name || !strlen(name))
+ name = "Default job";
+
+ if (!strcmp(name, job))
+ break;
+
+ gco = NULL;
+ }
+
+ if (!gco) {
+ gfio_report_info(gc->ge->ui, "Internal Error", "Could not find job description.\nThat should not be possible!\n");
+ return;
+ }
+
+ gjv->in_job_switch = 1;
+ gopt_set_options(gjv, &gco->o);
+ gjv->in_job_switch = 0;
+}
+
+void gopt_get_options_window(GtkWidget *window, struct gfio_client *gc)
+{
+ GtkWidget *dialog, *notebook, *vbox, *topvbox, *combo;
+ struct gfio_client_options *gco;
+ struct flist_head *entry;
+ struct gopt_job_view *gjv;