X-Git-Url: https://git.kernel.dk/?p=fio.git;a=blobdiff_plain;f=goptions.c;h=d7178eb68aad07a4e27473af9caed4a6e68a3fc8;hp=36477f0897bf73fc1008b312c3bc8b7188471175;hb=ec0218ff0e7ad3a480a13db33b0e0cd668ef6222;hpb=9af4a24408ea7d4cea084a4fe214b81145cc36ac diff --git a/goptions.c b/goptions.c index 36477f08..d7178eb6 100644 --- a/goptions.c +++ b/goptions.c @@ -37,12 +37,80 @@ struct gopt_str { GtkWidget *entry; }; +#define GOPT_RANGE_SPIN 4 + struct gopt_range { struct gopt gopt; - GtkWidget *spins[4]; + GtkWidget *spins[GOPT_RANGE_SPIN]; +}; + +struct gopt_widget { + struct flist_head list; + GtkWidget *widget; }; -static struct gopt *gopt_new_str_store(struct fio_option *o) +static struct flist_head gopt_list[FIO_MAX_OPTS]; + +static void __gopt_set_children_visible(unsigned int idx, gboolean visible) +{ + struct flist_head *entry; + struct gopt_widget *gw; + + flist_for_each(entry, &gopt_list[idx]) { + gw = flist_entry(entry, struct gopt_widget, list); + gtk_widget_set_sensitive(gw->widget, visible); + } +} + +/* + * Mark children as invisible, if needed. + */ +static void gopt_set_children_visible(struct fio_option *parent, gboolean visible) +{ + struct fio_option *o; + int i; + + /* + * This isn't super fast, but it should not be an issue. If it is, we + * can speed it up by caching the lookup at least. Or we can do it + * once, at init time. + */ + for (i = 0; fio_options[i].name; i++) { + o = &fio_options[i]; + if (!o->parent || !o->hide) + continue; + + if (strcmp(parent->name, o->parent)) + continue; + + __gopt_set_children_visible(i, visible); + } +} + +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) +{ + struct gopt_widget *gw; + + gopt->opt_index = idx; + + gw = malloc(sizeof(*gw)); + gw->widget = gopt->box; + flist_add_tail(&gw->list, &gopt_list[idx]); +} + +static struct gopt *gopt_new_str_store(struct fio_option *o, const char *text, unsigned int idx) { struct gopt_str *s; GtkWidget *label; @@ -54,7 +122,11 @@ static struct gopt *gopt_new_str_store(struct fio_option *o) gtk_box_pack_start(GTK_BOX(s->gopt.box), label, FALSE, FALSE, 0); s->entry = gtk_entry_new(); + gopt_mark_index(&s->gopt, idx); + if (text) + gtk_entry_set_text(GTK_ENTRY(s->entry), text); gtk_entry_set_editable(GTK_ENTRY(s->entry), 1); + g_signal_connect(GTK_OBJECT(s->entry), "changed", G_CALLBACK(gopt_str_changed), s); if (o->def) gtk_entry_set_text(GTK_ENTRY(s->entry), o->def); @@ -63,21 +135,41 @@ static struct gopt *gopt_new_str_store(struct fio_option *o) return &s->gopt; } -static struct gopt *gopt_new_combo(struct fio_option *o) +static void gopt_combo_changed(GtkComboBox *box, gpointer data) { - struct gopt_combo *combo; - struct value_pair *vp; + struct gopt_combo *c = (struct gopt_combo *) data; + struct fio_option *o = &fio_options[c->gopt.opt_index]; + + printf("combo %s changed\n", o->name); +} + +static struct gopt_combo *__gopt_new_combo(struct fio_option *o, unsigned int idx) +{ + struct gopt_combo *c; GtkWidget *label; - int i, active = 0; - combo = malloc(sizeof(*combo)); + c = malloc(sizeof(*c)); - combo->gopt.box = gtk_hbox_new(FALSE, 3); + c->gopt.box = gtk_hbox_new(FALSE, 3); label = gtk_label_new(o->name); - gtk_box_pack_start(GTK_BOX(combo->gopt.box), label, FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(c->gopt.box), label, FALSE, FALSE, 0); + + c->combo = gtk_combo_box_new_text(); + gopt_mark_index(&c->gopt, idx); + gtk_box_pack_start(GTK_BOX(c->gopt.box), c->combo, FALSE, FALSE, 0); + + g_signal_connect(GTK_OBJECT(c->combo), "changed", G_CALLBACK(gopt_combo_changed), c); + + return c; +} + +static struct gopt *gopt_new_combo_str(struct fio_option *o, const char *text, unsigned int idx) +{ + struct gopt_combo *combo; + struct value_pair *vp; + int i, active = 0; - combo->combo = gtk_combo_box_new_text(); - gtk_box_pack_start(GTK_BOX(combo->gopt.box), combo->combo, FALSE, FALSE, 0); + combo = __gopt_new_combo(o, idx); i = 0; vp = &o->posval[0]; @@ -85,6 +177,30 @@ static struct gopt *gopt_new_combo(struct fio_option *o) gtk_combo_box_append_text(GTK_COMBO_BOX(combo->combo), vp->ival); if (o->def && !strcmp(vp->ival, o->def)) active = i; + if (text && !strcmp(vp->ival, text)) + active = i; + vp++; + i++; + } + + gtk_combo_box_set_active(GTK_COMBO_BOX(combo->combo), active); + return &combo->gopt; +} + +static struct gopt *gopt_new_combo_int(struct fio_option *o, unsigned int *ip, unsigned int idx) +{ + struct gopt_combo *combo; + struct value_pair *vp; + int i, active = 0; + + combo = __gopt_new_combo(o, idx); + + i = 0; + vp = &o->posval[0]; + while (vp->ival) { + gtk_combo_box_append_text(GTK_COMBO_BOX(combo->combo), vp->ival); + if (ip && vp->oval == *ip) + active = i; vp++; i++; } @@ -93,10 +209,20 @@ static struct gopt *gopt_new_combo(struct fio_option *o) return &combo->gopt; } -static struct gopt *gopt_new_int(struct fio_option *o) +static void gopt_int_changed(GtkSpinButton *spin, gpointer data) { + struct gopt_int *i = (struct gopt_int *) data; + struct fio_option *o = &fio_options[i->gopt.opt_index]; + + printf("int %s changed\n", o->name); +} + +static struct gopt_int *__gopt_new_int(struct fio_option *o, unsigned long long *p, + unsigned int idx) +{ + unsigned long long defval; struct gopt_int *i; - gint maxval, defval; + guint maxval, interval; GtkWidget *label; i = malloc(sizeof(*i)); @@ -106,25 +232,68 @@ static struct gopt *gopt_new_int(struct fio_option *o) maxval = o->maxval; if (!maxval) - maxval = INT_MAX; + maxval = UINT_MAX; defval = 0; - if (o->def) { + if (p) + defval = *p; + else if (o->def) { long long val; check_str_bytes(o->def, &val, NULL); defval = val; } - i->spin = gtk_spin_button_new_with_range(o->minval, maxval, 1.0); + interval = 1.0; + if (o->interval) + interval = o->interval; + + i->spin = gtk_spin_button_new_with_range(o->minval, maxval, interval); + gopt_mark_index(&i->gopt, idx); gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(i->spin), GTK_UPDATE_IF_VALID); gtk_spin_button_set_value(GTK_SPIN_BUTTON(i->spin), defval); gtk_box_pack_start(GTK_BOX(i->gopt.box), i->spin, FALSE, FALSE, 0); + + g_signal_connect(G_OBJECT(i->spin), "value-changed", G_CALLBACK(gopt_int_changed), i); + + return i; +} + +static struct gopt *gopt_new_int(struct fio_option *o, unsigned int *ip, unsigned int idx) +{ + unsigned long long ullp; + struct gopt_int *i; + + if (ip) { + ullp = *ip; + i = __gopt_new_int(o, &ullp, idx); + } else + i = __gopt_new_int(o, NULL, idx); + return &i->gopt; } -static struct gopt *gopt_new_bool(struct fio_option *o) +static struct gopt *gopt_new_ullong(struct fio_option *o, unsigned long long *p, + unsigned int idx) +{ + struct gopt_int *i; + + i = __gopt_new_int(o, p, idx); + return &i->gopt; +} + +static void gopt_bool_toggled(GtkToggleButton *button, gpointer data) +{ + struct gopt_bool *b = (struct gopt_bool *) data; + struct fio_option *o = &fio_options[b->gopt.opt_index]; + gboolean set; + + set = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(b->check)); + gopt_set_children_visible(o, set); +} + +static struct gopt *gopt_new_bool(struct fio_option *o, unsigned int *val, unsigned int idx) { struct gopt_bool *b; GtkWidget *label; @@ -136,24 +305,71 @@ static struct gopt *gopt_new_bool(struct fio_option *o) gtk_box_pack_start(GTK_BOX(b->gopt.box), label, FALSE, FALSE, 0); b->check = gtk_check_button_new(); - if (o->def && !strcmp(o->def, "1")) + gopt_mark_index(&b->gopt, idx); + if (val) + defstate = *val; + else if (o->def && !strcmp(o->def, "1")) defstate = 1; gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b->check), defstate); + g_signal_connect(G_OBJECT(b->check), "toggled", G_CALLBACK(gopt_bool_toggled), b); gtk_box_pack_start(GTK_BOX(b->gopt.box), b->check, FALSE, FALSE, 0); return &b->gopt; } -static struct gopt *gopt_new_int_range(struct fio_option *o) +/* + * These are paired 0/1 and 2/3. 0/2 are min values, 1/3 are max values. + * If the max is made smaller than min, adjust min down. + * If the min is made larger than max, adjust the max. + */ +static void range_value_changed(GtkSpinButton *spin, gpointer data) +{ + struct gopt_range *r = (struct gopt_range *) data; + int changed = -1, i; + gint val, mval; + + for (i = 0; i < GOPT_RANGE_SPIN; i++) { + if (GTK_SPIN_BUTTON(r->spins[i]) == spin) { + changed = i; + break; + } + } + + assert(changed != -1); + + /* + * Min changed + */ + if (changed == 0 || changed == 2) { + GtkWidget *mspin = r->spins[changed + 1]; + + val = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(r->spins[changed])); + mval = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(mspin)); + if (val > mval) + gtk_spin_button_set_value(GTK_SPIN_BUTTON(mspin), val); + } else { + GtkWidget *mspin = r->spins[changed - 1]; + + val = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(r->spins[changed])); + mval = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(mspin)); + if (val < mval) + gtk_spin_button_set_value(GTK_SPIN_BUTTON(mspin), val); + } +} + +static struct gopt *gopt_new_int_range(struct fio_option *o, unsigned int **ip, + unsigned int idx) { struct gopt_range *r; gint maxval, defval; GtkWidget *label; + guint interval; int i; r = malloc(sizeof(*r)); r->gopt.box = gtk_hbox_new(FALSE, 3); + gopt_mark_index(&r->gopt, idx); label = gtk_label_new(o->name); gtk_box_pack_start(GTK_BOX(r->gopt.box), label, FALSE, FALSE, 0); @@ -169,46 +385,97 @@ static struct gopt *gopt_new_int_range(struct fio_option *o) defval = val; } - for (i = 0; i < 4; i++) { - r->spins[i] = gtk_spin_button_new_with_range(o->minval, maxval, 1.0); + interval = 1.0; + if (o->interval) + interval = o->interval; + + for (i = 0; i < GOPT_RANGE_SPIN; i++) { + r->spins[i] = gtk_spin_button_new_with_range(o->minval, maxval, interval); gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(r->spins[i]), GTK_UPDATE_IF_VALID); - gtk_spin_button_set_value(GTK_SPIN_BUTTON(r->spins[i]), defval); + if (ip) + gtk_spin_button_set_value(GTK_SPIN_BUTTON(r->spins[i]), *ip[i]); + else + gtk_spin_button_set_value(GTK_SPIN_BUTTON(r->spins[i]), defval); gtk_box_pack_start(GTK_BOX(r->gopt.box), r->spins[i], FALSE, FALSE, 0); + g_signal_connect(G_OBJECT(r->spins[i]), "value-changed", G_CALLBACK(range_value_changed), r); } return &r->gopt; } static void gopt_add_option(GtkWidget *hbox, struct fio_option *o, - unsigned int opt_index) + unsigned int opt_index, struct thread_options *to) { struct gopt *go = NULL; switch (o->type) { - case FIO_OPT_STR_STORE: - go = gopt_new_str_store(o); - break; case FIO_OPT_STR_VAL: - case FIO_OPT_STR_VAL_TIME: - case FIO_OPT_INT: - go = gopt_new_int(o); + case FIO_OPT_STR_VAL_TIME: { + unsigned long long *ullp = NULL; + + if (o->off1) + ullp = td_var(to, o->off1); + + go = gopt_new_ullong(o, ullp, opt_index); break; + } + case FIO_OPT_INT: { + unsigned int *ip = NULL; + + if (o->off1) + ip = td_var(to, o->off1); + + go = gopt_new_int(o, ip, opt_index); + break; + } case FIO_OPT_STR_SET: - case FIO_OPT_BOOL: - go = gopt_new_bool(o); + case FIO_OPT_BOOL: { + unsigned int *ip = NULL; + + if (o->off1) + ip = td_var(to, o->off1); + + go = gopt_new_bool(o, ip, opt_index); break; - case FIO_OPT_STR: + } + case FIO_OPT_STR: { + unsigned int *ip = NULL; + + if (o->off1) + ip = td_var(to, o->off1); + + go = gopt_new_combo_int(o, ip, opt_index); + break; + } + case FIO_OPT_STR_STORE: { + char *text = NULL; + + if (o->off1) { + char **p = td_var(to, o->off1); + text = *p; + } + if (!o->posval[0].ival) { - go = gopt_new_str_store(o); + go = gopt_new_str_store(o, text, opt_index); break; } + + go = gopt_new_combo_str(o, text, opt_index); + break; + } case FIO_OPT_STR_MULTI: - go = gopt_new_combo(o); + go = gopt_new_combo_str(o, NULL, opt_index); break; - case FIO_OPT_RANGE: - go = gopt_new_int_range(o); + case FIO_OPT_RANGE: { + unsigned int *ip[4] = { td_var(to, o->off1), + td_var(to, o->off2), + td_var(to, o->off3), + td_var(to, o->off4) }; + + go = gopt_new_int_range(o, ip, opt_index); break; + } /* still need to handle this one */ case FIO_OPT_FLOAT_LIST: break; @@ -224,12 +491,11 @@ static void gopt_add_option(GtkWidget *hbox, struct fio_option *o, gtk_widget_set_tooltip_text(go->box, o->help); gtk_box_pack_start(GTK_BOX(hbox), go->box, FALSE, FALSE, 5); - go->opt_index = opt_index; go->opt_type = o->type; } } -static void gopt_add_options(GtkWidget **vboxes) +static void gopt_add_options(GtkWidget **vboxes, struct thread_options *to) { GtkWidget *hbox = NULL; int i; @@ -244,7 +510,7 @@ static void gopt_add_options(GtkWidget **vboxes) hbox = gtk_hbox_new(FALSE, 3); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 5); - gopt_add_option(hbox, &fio_options[i], i); + gopt_add_option(hbox, o, i, to); } } } @@ -269,8 +535,12 @@ static GtkWidget *gopt_add_group_tab(GtkWidget *notebook, struct opt_group *og) static void gopt_add_group_tabs(GtkWidget *notebook, GtkWidget **vbox) { struct opt_group *og; - unsigned int i = 0; + unsigned int i; + + for (i = 0; i < FIO_MAX_OPTS; i++) + INIT_FLIST_HEAD(&gopt_list[i]); + i = 0; do { unsigned int mask = (1U << i); @@ -282,7 +552,7 @@ static void gopt_add_group_tabs(GtkWidget *notebook, GtkWidget **vbox) } while (1); } -void gopt_get_options_window(GtkWidget *window) +void gopt_get_options_window(GtkWidget *window, struct thread_options *o) { GtkWidget *dialog, *notebook; GtkWidget *vboxes[__FIO_OPT_G_NR]; @@ -301,7 +571,7 @@ void gopt_get_options_window(GtkWidget *window) gopt_add_group_tabs(notebook, vboxes); - gopt_add_options(vboxes); + gopt_add_options(vboxes, o); gtk_widget_show_all(dialog);