From 85dd01e7d7fa9989bf55002bc416c4d8118fdf5f Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Mon, 12 Mar 2012 14:33:16 +0100 Subject: [PATCH] gfio: improve Job menu Still need to figure out how to make certain items in the job menu sensitive/insensitive, apparently I can't lookup the item widgets (only the menu widget). Signed-off-by: Jens Axboe --- client.c | 14 +++- client.h | 4 + gfio.c | 245 ++++++++++++++++++++++++++++++++++++++++++++++--------- 3 files changed, 222 insertions(+), 41 deletions(-) diff --git a/client.c b/client.c index 5545a8a9..f2c157ae 100644 --- a/client.c +++ b/client.c @@ -27,6 +27,7 @@ static void handle_gs(struct fio_client *client, struct fio_net_cmd *cmd); static void handle_probe(struct fio_client *client, struct fio_net_cmd *cmd); static void handle_text(struct fio_client *client, struct fio_net_cmd *cmd); static void handle_stop(struct fio_client *client, struct fio_net_cmd *cmd); +static void handle_start(struct fio_client *client, struct fio_net_cmd *cmd); struct client_ops fio_client_ops = { .text_op = handle_text, @@ -34,6 +35,7 @@ struct client_ops fio_client_ops = { .thread_status = handle_ts, .group_stats = handle_gs, .stop = handle_stop, + .start = handle_start, .eta = display_thread_status, .probe = handle_probe, .eta_msec = FIO_CLIENT_DEF_ETA_MSEC, @@ -907,7 +909,7 @@ static void handle_start(struct fio_client *client, struct fio_net_cmd *cmd) struct cmd_start_pdu *pdu = (struct cmd_start_pdu *) cmd->payload; client->state = Client_started; - client->jobs = le32_to_cpu(pdu->jobs); + client->jobs = pdu->jobs; } static void handle_stop(struct fio_client *client, struct fio_net_cmd *cmd) @@ -1004,12 +1006,18 @@ int fio_handle_client(struct fio_client *client) break; case FIO_NET_CMD_SERVER_START: client->state = Client_running; + if (ops->job_start) + ops->job_start(client, cmd); free(cmd); break; - case FIO_NET_CMD_START: - handle_start(client, cmd); + case FIO_NET_CMD_START: { + struct cmd_start_pdu *pdu = (struct cmd_start_pdu *) cmd->payload; + + pdu->jobs = le32_to_cpu(pdu->jobs); + ops->start(client, cmd); free(cmd); break; + } case FIO_NET_CMD_STOP: { struct cmd_end_pdu *pdu = (struct cmd_end_pdu *) cmd->payload; diff --git a/client.h b/client.h index 9668afa8..ea7ea6f1 100644 --- a/client.h +++ b/client.h @@ -70,6 +70,8 @@ typedef void (*client_quit_op)(struct fio_client *); typedef void (*client_add_job_op)(struct fio_client *, struct fio_net_cmd *); typedef void (*client_timed_out)(struct fio_client *); typedef void (*client_stop_op)(struct fio_client *, struct fio_net_cmd *); +typedef void (*client_start_op)(struct fio_client *, struct fio_net_cmd *); +typedef void (*client_job_start_op)(struct fio_client *, struct fio_net_cmd *); struct client_ops { client_text_op_func text_op; @@ -83,6 +85,8 @@ struct client_ops { client_add_job_op add_job; client_timed_out timed_out; client_stop_op stop; + client_start_op start; + client_job_start_op job_start; unsigned int eta_msec; int stay_connected; }; diff --git a/gfio.c b/gfio.c index 40ef34c9..88d67588 100644 --- a/gfio.c +++ b/gfio.c @@ -131,6 +131,15 @@ struct gui { struct flist_head list; } main_ui; +enum { + GE_STATE_NEW = 1, + GE_STATE_CONNECTED, + GE_STATE_JOB_SENT, + GE_STATE_JOB_STARTED, + GE_STATE_JOB_RUNNING, + GE_STATE_JOB_DONE, +}; + /* * Notebook entry */ @@ -160,7 +169,7 @@ struct gui_entry { struct eta_widget eta; GtkWidget *page_label; gint page_num; - int connected; + unsigned int state; struct gfio_client *client; int nr_job_files; @@ -377,22 +386,6 @@ static GtkWidget *create_spinbutton(GtkWidget *hbox, double min, double max, dou return button; } -static void gfio_set_connected(struct gui_entry *ge, int connected) -{ - if (connected) { - gtk_widget_set_sensitive(ge->button[SEND_BUTTON], 1); - ge->connected = 1; - gtk_button_set_label(GTK_BUTTON(ge->button[CONNECT_BUTTON]), "Disconnect"); - gtk_widget_set_sensitive(ge->button[CONNECT_BUTTON], 1); - } else { - ge->connected = 0; - gtk_button_set_label(GTK_BUTTON(ge->button[CONNECT_BUTTON]), "Connect"); - gtk_widget_set_sensitive(ge->button[SEND_BUTTON], 0); - gtk_widget_set_sensitive(ge->button[START_JOB_BUTTON], 0); - gtk_widget_set_sensitive(ge->button[CONNECT_BUTTON], 1); - } -} - static void label_set_int_value(GtkWidget *entry, unsigned int val) { char tmp[80]; @@ -427,6 +420,101 @@ static void show_info_dialog(struct gui *ui, const char *title, gtk_widget_destroy(dialog); } +/* + * Update sensitivity of job buttons and job menu items, based on the + * state of the client. + */ +static void update_button_states(struct gui *ui, struct gui_entry *ge) +{ + unsigned int connect_state, send_state, start_state, edit_state; + const char *connect_str = NULL; + GtkWidget *w; + + switch (ge->state) { + default: { + char tmp[80]; + + sprintf(tmp, "Bad client state: %u\n", ge->state); + show_info_dialog(ui, "Error", tmp); + /* fall through to new state */ + } + + case GE_STATE_NEW: + connect_state = 1; + edit_state = 0; + connect_str = "Connect"; + send_state = 0; + start_state = 0; + break; + case GE_STATE_CONNECTED: + connect_state = 1; + edit_state = 0; + connect_str = "Disconnect"; + send_state = 1; + start_state = 0; + break; + case GE_STATE_JOB_SENT: + connect_state = 1; + edit_state = 0; + connect_str = "Disconnect"; + send_state = 0; + start_state = 1; + break; + case GE_STATE_JOB_STARTED: + connect_state = 1; + edit_state = 1; + connect_str = "Disconnect"; + send_state = 0; + start_state = 1; + break; + case GE_STATE_JOB_RUNNING: + connect_state = 1; + edit_state = 0; + connect_str = "Disconnect"; + send_state = 0; + start_state = 0; + break; + case GE_STATE_JOB_DONE: + connect_state = 1; + edit_state = 0; + connect_str = "Connect"; + send_state = 0; + start_state = 0; + break; + } + + gtk_widget_set_sensitive(ge->button[CONNECT_BUTTON], connect_state); + gtk_widget_set_sensitive(ge->button[SEND_BUTTON], send_state); + gtk_widget_set_sensitive(ge->button[START_JOB_BUTTON], start_state); + gtk_button_set_label(GTK_BUTTON(ge->button[CONNECT_BUTTON]), connect_str); + + /* + * So the below doesn't work at all, how to set those menu items + * invisibible... + */ + w = gtk_ui_manager_get_widget(ui->uimanager, "/MainMenu/JobMenu/Connect"); + if (w) + gtk_widget_set_sensitive(w, connect_state); + + w = gtk_ui_manager_get_widget(ui->uimanager, "/MainMenu/JobMenu/Edit Job"); + if (w) + gtk_widget_set_sensitive(w, edit_state); + + w = gtk_ui_manager_get_widget(ui->uimanager, "/MainMenu/JobMenu/Send Job"); + if (w) + gtk_widget_set_sensitive(w, send_state); + + w = gtk_ui_manager_get_widget(ui->uimanager, "/MainMenu/JobMenu/Start Job"); + if (w) + gtk_widget_set_sensitive(w, start_state); +} + +static void gfio_set_state(struct gui_entry *ge, unsigned int state) +{ + ge->state = state; + update_button_states(ge->ui, ge); +} + #define ALIGN_LEFT 1 #define ALIGN_RIGHT 2 #define INVISIBLE 4 @@ -1441,7 +1529,7 @@ static void gfio_probe_op(struct fio_client *client, struct fio_net_cmd *cmd) sprintf(buf, "%u.%u.%u", probe->fio_major, probe->fio_minor, probe->fio_patch); gtk_label_set_text(GTK_LABEL(ge->probe.fio_ver), buf); - gfio_set_connected(ge, 1); + gfio_set_state(ge, GE_STATE_CONNECTED); gdk_threads_leave(); } @@ -1475,7 +1563,7 @@ static void gfio_quit_op(struct fio_client *client) struct gfio_client *gc = client->client_data; gdk_threads_enter(); - gfio_set_connected(gc->ge, 0); + gfio_set_state(gc->ge, GE_STATE_NEW); gdk_threads_leave(); } @@ -1508,6 +1596,8 @@ static void gfio_add_job_op(struct fio_client *client, struct fio_net_cmd *cmd) gc->job_added++; + gfio_set_state(ge, GE_STATE_JOB_SENT); + gdk_threads_leave(); } @@ -1518,7 +1608,7 @@ static void gfio_client_timed_out(struct fio_client *client) gdk_threads_enter(); - gfio_set_connected(gc->ge, 0); + gfio_set_state(gc->ge, GE_STATE_NEW); clear_ge_ui_info(gc->ge); sprintf(buf, "Client %s: timeout talking to server.\n", client->hostname); @@ -1533,7 +1623,7 @@ static void gfio_client_stop(struct fio_client *client, struct fio_net_cmd *cmd) gdk_threads_enter(); - gfio_set_connected(gc->ge, 0); + gfio_set_state(gc->ge, GE_STATE_JOB_DONE); if (gc->err_entry) entry_set_int_value(gc->err_entry, client->error); @@ -1541,6 +1631,24 @@ static void gfio_client_stop(struct fio_client *client, struct fio_net_cmd *cmd) gdk_threads_leave(); } +static void gfio_client_start(struct fio_client *client, struct fio_net_cmd *cmd) +{ + struct gfio_client *gc = client->client_data; + + gdk_threads_enter(); + gfio_set_state(gc->ge, GE_STATE_JOB_STARTED); + gdk_threads_leave(); +} + +static void gfio_client_job_start(struct fio_client *client, struct fio_net_cmd *cmd) +{ + struct gfio_client *gc = client->client_data; + + gdk_threads_enter(); + gfio_set_state(gc->ge, GE_STATE_JOB_RUNNING); + gdk_threads_leave(); +} + struct client_ops gfio_client_ops = { .text_op = gfio_text_op, .disk_util = gfio_disk_util_op, @@ -1553,6 +1661,8 @@ struct client_ops gfio_client_ops = { .add_job = gfio_add_job_op, .timed_out = gfio_client_timed_out, .stop = gfio_client_stop, + .start = gfio_client_start, + .job_start = gfio_client_job_start, .eta_msec = FIO_CLIENT_DEF_ETA_MSEC, .stay_connected = 1, }; @@ -1639,7 +1749,7 @@ static void connect_clicked(GtkWidget *widget, gpointer data) struct gui_entry *ge = data; struct gfio_client *gc = ge->client; - if (!ge->connected) { + if (ge->state == GE_STATE_NEW) { int ret; if (!ge->nr_job_files) @@ -1653,8 +1763,7 @@ static void connect_clicked(GtkWidget *widget, gpointer data) if (!ret) { if (!ge->ui->handler_running) pthread_create(&ge->ui->t, NULL, job_thread, ge->ui); - gtk_widget_set_sensitive(ge->button[CONNECT_BUTTON], 0); - gtk_widget_set_sensitive(ge->button[SEND_BUTTON], 1); + gfio_set_state(ge, GE_STATE_CONNECTED); } else { GError *error; @@ -1664,7 +1773,7 @@ static void connect_clicked(GtkWidget *widget, gpointer data) } } else { fio_client_terminate(gc->client); - gfio_set_connected(ge, 0); + gfio_set_state(ge, GE_STATE_NEW); clear_ge_ui_info(ge); } } @@ -1682,9 +1791,6 @@ static void send_clicked(GtkWidget *widget, gpointer data) gtk_widget_set_sensitive(ge->button[START_JOB_BUTTON], 1); } - - gtk_widget_set_sensitive(ge->button[SEND_BUTTON], 0); - gtk_widget_set_sensitive(ge->button[START_JOB_BUTTON], 1); } static GtkWidget *add_button(GtkWidget *buttonbox, @@ -1904,6 +2010,7 @@ static struct gui_entry *alloc_new_gui_entry(struct gui *ui) ge = malloc(sizeof(*ge)); memset(ge, 0, sizeof(*ge)); + ge->state = GE_STATE_NEW; INIT_FLIST_HEAD(&ge->list); flist_add_tail(&ge->list, &ui->list); ge->ui = ui; @@ -1919,7 +2026,7 @@ static void ge_destroy(GtkWidget *w, gpointer data) struct gfio_client *gc = ge->client; if (gc && gc->client) { - if (ge->connected) + if (ge->state >= GE_STATE_CONNECTED) fio_client_terminate(gc->client); fio_put_client(gc->client); @@ -1975,18 +2082,31 @@ static struct gui_entry *get_ge_from_page(unsigned int cur_page) return NULL; } -static void file_close(GtkWidget *w, gpointer data) +static struct gui_entry *get_ge_from_cur_tab(struct gui *ui) { - struct gui *ui = (struct gui *) data; gint cur_page; /* - * Can't close the main tab + * 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) { - struct gui_entry *ge = get_ge_from_page(cur_page); + if (cur_page) + return get_ge_from_page(cur_page); + + 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; } @@ -2139,10 +2259,41 @@ static void view_log(GtkWidget *w, gpointer data) gtk_widget_show_all(win); } -static void edit_options(GtkWidget *w, gpointer data) +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) { } +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 __update_graph_limits(struct gfio_graphs *g) { line_graph_set_data_count_limit(g->iops_graph, gfio_graph_limit); @@ -2304,7 +2455,10 @@ static GtkActionEntry menu_items[] = { { "SaveFile", GTK_STOCK_SAVE, NULL, "S", NULL, G_CALLBACK(file_save) }, { "Preferences", GTK_STOCK_PREFERENCES, NULL, "p", NULL, G_CALLBACK(preferences) }, { "ViewLog", NULL, "Log", "l", NULL, G_CALLBACK(view_log) }, - { "EditOptions", NULL, "Edit Options", "E", NULL, G_CALLBACK(edit_options) }, + { "ConnectJob", NULL, "Connect", "E", NULL, G_CALLBACK(connect_job_entry) }, + { "EditJob", NULL, "Edit job", "E", NULL, G_CALLBACK(edit_job_entry) }, + { "SendJob", NULL, "Send job", "X", NULL, G_CALLBACK(send_job_entry) }, + { "StartJob", NULL, "Start job", "L", NULL, G_CALLBACK(start_job_entry) }, { "Quit", GTK_STOCK_QUIT, NULL, "Q", NULL, G_CALLBACK(quit_clicked) }, { "About", GTK_STOCK_ABOUT, NULL, NULL, NULL, G_CALLBACK(about_dialog) }, }; @@ -2325,7 +2479,12 @@ static const gchar *ui_string = " \ \ \ \ - \ + \ + \ + \ + \ + \ + \ \ \ \ @@ -2583,8 +2742,18 @@ static gboolean notebook_switch_page(GtkNotebook *notebook, GtkWidget *widget, { struct gui *ui = (struct gui *) data; + struct gui_entry *ge; + + if (!page) { + set_job_menu_visible(ui, 0); + return TRUE; + } + + set_job_menu_visible(ui, 1); + ge = get_ge_from_page(page); + if (ge) + update_button_states(ui, ge); - set_job_menu_visible(ui, page); return TRUE; } -- 2.25.1