blob: b9da70274ac0739d2bcc055a7c45d24bf36563de [file] [log] [blame]
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001/*
2 * gfio - gui front end for fio - the flexible io tester
3 *
Jens Axboe3c3ed072012-03-27 09:12:39 +02004 * Copyright (C) 2012 Stephen M. Cameron <stephenmcameron@gmail.com>
Jens Axboec0187f32012-03-06 15:39:15 +01005 * Copyright (C) 2012 Jens Axboe <axboe@kernel.dk>
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01006 *
7 * The license below covers all files distributed with fio unless otherwise
8 * noted in the file itself.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 */
Stephen M. Cameron8232e282012-02-24 08:17:31 +010024#include <locale.h>
Stephen M. Cameron60f6b332012-02-24 08:17:32 +010025#include <malloc.h>
Jens Axboe6b79c802012-03-08 10:51:36 +010026#include <string.h>
Stephen M. Cameron8232e282012-02-24 08:17:31 +010027
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +010028#include <glib.h>
Jens Axboe2fd3bb02012-03-07 08:07:39 +010029#include <cairo.h>
Stephen M. Cameronff1f3282012-02-24 08:17:30 +010030#include <gtk/gtk.h>
31
Stephen M. Cameron8232e282012-02-24 08:17:31 +010032#include "fio.h"
Jens Axboe53e0e852012-03-15 19:38:01 +010033#include "gfio.h"
34#include "ghelpers.h"
Jens Axboe9af4a242012-03-16 10:13:49 +010035#include "goptions.h"
Jens Axboe41666582012-03-21 10:25:29 +010036#include "gerror.h"
Jens Axboe1252d8f2012-03-21 11:13:31 +010037#include "gclient.h"
Jens Axboe2fd3bb02012-03-07 08:07:39 +010038#include "graph.h"
Stephen M. Cameron8232e282012-02-24 08:17:31 +010039
Jens Axboe63a130b2012-03-06 20:08:59 +010040static int gfio_server_running;
Jens Axboe8577f4f2012-03-09 19:28:27 +010041static unsigned int gfio_graph_limit = 100;
Jens Axboe63a130b2012-03-06 20:08:59 +010042
Jens Axboe1252d8f2012-03-21 11:13:31 +010043GdkColor gfio_color_white;
Jens Axboe2a95f712012-04-16 11:48:45 +020044GdkColor gfio_color_lightyellow;
Jens Axboea1e79722012-03-23 10:52:25 +010045const char *gfio_graph_font = GRAPH_DEFAULT_FONT;
Jens Axboe3e47bd22012-02-29 13:45:02 +010046
Stephen M. Cameronf3074002012-02-24 08:17:30 +010047typedef void (*clickfunction)(GtkWidget *widget, gpointer data);
48
Jens Axboe3e47bd22012-02-29 13:45:02 +010049static void connect_clicked(GtkWidget *widget, gpointer data);
Stephen M. Cameronf3074002012-02-24 08:17:30 +010050static void start_job_clicked(GtkWidget *widget, gpointer data);
Jens Axboeb9d2f302012-03-08 20:36:28 +010051static void send_clicked(GtkWidget *widget, gpointer data);
Stephen M. Cameronf3074002012-02-24 08:17:30 +010052
53static struct button_spec {
54 const char *buttontext;
55 clickfunction f;
Jens Axboe014f4022012-03-15 14:03:01 +010056 const char *tooltiptext[2];
57 const int start_sensitive;
Stephen M. Cameronf3074002012-02-24 08:17:30 +010058} buttonspeclist[] = {
Jens Axboe53e0e852012-03-15 19:38:01 +010059 {
60 .buttontext = "Connect",
61 .f = connect_clicked,
62 .tooltiptext = { "Disconnect from host", "Connect to host" },
63 .start_sensitive = 1,
64 },
65 {
66 .buttontext = "Send",
67 .f = send_clicked,
68 .tooltiptext = { "Send job description to host", NULL },
69 .start_sensitive = 0,
70 },
71 {
72 .buttontext = "Start Job",
73 .f = start_job_clicked,
74 .tooltiptext = { "Start the current job on the server", NULL },
75 .start_sensitive = 0,
76 },
Jens Axboee0681f32012-03-06 12:14:42 +010077};
78
Jens Axboe8dfd6072012-03-22 22:10:37 +010079static void setup_iops_graph(struct gfio_graphs *gg)
Jens Axboe2fd3bb02012-03-07 08:07:39 +010080{
Jens Axboe2f99deb2012-03-09 14:37:29 +010081 struct graph *g;
82
83 g = graph_new(DRAWING_AREA_XDIM / 2.0, DRAWING_AREA_YDIM, gfio_graph_font);
Jens Axboed8fbeef2012-03-14 10:25:44 +010084 graph_title(g, "IOPS (IOs/sec)");
Jens Axboe2f99deb2012-03-09 14:37:29 +010085 graph_x_title(g, "Time (secs)");
Jens Axboe8dfd6072012-03-22 22:10:37 +010086 gg->read_iops = graph_add_label(g, "Read IOPS");
87 gg->write_iops = graph_add_label(g, "Write IOPS");
88 graph_set_color(g, gg->read_iops, 0.13, 0.54, 0.13);
89 graph_set_color(g, gg->write_iops, 1.0, 0.0, 0.0);
Jens Axboe8577f4f2012-03-09 19:28:27 +010090 line_graph_set_data_count_limit(g, gfio_graph_limit);
Jens Axboed8fbeef2012-03-14 10:25:44 +010091 graph_add_extra_space(g, 0.0, 0.0, 0.0, 0.0);
Jens Axboe01a947f2012-03-22 21:21:00 +010092 graph_set_graph_all_zeroes(g, 0);
Jens Axboe75450782012-03-23 08:15:46 +010093 gg->iops_graph = g;
Jens Axboe2fd3bb02012-03-07 08:07:39 +010094}
95
Jens Axboe8dfd6072012-03-22 22:10:37 +010096static void setup_bandwidth_graph(struct gfio_graphs *gg)
Jens Axboe2fd3bb02012-03-07 08:07:39 +010097{
Jens Axboe2f99deb2012-03-09 14:37:29 +010098 struct graph *g;
99
100 g = graph_new(DRAWING_AREA_XDIM / 2.0, DRAWING_AREA_YDIM, gfio_graph_font);
Jens Axboed8fbeef2012-03-14 10:25:44 +0100101 graph_title(g, "Bandwidth (bytes/sec)");
Jens Axboe2f99deb2012-03-09 14:37:29 +0100102 graph_x_title(g, "Time (secs)");
Jens Axboe8dfd6072012-03-22 22:10:37 +0100103 gg->read_bw = graph_add_label(g, "Read Bandwidth");
104 gg->write_bw = graph_add_label(g, "Write Bandwidth");
105 graph_set_color(g, gg->read_bw, 0.13, 0.54, 0.13);
106 graph_set_color(g, gg->write_bw, 1.0, 0.0, 0.0);
Jens Axboed8fbeef2012-03-14 10:25:44 +0100107 graph_set_base_offset(g, 1);
Jens Axboe2f99deb2012-03-09 14:37:29 +0100108 line_graph_set_data_count_limit(g, 100);
Jens Axboed8fbeef2012-03-14 10:25:44 +0100109 graph_add_extra_space(g, 0.0, 0.0, 0.0, 0.0);
Jens Axboe01a947f2012-03-22 21:21:00 +0100110 graph_set_graph_all_zeroes(g, 0);
Jens Axboe75450782012-03-23 08:15:46 +0100111 gg->bandwidth_graph = g;
Jens Axboe2fd3bb02012-03-07 08:07:39 +0100112}
113
Jens Axboe2f99deb2012-03-09 14:37:29 +0100114static void setup_graphs(struct gfio_graphs *g)
Jens Axboe8663ea62012-03-02 14:04:30 +0100115{
Jens Axboe8dfd6072012-03-22 22:10:37 +0100116 setup_iops_graph(g);
117 setup_bandwidth_graph(g);
Jens Axboe2f99deb2012-03-09 14:37:29 +0100118}
119
Jens Axboe1252d8f2012-03-21 11:13:31 +0100120void clear_ge_ui_info(struct gui_entry *ge)
Jens Axboe2f99deb2012-03-09 14:37:29 +0100121{
122 gtk_label_set_text(GTK_LABEL(ge->probe.hostname), "");
123 gtk_label_set_text(GTK_LABEL(ge->probe.os), "");
124 gtk_label_set_text(GTK_LABEL(ge->probe.arch), "");
125 gtk_label_set_text(GTK_LABEL(ge->probe.fio_ver), "");
Jens Axboe3863d1a2012-03-09 17:39:05 +0100126#if 0
127 /* should we empty it... */
Jens Axboe2f99deb2012-03-09 14:37:29 +0100128 gtk_entry_set_text(GTK_ENTRY(ge->eta.name), "");
Jens Axboe3863d1a2012-03-09 17:39:05 +0100129#endif
Jens Axboec80b74b2012-03-12 10:23:28 +0100130 multitext_update_entry(&ge->eta.iotype, 0, "");
Jens Axboe99d633a2012-03-15 15:55:04 +0100131 multitext_update_entry(&ge->eta.bs, 0, "");
Jens Axboec80b74b2012-03-12 10:23:28 +0100132 multitext_update_entry(&ge->eta.ioengine, 0, "");
133 multitext_update_entry(&ge->eta.iodepth, 0, "");
Jens Axboe2f99deb2012-03-09 14:37:29 +0100134 gtk_entry_set_text(GTK_ENTRY(ge->eta.jobs), "");
135 gtk_entry_set_text(GTK_ENTRY(ge->eta.files), "");
136 gtk_entry_set_text(GTK_ENTRY(ge->eta.read_bw), "");
137 gtk_entry_set_text(GTK_ENTRY(ge->eta.read_iops), "");
138 gtk_entry_set_text(GTK_ENTRY(ge->eta.write_bw), "");
139 gtk_entry_set_text(GTK_ENTRY(ge->eta.write_iops), "");
Jens Axboe8663ea62012-03-02 14:04:30 +0100140}
141
Jens Axboe781ccba2012-03-15 09:44:42 +0100142static void set_menu_entry_text(struct gui *ui, const char *path,
143 const char *text)
144{
145 GtkWidget *w;
146
147 w = gtk_ui_manager_get_widget(ui->uimanager, path);
148 if (w)
149 gtk_menu_item_set_label(GTK_MENU_ITEM(w), text);
150 else
151 fprintf(stderr, "gfio: can't find path %s\n", path);
152}
153
154
155static void set_menu_entry_visible(struct gui *ui, const char *path, int show)
156{
157 GtkWidget *w;
158
159 w = gtk_ui_manager_get_widget(ui->uimanager, path);
160 if (w)
161 gtk_widget_set_sensitive(w, show);
162 else
163 fprintf(stderr, "gfio: can't find path %s\n", path);
164}
165
166static void set_job_menu_visible(struct gui *ui, int visible)
167{
168 set_menu_entry_visible(ui, "/MainMenu/JobMenu", visible);
169}
170
171static void set_view_results_visible(struct gui *ui, int visible)
172{
173 set_menu_entry_visible(ui, "/MainMenu/ViewMenu/Results", visible);
174}
175
Jens Axboe014f4022012-03-15 14:03:01 +0100176static const char *get_button_tooltip(struct button_spec *s, int sensitive)
177{
178 if (s->tooltiptext[sensitive])
179 return s->tooltiptext[sensitive];
180
181 return s->tooltiptext[0];
182}
183
184static GtkWidget *add_button(GtkWidget *buttonbox,
185 struct button_spec *buttonspec, gpointer data)
186{
187 GtkWidget *button = gtk_button_new_with_label(buttonspec->buttontext);
188 gboolean sens = buttonspec->start_sensitive;
189
190 g_signal_connect(button, "clicked", G_CALLBACK(buttonspec->f), data);
191 gtk_box_pack_start(GTK_BOX(buttonbox), button, FALSE, FALSE, 3);
192
193 sens = buttonspec->start_sensitive;
194 gtk_widget_set_tooltip_text(button, get_button_tooltip(buttonspec, sens));
195 gtk_widget_set_sensitive(button, sens);
196
197 return button;
198}
199
200static void add_buttons(struct gui_entry *ge, struct button_spec *buttonlist,
201 int nbuttons)
202{
203 int i;
204
205 for (i = 0; i < nbuttons; i++)
206 ge->button[i] = add_button(ge->buttonbox, &buttonlist[i], ge);
207}
208
Jens Axboe85dd01e2012-03-12 14:33:16 +0100209/*
210 * Update sensitivity of job buttons and job menu items, based on the
211 * state of the client.
212 */
213static void update_button_states(struct gui *ui, struct gui_entry *ge)
214{
215 unsigned int connect_state, send_state, start_state, edit_state;
216 const char *connect_str = NULL;
Jens Axboe85dd01e2012-03-12 14:33:16 +0100217
218 switch (ge->state) {
Jens Axboe1252d8f2012-03-21 11:13:31 +0100219 default:
220 gfio_report_error(ge, "Bad client state: %u\n", ge->state);
Jens Axboe85dd01e2012-03-12 14:33:16 +0100221 /* fall through to new state */
Jens Axboe85dd01e2012-03-12 14:33:16 +0100222 case GE_STATE_NEW:
223 connect_state = 1;
Jens Axboe9af4a242012-03-16 10:13:49 +0100224 edit_state = 1;
Jens Axboe85dd01e2012-03-12 14:33:16 +0100225 connect_str = "Connect";
226 send_state = 0;
227 start_state = 0;
228 break;
229 case GE_STATE_CONNECTED:
230 connect_state = 1;
Jens Axboe9af4a242012-03-16 10:13:49 +0100231 edit_state = 1;
Jens Axboe85dd01e2012-03-12 14:33:16 +0100232 connect_str = "Disconnect";
233 send_state = 1;
234 start_state = 0;
235 break;
236 case GE_STATE_JOB_SENT:
237 connect_state = 1;
Jens Axboe9af4a242012-03-16 10:13:49 +0100238 edit_state = 1;
Jens Axboe85dd01e2012-03-12 14:33:16 +0100239 connect_str = "Disconnect";
240 send_state = 0;
241 start_state = 1;
242 break;
243 case GE_STATE_JOB_STARTED:
244 connect_state = 1;
245 edit_state = 1;
246 connect_str = "Disconnect";
247 send_state = 0;
248 start_state = 1;
249 break;
250 case GE_STATE_JOB_RUNNING:
251 connect_state = 1;
252 edit_state = 0;
253 connect_str = "Disconnect";
254 send_state = 0;
255 start_state = 0;
256 break;
257 case GE_STATE_JOB_DONE:
258 connect_state = 1;
259 edit_state = 0;
260 connect_str = "Connect";
261 send_state = 0;
262 start_state = 0;
263 break;
264 }
265
Jens Axboe53e0e852012-03-15 19:38:01 +0100266 gtk_widget_set_sensitive(ge->button[GFIO_BUTTON_CONNECT], connect_state);
267 gtk_widget_set_sensitive(ge->button[GFIO_BUTTON_SEND], send_state);
268 gtk_widget_set_sensitive(ge->button[GFIO_BUTTON_START], start_state);
269 gtk_button_set_label(GTK_BUTTON(ge->button[GFIO_BUTTON_CONNECT]), connect_str);
270 gtk_widget_set_tooltip_text(ge->button[GFIO_BUTTON_CONNECT], get_button_tooltip(&buttonspeclist[GFIO_BUTTON_CONNECT], connect_state));
Jens Axboe85dd01e2012-03-12 14:33:16 +0100271
Jens Axboe781ccba2012-03-15 09:44:42 +0100272 set_menu_entry_visible(ui, "/MainMenu/JobMenu/Connect", connect_state);
273 set_menu_entry_text(ui, "/MainMenu/JobMenu/Connect", connect_str);
Jens Axboe85dd01e2012-03-12 14:33:16 +0100274
Jens Axboe781ccba2012-03-15 09:44:42 +0100275 set_menu_entry_visible(ui, "/MainMenu/JobMenu/Edit job", edit_state);
276 set_menu_entry_visible(ui, "/MainMenu/JobMenu/Send job", send_state);
277 set_menu_entry_visible(ui, "/MainMenu/JobMenu/Start job", start_state);
Jens Axboe85dd01e2012-03-12 14:33:16 +0100278
Jens Axboe781ccba2012-03-15 09:44:42 +0100279 if (ge->client && ge->client->nr_results)
280 set_view_results_visible(ui, 1);
281 else
282 set_view_results_visible(ui, 0);
Jens Axboe85dd01e2012-03-12 14:33:16 +0100283}
284
Jens Axboe1252d8f2012-03-21 11:13:31 +0100285void gfio_set_state(struct gui_entry *ge, unsigned int state)
Jens Axboe85dd01e2012-03-12 14:33:16 +0100286{
287 ge->state = state;
288 update_button_states(ge->ui, ge);
289}
290
Jens Axboe9b260bd2012-03-06 11:02:52 +0100291static void gfio_ui_setup_log(struct gui *ui)
292{
293 GtkTreeSelection *selection;
294 GtkListStore *model;
295 GtkWidget *tree_view;
296
Jens Axboe3ad04392012-03-26 21:08:46 +0200297 model = gtk_list_store_new(4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
Jens Axboe9b260bd2012-03-06 11:02:52 +0100298
299 tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
300 gtk_widget_set_can_focus(tree_view, FALSE);
301
302 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
303 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_BROWSE);
Jens Axboe661f7412012-03-06 13:55:45 +0100304 g_object_set(G_OBJECT(tree_view), "headers-visible", TRUE,
305 "enable-grid-lines", GTK_TREE_VIEW_GRID_LINES_BOTH, NULL);
Jens Axboe9b260bd2012-03-06 11:02:52 +0100306
307 tree_view_column(tree_view, 0, "Time", ALIGN_RIGHT | UNSORTABLE);
308 tree_view_column(tree_view, 1, "Host", ALIGN_RIGHT | UNSORTABLE);
309 tree_view_column(tree_view, 2, "Level", ALIGN_RIGHT | UNSORTABLE);
Jens Axboef095d562012-03-06 13:49:12 +0100310 tree_view_column(tree_view, 3, "Text", ALIGN_LEFT | UNSORTABLE);
Jens Axboe9b260bd2012-03-06 11:02:52 +0100311
312 ui->log_model = model;
313 ui->log_tree = tree_view;
314}
315
Jens Axboe2f99deb2012-03-09 14:37:29 +0100316static gint on_config_drawing_area(GtkWidget *w, GdkEventConfigure *event,
317 gpointer data)
Stephen M. Cameron3ea48b82012-03-07 19:40:58 +0100318{
Jens Axboecd0d2db2012-03-26 19:30:24 +0200319 guint width = gtk_widget_get_allocated_width(w);
320 guint height = gtk_widget_get_allocated_height(w);
Jens Axboe2f99deb2012-03-09 14:37:29 +0100321 struct gfio_graphs *g = data;
322
Jens Axboecd0d2db2012-03-26 19:30:24 +0200323 graph_set_size(g->iops_graph, width / 2.0, height);
324 graph_set_position(g->iops_graph, width / 2.0, 0.0);
325 graph_set_size(g->bandwidth_graph, width / 2.0, height);
Stephen M. Cameron57f9d282012-03-11 11:36:51 +0100326 graph_set_position(g->bandwidth_graph, 0, 0);
Stephen M. Cameron3ea48b82012-03-07 19:40:58 +0100327 return TRUE;
328}
329
Stephen M. Cameron57f9d282012-03-11 11:36:51 +0100330static void draw_graph(struct graph *g, cairo_t *cr)
331{
332 line_graph_draw(g, cr);
333 cairo_stroke(cr);
334}
335
Jens Axboe93e2db22012-03-13 09:45:22 +0100336static gboolean graph_tooltip(GtkWidget *w, gint x, gint y,
337 gboolean keyboard_mode, GtkTooltip *tooltip,
338 gpointer data)
339{
340 struct gfio_graphs *g = data;
341 const char *text = NULL;
342
343 if (graph_contains_xy(g->iops_graph, x, y))
344 text = graph_find_tooltip(g->iops_graph, x, y);
345 else if (graph_contains_xy(g->bandwidth_graph, x, y))
346 text = graph_find_tooltip(g->bandwidth_graph, x, y);
347
348 if (text) {
349 gtk_tooltip_set_text(tooltip, text);
350 return TRUE;
351 }
352
353 return FALSE;
354}
355
Jens Axboe2fd3bb02012-03-07 08:07:39 +0100356static int on_expose_drawing_area(GtkWidget *w, GdkEvent *event, gpointer p)
357{
Jens Axboe2f99deb2012-03-09 14:37:29 +0100358 struct gfio_graphs *g = p;
Jens Axboe2fd3bb02012-03-07 08:07:39 +0100359 cairo_t *cr;
360
Jens Axboecd0d2db2012-03-26 19:30:24 +0200361 cr = gdk_cairo_create(gtk_widget_get_window(w));
Jens Axboe93e2db22012-03-13 09:45:22 +0100362
363 if (graph_has_tooltips(g->iops_graph) ||
364 graph_has_tooltips(g->bandwidth_graph)) {
365 g_object_set(w, "has-tooltip", TRUE, NULL);
366 g_signal_connect(w, "query-tooltip", G_CALLBACK(graph_tooltip), g);
367 }
368
Jens Axboe2fd3bb02012-03-07 08:07:39 +0100369 cairo_set_source_rgb(cr, 0, 0, 0);
Stephen M. Cameron57f9d282012-03-11 11:36:51 +0100370 draw_graph(g->iops_graph, cr);
371 draw_graph(g->bandwidth_graph, cr);
Jens Axboe2fd3bb02012-03-07 08:07:39 +0100372 cairo_destroy(cr);
373
374 return FALSE;
375}
376
Jens Axboe2f99deb2012-03-09 14:37:29 +0100377/*
Jens Axboe0fd18982012-03-14 10:34:48 +0100378 * FIXME: need more handling here
379 */
380static void ge_destroy(struct gui_entry *ge)
381{
382 struct gfio_client *gc = ge->client;
383
Jens Axboe470cdbb2012-03-21 12:02:13 +0100384 if (gc) {
385 if (gc->client) {
386 if (ge->state >= GE_STATE_CONNECTED)
387 fio_client_terminate(gc->client);
Jens Axboe0fd18982012-03-14 10:34:48 +0100388
Jens Axboe470cdbb2012-03-21 12:02:13 +0100389 fio_put_client(gc->client);
390 }
391 free(gc);
Jens Axboe0fd18982012-03-14 10:34:48 +0100392 }
393
Jens Axboeb98ab712012-03-21 12:48:32 +0100394 g_hash_table_remove(ge->ui->ge_hash, &ge->page_num);
395
Jens Axboe0cf3ece2012-03-21 10:15:20 +0100396 free(ge->job_file);
397 free(ge->host);
Jens Axboe0fd18982012-03-14 10:34:48 +0100398 free(ge);
399}
400
401static void ge_widget_destroy(GtkWidget *w, gpointer data)
402{
Jens Axboe2eb98bf2012-03-20 08:20:48 +0100403 struct gui_entry *ge = (struct gui_entry *) data;
404
405 ge_destroy(ge);
Jens Axboe0fd18982012-03-14 10:34:48 +0100406}
407
408static void gfio_quit(struct gui *ui)
409{
Jens Axboe3c3ed072012-03-27 09:12:39 +0200410 gtk_main_quit();
Jens Axboe0fd18982012-03-14 10:34:48 +0100411}
412
Stephen M. Cameronff1f3282012-02-24 08:17:30 +0100413static void quit_clicked(__attribute__((unused)) GtkWidget *widget,
Jens Axboe3c3ed072012-03-27 09:12:39 +0200414 gpointer data)
Stephen M. Cameronff1f3282012-02-24 08:17:30 +0100415{
Jens Axboe6e02ad62012-03-20 12:25:36 +0100416 struct gui *ui = (struct gui *) data;
417
418 gfio_quit(ui);
Stephen M. Cameronff1f3282012-02-24 08:17:30 +0100419}
420
Stephen M. Cameron25927252012-02-24 08:17:31 +0100421static void *job_thread(void *arg)
Stephen M. Cameronf3074002012-02-24 08:17:30 +0100422{
Jens Axboea9eccde2012-03-09 14:59:42 +0100423 struct gui *ui = arg;
424
425 ui->handler_running = 1;
Stephen M. Cameron25927252012-02-24 08:17:31 +0100426 fio_handle_clients(&gfio_client_ops);
Jens Axboea9eccde2012-03-09 14:59:42 +0100427 ui->handler_running = 0;
Stephen M. Cameron25927252012-02-24 08:17:31 +0100428 return NULL;
429}
430
Jens Axboe0cf3ece2012-03-21 10:15:20 +0100431static int send_job_file(struct gui_entry *ge)
Stephen M. Cameron60f6b332012-02-24 08:17:32 +0100432{
Jens Axboe9988ca72012-03-09 15:14:06 +0100433 struct gfio_client *gc = ge->client;
Jens Axboe0cf3ece2012-03-21 10:15:20 +0100434 int ret = 0;
Stephen M. Cameron60f6b332012-02-24 08:17:32 +0100435
Jens Axboe753e9e62012-03-24 20:22:29 +0100436 /*
437 * Prune old options, we are expecting the return options
438 * when the job file is parsed remotely and returned to us.
439 */
440 while (!flist_empty(&gc->o_list)) {
441 struct gfio_client_options *gco;
442
443 gco = flist_entry(gc->o_list.next, struct gfio_client_options, list);
444 flist_del(&gco->list);
445 free(gco);
446 }
447
Jens Axboe0cf3ece2012-03-21 10:15:20 +0100448 ret = fio_client_send_ini(gc->client, ge->job_file);
449 if (!ret)
450 return 0;
Jens Axboec7249262012-03-09 17:11:04 +0100451
Jens Axboe41666582012-03-21 10:25:29 +0100452 gfio_report_error(ge, "Failed to send file %s: %s\n", ge->job_file, strerror(-ret));
Jens Axboe0cf3ece2012-03-21 10:15:20 +0100453 return 1;
Stephen M. Cameron60f6b332012-02-24 08:17:32 +0100454}
455
Jens Axboe63a130b2012-03-06 20:08:59 +0100456static void *server_thread(void *arg)
457{
458 is_backend = 1;
459 gfio_server_running = 1;
460 fio_start_server(NULL);
461 gfio_server_running = 0;
462 return NULL;
463}
464
Jens Axboe6e02ad62012-03-20 12:25:36 +0100465static void gfio_start_server(struct gui *ui)
Jens Axboe63a130b2012-03-06 20:08:59 +0100466{
467 if (!gfio_server_running) {
468 gfio_server_running = 1;
469 pthread_create(&ui->server_t, NULL, server_thread, NULL);
Jens Axboee34f6ad2012-03-06 20:47:15 +0100470 pthread_detach(ui->server_t);
Jens Axboe63a130b2012-03-06 20:08:59 +0100471 }
472}
473
Stephen M. Cameron25927252012-02-24 08:17:31 +0100474static void start_job_clicked(__attribute__((unused)) GtkWidget *widget,
Jens Axboe3c3ed072012-03-27 09:12:39 +0200475 gpointer data)
Stephen M. Cameron25927252012-02-24 08:17:31 +0100476{
Jens Axboe2f99deb2012-03-09 14:37:29 +0100477 struct gui_entry *ge = data;
478 struct gfio_client *gc = ge->client;
Stephen M. Cameron25927252012-02-24 08:17:31 +0100479
Jens Axboe78cb2fe2012-03-12 23:05:29 +0100480 if (gc)
481 fio_start_client(gc->client);
Stephen M. Cameronf3074002012-02-24 08:17:30 +0100482}
483
Jens Axboedf06f222012-03-02 13:32:04 +0100484static void file_open(GtkWidget *w, gpointer data);
485
Jens Axboe62bc9372012-03-07 11:45:07 +0100486struct connection_widgets
487{
488 GtkWidget *hentry;
489 GtkWidget *combo;
490 GtkWidget *button;
491};
492
493static void hostname_cb(GtkEntry *entry, gpointer data)
494{
495 struct connection_widgets *cw = data;
496 int uses_net = 0, is_localhost = 0;
497 const gchar *text;
498 gchar *ctext;
499
500 /*
501 * Check whether to display the 'auto start backend' box
502 * or not. Show it if we are a localhost and using network,
503 * or using a socket.
504 */
Jens Axboef762cef2012-03-26 13:51:11 +0200505 ctext = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(cw->combo));
Jens Axboe62bc9372012-03-07 11:45:07 +0100506 if (!ctext || !strncmp(ctext, "IPv4", 4) || !strncmp(ctext, "IPv6", 4))
507 uses_net = 1;
508 g_free(ctext);
509
510 if (uses_net) {
511 text = gtk_entry_get_text(GTK_ENTRY(cw->hentry));
512 if (!strcmp(text, "127.0.0.1") || !strcmp(text, "localhost") ||
513 !strcmp(text, "::1") || !strcmp(text, "ip6-localhost") ||
514 !strcmp(text, "ip6-loopback"))
515 is_localhost = 1;
516 }
517
518 if (!uses_net || is_localhost) {
519 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cw->button), 1);
520 gtk_widget_set_sensitive(cw->button, 1);
521 } else {
522 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cw->button), 0);
523 gtk_widget_set_sensitive(cw->button, 0);
524 }
Jens Axboeb0500cc2012-03-21 11:59:18 +0100525}
Jens Axboea7a42ce2012-03-02 13:12:04 +0100526
Jens Axboeb0500cc2012-03-21 11:59:18 +0100527static int get_connection_details(struct gui_entry *ge)
528{
529 GtkWidget *dialog, *box, *vbox, *hbox, *frame, *pentry;
530 struct connection_widgets cw;
531 struct gui *ui = ge->ui;
532 char *typeentry;
Jens Axboea7a42ce2012-03-02 13:12:04 +0100533
Jens Axboeb0500cc2012-03-21 11:59:18 +0100534 if (ge->host)
Jens Axboe1252d8f2012-03-21 11:13:31 +0100535 return 0;
Jens Axboe1252d8f2012-03-21 11:13:31 +0100536
Jens Axboeb0500cc2012-03-21 11:59:18 +0100537 dialog = gtk_dialog_new_with_buttons("Connection details",
538 GTK_WINDOW(ui->window),
539 GTK_DIALOG_DESTROY_WITH_PARENT,
540 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
541 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, NULL);
Jens Axboe1252d8f2012-03-21 11:13:31 +0100542
Jens Axboeb0500cc2012-03-21 11:59:18 +0100543 frame = gtk_frame_new("Hostname / socket name");
Jens Axboef762cef2012-03-26 13:51:11 +0200544 vbox = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
Jens Axboeb0500cc2012-03-21 11:59:18 +0100545 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
Jens Axboe1252d8f2012-03-21 11:13:31 +0100546
Jens Axboeb0500cc2012-03-21 11:59:18 +0100547 box = gtk_vbox_new(FALSE, 6);
548 gtk_container_add(GTK_CONTAINER(frame), box);
Jens Axboe1252d8f2012-03-21 11:13:31 +0100549
Jens Axboeb0500cc2012-03-21 11:59:18 +0100550 hbox = gtk_hbox_new(TRUE, 10);
551 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
552 cw.hentry = gtk_entry_new();
553 gtk_entry_set_text(GTK_ENTRY(cw.hentry), "localhost");
554 gtk_box_pack_start(GTK_BOX(hbox), cw.hentry, TRUE, TRUE, 0);
Jens Axboe1252d8f2012-03-21 11:13:31 +0100555
Jens Axboeb0500cc2012-03-21 11:59:18 +0100556 frame = gtk_frame_new("Port");
557 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
558 box = gtk_vbox_new(FALSE, 10);
559 gtk_container_add(GTK_CONTAINER(frame), box);
Jens Axboe1252d8f2012-03-21 11:13:31 +0100560
Jens Axboeb0500cc2012-03-21 11:59:18 +0100561 hbox = gtk_hbox_new(TRUE, 4);
562 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
563 pentry = create_spinbutton(hbox, 1, 65535, FIO_NET_PORT);
Jens Axboe1252d8f2012-03-21 11:13:31 +0100564
Jens Axboeb0500cc2012-03-21 11:59:18 +0100565 frame = gtk_frame_new("Type");
566 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
567 box = gtk_vbox_new(FALSE, 10);
568 gtk_container_add(GTK_CONTAINER(frame), box);
Jens Axboe1252d8f2012-03-21 11:13:31 +0100569
Jens Axboeb0500cc2012-03-21 11:59:18 +0100570 hbox = gtk_hbox_new(TRUE, 4);
571 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
Jens Axboe1252d8f2012-03-21 11:13:31 +0100572
Jens Axboef762cef2012-03-26 13:51:11 +0200573 cw.combo = gtk_combo_box_text_new();
574 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(cw.combo), "IPv4");
575 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(cw.combo), "IPv6");
576 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(cw.combo), "local socket");
Jens Axboeb0500cc2012-03-21 11:59:18 +0100577 gtk_combo_box_set_active(GTK_COMBO_BOX(cw.combo), 0);
Jens Axboe1252d8f2012-03-21 11:13:31 +0100578
Jens Axboeb0500cc2012-03-21 11:59:18 +0100579 gtk_container_add(GTK_CONTAINER(hbox), cw.combo);
Jens Axboe1252d8f2012-03-21 11:13:31 +0100580
Jens Axboeb0500cc2012-03-21 11:59:18 +0100581 frame = gtk_frame_new("Options");
582 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
583 box = gtk_vbox_new(FALSE, 10);
584 gtk_container_add(GTK_CONTAINER(frame), box);
Jens Axboe38634cb2012-03-13 12:26:41 +0100585
Jens Axboeb0500cc2012-03-21 11:59:18 +0100586 hbox = gtk_hbox_new(TRUE, 4);
587 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
Jens Axboe2f99deb2012-03-09 14:37:29 +0100588
Jens Axboeb0500cc2012-03-21 11:59:18 +0100589 cw.button = gtk_check_button_new_with_label("Auto-spawn fio backend");
590 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cw.button), 1);
591 gtk_widget_set_tooltip_text(cw.button, "When running fio locally, it is necessary to have the backend running on the same system. If this is checked, gfio will start the backend automatically for you if it isn't already running.");
592 gtk_box_pack_start(GTK_BOX(hbox), cw.button, FALSE, FALSE, 6);
Jens Axboe2f99deb2012-03-09 14:37:29 +0100593
Jens Axboe1252d8f2012-03-21 11:13:31 +0100594 /*
Jens Axboeb0500cc2012-03-21 11:59:18 +0100595 * Connect edit signal, so we can show/not-show the auto start button
Jens Axboe1252d8f2012-03-21 11:13:31 +0100596 */
Jens Axboecd972fd2012-03-26 12:55:33 +0200597 g_signal_connect(G_OBJECT(cw.hentry), "changed", G_CALLBACK(hostname_cb), &cw);
598 g_signal_connect(G_OBJECT(cw.combo), "changed", G_CALLBACK(hostname_cb), &cw);
Jens Axboe0420ba62012-02-29 11:16:52 +0100599
Jens Axboeb0500cc2012-03-21 11:59:18 +0100600 gtk_widget_show_all(dialog);
Jens Axboe1252d8f2012-03-21 11:13:31 +0100601
Jens Axboeb0500cc2012-03-21 11:59:18 +0100602 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT) {
603 gtk_widget_destroy(dialog);
Jens Axboea6790902012-03-13 15:16:11 +0100604 return 1;
605 }
606
Jens Axboeb0500cc2012-03-21 11:59:18 +0100607 ge->host = strdup(gtk_entry_get_text(GTK_ENTRY(cw.hentry)));
608 ge->port = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(pentry));
Jens Axboea6790902012-03-13 15:16:11 +0100609
Jens Axboef762cef2012-03-26 13:51:11 +0200610 typeentry = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(cw.combo));
Jens Axboeb0500cc2012-03-21 11:59:18 +0100611 if (!typeentry || !strncmp(typeentry, "IPv4", 4))
612 ge->type = Fio_client_ipv4;
613 else if (!strncmp(typeentry, "IPv6", 4))
614 ge->type = Fio_client_ipv6;
615 else
616 ge->type = Fio_client_socket;
617 g_free(typeentry);
Jens Axboe1252d8f2012-03-21 11:13:31 +0100618
Jens Axboeb0500cc2012-03-21 11:59:18 +0100619 ge->server_start = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cw.button));
Jens Axboe1252d8f2012-03-21 11:13:31 +0100620
Jens Axboeb0500cc2012-03-21 11:59:18 +0100621 gtk_widget_destroy(dialog);
622 return 0;
623}
Jens Axboe1252d8f2012-03-21 11:13:31 +0100624
Jens Axboeb0500cc2012-03-21 11:59:18 +0100625static void gfio_set_client(struct gfio_client *gc, struct fio_client *client)
626{
627 gc->client = fio_get_client(client);
628 client->client_data = gc;
629}
Jens Axboe1252d8f2012-03-21 11:13:31 +0100630
Jens Axboeb0500cc2012-03-21 11:59:18 +0100631static void gfio_client_added(struct gui_entry *ge, struct fio_client *client)
632{
Jens Axboecf3d8242012-03-24 08:56:50 +0100633 struct gfio_client_options *gco;
Jens Axboeb0500cc2012-03-21 11:59:18 +0100634 struct gfio_client *gc;
Jens Axboe1252d8f2012-03-21 11:13:31 +0100635
Jens Axboecf3d8242012-03-24 08:56:50 +0100636 gc = calloc(1, sizeof(*gc));
637 INIT_FLIST_HEAD(&gc->o_list);
Jens Axboeb0500cc2012-03-21 11:59:18 +0100638 gc->ge = ge;
639 ge->client = gc;
640 gfio_set_client(gc, client);
Jens Axboecf3d8242012-03-24 08:56:50 +0100641
642 /*
643 * Just add a default set of options, need to consider how best
644 * to handle this
645 */
646 gco = calloc(1, sizeof(*gco));
Jens Axboe753e9e62012-03-24 20:22:29 +0100647 INIT_FLIST_HEAD(&gco->list);
Jens Axboecf3d8242012-03-24 08:56:50 +0100648 options_default_fill(&gco->o);
649 flist_add_tail(&gco->list, &gc->o_list);
Jens Axboe753e9e62012-03-24 20:22:29 +0100650 gc->o_list_nr++;
Jens Axboeb0500cc2012-03-21 11:59:18 +0100651}
Jens Axboea6790902012-03-13 15:16:11 +0100652
Jens Axboeb0500cc2012-03-21 11:59:18 +0100653static void connect_clicked(GtkWidget *widget, gpointer data)
654{
655 struct gui_entry *ge = data;
656 struct gfio_client *gc = ge->client;
Jens Axboea6790902012-03-13 15:16:11 +0100657
Jens Axboeb0500cc2012-03-21 11:59:18 +0100658 if (ge->state == GE_STATE_NEW) {
659 int ret;
Jens Axboea6790902012-03-13 15:16:11 +0100660
Jens Axboeb0500cc2012-03-21 11:59:18 +0100661 if (!ge->job_file)
662 file_open(widget, ge->ui);
663 if (!ge->job_file)
Jens Axboe1252d8f2012-03-21 11:13:31 +0100664 return;
Jens Axboeb0500cc2012-03-21 11:59:18 +0100665
666 gc = ge->client;
667
668 if (!gc->client) {
669 struct fio_client *client;
670
671 if (get_connection_details(ge)) {
672 gfio_report_error(ge, "Failed to get connection details\n");
673 return;
674 }
675
676 client = fio_client_add_explicit(&gfio_client_ops, ge->host, ge->type, ge->port);
677 if (!client) {
678 gfio_report_error(ge, "Failed to add client %s\n", ge->host);
679 free(ge->host);
680 ge->host = NULL;
681 return;
682 }
683 gfio_set_client(gc, client);
Jens Axboe1252d8f2012-03-21 11:13:31 +0100684 }
Jens Axboe0420ba62012-02-29 11:16:52 +0100685
Jens Axboeb0500cc2012-03-21 11:59:18 +0100686 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(ge->thread_status_pb), "No jobs running");
687 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(ge->thread_status_pb), 0.0);
688 ret = fio_client_connect(gc->client);
689 if (!ret) {
690 if (!ge->ui->handler_running)
691 pthread_create(&ge->ui->t, NULL, job_thread, ge->ui);
692 gfio_set_state(ge, GE_STATE_CONNECTED);
693 } else {
694 gfio_report_error(ge, "Failed to connect to %s: %s\n", ge->client->client->hostname, strerror(-ret));
695 }
696 } else {
697 fio_client_terminate(gc->client);
698 gfio_set_state(ge, GE_STATE_NEW);
699 clear_ge_ui_info(ge);
700 }
701}
702
703static void send_clicked(GtkWidget *widget, gpointer data)
704{
705 struct gui_entry *ge = data;
706
707 if (send_job_file(ge))
708 gtk_widget_set_sensitive(ge->button[GFIO_BUTTON_START], 1);
709}
710
711static GtkWidget *new_client_page(struct gui_entry *ge);
712
713static struct gui_entry *alloc_new_gui_entry(struct gui *ui)
714{
715 struct gui_entry *ge;
716
717 ge = malloc(sizeof(*ge));
718 memset(ge, 0, sizeof(*ge));
719 ge->state = GE_STATE_NEW;
Jens Axboeb0500cc2012-03-21 11:59:18 +0100720 ge->ui = ui;
721 return ge;
722}
723
724static struct gui_entry *get_new_ge_with_tab(struct gui *ui, const char *name)
725{
726 struct gui_entry *ge;
727
728 ge = alloc_new_gui_entry(ui);
729
730 ge->vbox = new_client_page(ge);
731 g_signal_connect(ge->vbox, "destroy", G_CALLBACK(ge_widget_destroy), ge);
732
733 ge->page_label = gtk_label_new(name);
734 ge->page_num = gtk_notebook_append_page(GTK_NOTEBOOK(ui->notebook), ge->vbox, ge->page_label);
735
Jens Axboeb98ab712012-03-21 12:48:32 +0100736 g_hash_table_insert(ui->ge_hash, &ge->page_num, ge);
737
Jens Axboeb0500cc2012-03-21 11:59:18 +0100738 gtk_widget_show_all(ui->window);
739 return ge;
740}
741
742static void file_new(GtkWidget *w, gpointer data)
743{
744 struct gui *ui = (struct gui *) data;
745 struct gui_entry *ge;
746
747 ge = get_new_ge_with_tab(ui, "Untitled");
748 gtk_notebook_set_current_page(GTK_NOTEBOOK(ui->notebook), ge->page_num);
749}
750
751/*
752 * Return the 'ge' corresponding to the tab. If the active tab is the
753 * main tab, open a new tab.
754 */
755static struct gui_entry *get_ge_from_page(struct gui *ui, gint cur_page,
756 int *created)
757{
Jens Axboeb0500cc2012-03-21 11:59:18 +0100758 if (!cur_page) {
759 if (created)
760 *created = 1;
761 return get_new_ge_with_tab(ui, "Untitled");
762 }
763
764 if (created)
765 *created = 0;
766
Jens Axboeb98ab712012-03-21 12:48:32 +0100767 return g_hash_table_lookup(ui->ge_hash, &cur_page);
Jens Axboeb0500cc2012-03-21 11:59:18 +0100768}
769
770static struct gui_entry *get_ge_from_cur_tab(struct gui *ui)
771{
772 gint cur_page;
773
774 /*
775 * Main tab is tab 0, so any current page other than 0 holds
776 * a ge entry.
777 */
778 cur_page = gtk_notebook_get_current_page(GTK_NOTEBOOK(ui->notebook));
779 if (cur_page)
780 return get_ge_from_page(ui, cur_page, NULL);
781
782 return NULL;
783}
784
785static void file_close(GtkWidget *w, gpointer data)
786{
787 struct gui *ui = (struct gui *) data;
788 struct gui_entry *ge;
789
790 /*
791 * Can't close the main tab
792 */
793 ge = get_ge_from_cur_tab(ui);
794 if (ge) {
795 gtk_widget_destroy(ge->vbox);
796 return;
797 }
798
Jens Axboeb98ab712012-03-21 12:48:32 +0100799 if (g_hash_table_size(ui->ge_hash)) {
Jens Axboeb0500cc2012-03-21 11:59:18 +0100800 gfio_report_info(ui, "Error", "The main page view cannot be closed\n");
801 return;
802 }
803
804 gfio_quit(ui);
805}
806
807static void file_add_recent(struct gui *ui, const gchar *uri)
808{
809 GtkRecentData grd;
810
811 memset(&grd, 0, sizeof(grd));
812 grd.display_name = strdup("gfio");
813 grd.description = strdup("Fio job file");
814 grd.mime_type = strdup(GFIO_MIME);
815 grd.app_name = strdup(g_get_application_name());
816 grd.app_exec = strdup("gfio %f/%u");
817
818 gtk_recent_manager_add_full(ui->recentmanager, uri, &grd);
819}
820
821static gchar *get_filename_from_uri(const gchar *uri)
822{
823 if (strncmp(uri, "file://", 7))
824 return strdup(uri);
825
826 return strdup(uri + 7);
827}
828
829static int do_file_open(struct gui_entry *ge, const gchar *uri)
830{
831 struct fio_client *client;
832
833 assert(!ge->job_file);
834
835 ge->job_file = get_filename_from_uri(uri);
836
837 client = fio_client_add_explicit(&gfio_client_ops, ge->host, ge->type, ge->port);
838 if (client) {
Jens Axboe832fde72012-03-21 12:55:49 +0100839 char *label = strdup(uri);
840
841 basename(label);
842 gtk_label_set_text(GTK_LABEL(ge->page_label), basename(label));
843 free(label);
844
Jens Axboeb0500cc2012-03-21 11:59:18 +0100845 gfio_client_added(ge, client);
846 file_add_recent(ge->ui, uri);
847 return 0;
848 }
849
850 gfio_report_error(ge, "Failed to add client %s\n", ge->host);
851 free(ge->host);
852 ge->host = NULL;
Jens Axboeb98ab712012-03-21 12:48:32 +0100853 free(ge->job_file);
854 ge->job_file = NULL;
Jens Axboeb0500cc2012-03-21 11:59:18 +0100855 return 1;
856}
857
858static int do_file_open_with_tab(struct gui *ui, const gchar *uri)
859{
860 struct gui_entry *ge;
861 gint cur_page;
862 int ret, ge_is_new = 0;
863
864 /*
865 * Creates new tab if current tab is the main window, or the
866 * current tab already has a client.
867 */
868 cur_page = gtk_notebook_get_current_page(GTK_NOTEBOOK(ui->notebook));
869 ge = get_ge_from_page(ui, cur_page, &ge_is_new);
870 if (ge->client) {
871 ge = get_new_ge_with_tab(ui, "Untitled");
872 ge_is_new = 1;
873 }
874
875 gtk_notebook_set_current_page(GTK_NOTEBOOK(ui->notebook), ge->page_num);
876
877 if (get_connection_details(ge)) {
878 if (ge_is_new)
879 gtk_widget_destroy(ge->vbox);
Jens Axboe3c3ed072012-03-27 09:12:39 +0200880
Jens Axboeb0500cc2012-03-21 11:59:18 +0100881 return 1;
882 }
883
884 ret = do_file_open(ge, uri);
885
886 if (!ret) {
887 if (ge->server_start)
888 gfio_start_server(ui);
889 } else {
890 if (ge_is_new)
891 gtk_widget_destroy(ge->vbox);
892 }
893
894 return ret;
895}
896
897static void recent_open(GtkAction *action, gpointer data)
898{
899 struct gui *ui = (struct gui *) data;
900 GtkRecentInfo *info;
901 const gchar *uri;
902
903 info = g_object_get_data(G_OBJECT(action), "gtk-recent-info");
904 uri = gtk_recent_info_get_uri(info);
905
906 do_file_open_with_tab(ui, uri);
907}
908
909static void file_open(GtkWidget *w, gpointer data)
910{
911 struct gui *ui = data;
912 GtkWidget *dialog;
913 GtkFileFilter *filter;
914 gchar *filename;
915
916 dialog = gtk_file_chooser_dialog_new("Open File",
917 GTK_WINDOW(ui->window),
918 GTK_FILE_CHOOSER_ACTION_OPEN,
919 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
920 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
921 NULL);
922 gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), FALSE);
923
924 filter = gtk_file_filter_new();
925 gtk_file_filter_add_pattern(filter, "*.fio");
926 gtk_file_filter_add_pattern(filter, "*.job");
927 gtk_file_filter_add_pattern(filter, "*.ini");
928 gtk_file_filter_add_mime_type(filter, GFIO_MIME);
929 gtk_file_filter_set_name(filter, "Fio job file");
930 gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(dialog), filter);
931
932 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT) {
933 gtk_widget_destroy(dialog);
934 return;
935 }
936
937 filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
938
939 gtk_widget_destroy(dialog);
940
941 do_file_open_with_tab(ui, filename);
942 g_free(filename);
943}
944
945static void file_save(GtkWidget *w, gpointer data)
946{
947 struct gui *ui = data;
948 GtkWidget *dialog;
949
950 dialog = gtk_file_chooser_dialog_new("Save File",
951 GTK_WINDOW(ui->window),
952 GTK_FILE_CHOOSER_ACTION_SAVE,
953 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
954 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
955 NULL);
956
957 gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE);
958 gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), "Untitled document");
959
960 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
961 char *filename;
962
Jens Axboe0420ba62012-02-29 11:16:52 +0100963 filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
Jens Axboeb0500cc2012-03-21 11:59:18 +0100964 // save_job_file(filename);
Jens Axboe0420ba62012-02-29 11:16:52 +0100965 g_free(filename);
966 }
Jens Axboeb0500cc2012-03-21 11:59:18 +0100967 gtk_widget_destroy(dialog);
968}
Jens Axboe0420ba62012-02-29 11:16:52 +0100969
Jens Axboe9b260bd2012-03-06 11:02:52 +0100970static void view_log_destroy(GtkWidget *w, gpointer data)
971{
972 struct gui *ui = (struct gui *) data;
973
Jens Axboef762cef2012-03-26 13:51:11 +0200974 g_object_ref(G_OBJECT(ui->log_tree));
Jens Axboe9b260bd2012-03-06 11:02:52 +0100975 gtk_container_remove(GTK_CONTAINER(w), ui->log_tree);
976 gtk_widget_destroy(w);
Jens Axboe4cbe7212012-03-06 13:36:17 +0100977 ui->log_view = NULL;
Jens Axboe9b260bd2012-03-06 11:02:52 +0100978}
979
Jens Axboe1252d8f2012-03-21 11:13:31 +0100980void gfio_view_log(struct gui *ui)
Jens Axboe9b260bd2012-03-06 11:02:52 +0100981{
Jens Axboe4cbe7212012-03-06 13:36:17 +0100982 GtkWidget *win, *scroll, *vbox, *box;
Jens Axboe9b260bd2012-03-06 11:02:52 +0100983
Jens Axboe4cbe7212012-03-06 13:36:17 +0100984 if (ui->log_view)
985 return;
986
987 ui->log_view = win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
Jens Axboe9b260bd2012-03-06 11:02:52 +0100988 gtk_window_set_title(GTK_WINDOW(win), "Log");
Jens Axboe4cbe7212012-03-06 13:36:17 +0100989 gtk_window_set_default_size(GTK_WINDOW(win), 700, 500);
Jens Axboe9b260bd2012-03-06 11:02:52 +0100990
Jens Axboe4cbe7212012-03-06 13:36:17 +0100991 scroll = gtk_scrolled_window_new(NULL, NULL);
Jens Axboe9b260bd2012-03-06 11:02:52 +0100992
Jens Axboe4cbe7212012-03-06 13:36:17 +0100993 gtk_container_set_border_width(GTK_CONTAINER(scroll), 5);
994
995 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
996
997 box = gtk_hbox_new(TRUE, 0);
Jens Axboef762cef2012-03-26 13:51:11 +0200998 gtk_box_pack_start(GTK_BOX(box), ui->log_tree, TRUE, TRUE, 0);
Jens Axboe4cbe7212012-03-06 13:36:17 +0100999 g_signal_connect(box, "destroy", G_CALLBACK(view_log_destroy), ui);
1000 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroll), box);
1001
1002 vbox = gtk_vbox_new(TRUE, 5);
Jens Axboef762cef2012-03-26 13:51:11 +02001003 gtk_box_pack_start(GTK_BOX(vbox), scroll, TRUE, TRUE, 0);
Jens Axboe4cbe7212012-03-06 13:36:17 +01001004
1005 gtk_container_add(GTK_CONTAINER(win), vbox);
Jens Axboe9b260bd2012-03-06 11:02:52 +01001006 gtk_widget_show_all(win);
1007}
1008
Jens Axboe1252d8f2012-03-21 11:13:31 +01001009static void view_log(GtkWidget *w, gpointer data)
1010{
1011 struct gui *ui = (struct gui *) data;
1012
1013 gfio_view_log(ui);
1014}
1015
Jens Axboe85dd01e2012-03-12 14:33:16 +01001016static void connect_job_entry(GtkWidget *w, gpointer data)
Jens Axboe16ce5ad2012-03-12 11:56:09 +01001017{
Jens Axboe85dd01e2012-03-12 14:33:16 +01001018 struct gui *ui = (struct gui *) data;
1019 struct gui_entry *ge;
Jens Axboe3c3ed072012-03-27 09:12:39 +02001020
Jens Axboe85dd01e2012-03-12 14:33:16 +01001021 ge = get_ge_from_cur_tab(ui);
1022 if (ge)
1023 connect_clicked(w, ge);
1024}
1025
1026static void send_job_entry(GtkWidget *w, gpointer data)
1027{
1028 struct gui *ui = (struct gui *) data;
1029 struct gui_entry *ge;
1030
1031 ge = get_ge_from_cur_tab(ui);
1032 if (ge)
1033 send_clicked(w, ge);
Jens Axboe85dd01e2012-03-12 14:33:16 +01001034}
1035
1036static void edit_job_entry(GtkWidget *w, gpointer data)
1037{
Jens Axboe9af4a242012-03-16 10:13:49 +01001038 struct gui *ui = (struct gui *) data;
Jens Axboe789f4cc2012-03-16 14:56:44 +01001039 struct gui_entry *ge;
Jens Axboe9af4a242012-03-16 10:13:49 +01001040
Jens Axboe789f4cc2012-03-16 14:56:44 +01001041 ge = get_ge_from_cur_tab(ui);
1042 if (ge && ge->client)
Jens Axboecf3d8242012-03-24 08:56:50 +01001043 gopt_get_options_window(ui->window, ge->client);
Jens Axboe85dd01e2012-03-12 14:33:16 +01001044}
1045
1046static void start_job_entry(GtkWidget *w, gpointer data)
1047{
1048 struct gui *ui = (struct gui *) data;
1049 struct gui_entry *ge;
1050
1051 ge = get_ge_from_cur_tab(ui);
1052 if (ge)
1053 start_job_clicked(w, ge);
Jens Axboe16ce5ad2012-03-12 11:56:09 +01001054}
1055
Jens Axboe781ccba2012-03-15 09:44:42 +01001056static void view_results(GtkWidget *w, gpointer data)
1057{
1058 struct gui *ui = (struct gui *) data;
1059 struct gfio_client *gc;
1060 struct gui_entry *ge;
1061
1062 ge = get_ge_from_cur_tab(ui);
1063 if (!ge)
1064 return;
1065
1066 if (ge->results_window)
1067 return;
1068
1069 gc = ge->client;
1070 if (gc && gc->nr_results)
1071 gfio_display_end_results(gc);
1072}
1073
Jens Axboea1e79722012-03-23 10:52:25 +01001074static void __update_graph_settings(struct gfio_graphs *g)
Jens Axboe8577f4f2012-03-09 19:28:27 +01001075{
1076 line_graph_set_data_count_limit(g->iops_graph, gfio_graph_limit);
Jens Axboea1e79722012-03-23 10:52:25 +01001077 graph_set_font(g->iops_graph, gfio_graph_font);
Jens Axboe8577f4f2012-03-09 19:28:27 +01001078 line_graph_set_data_count_limit(g->bandwidth_graph, gfio_graph_limit);
Jens Axboea1e79722012-03-23 10:52:25 +01001079 graph_set_font(g->bandwidth_graph, gfio_graph_font);
Jens Axboe8577f4f2012-03-09 19:28:27 +01001080}
1081
Jens Axboea1e79722012-03-23 10:52:25 +01001082static void ge_update_settings_fn(gpointer key, gpointer value, gpointer data)
Jens Axboeb98ab712012-03-21 12:48:32 +01001083{
1084 struct gui_entry *ge = (struct gui_entry *) value;
Jens Axboea1e79722012-03-23 10:52:25 +01001085 GdkEvent *ev;
Jens Axboeb98ab712012-03-21 12:48:32 +01001086
Jens Axboea1e79722012-03-23 10:52:25 +01001087 __update_graph_settings(&ge->graphs);
1088
1089 ev = gdk_event_new(GDK_EXPOSE);
Jens Axboeb6ab6a32012-03-26 19:34:15 +02001090 g_signal_emit_by_name(G_OBJECT(ge->graphs.drawing_area), GFIO_DRAW_EVENT, GTK_WIDGET(ge->graphs.drawing_area), ev, &ge->graphs);
Jens Axboea1e79722012-03-23 10:52:25 +01001091 gdk_event_free(ev);
Jens Axboeb98ab712012-03-21 12:48:32 +01001092}
1093
Jens Axboe8577f4f2012-03-09 19:28:27 +01001094static void update_graph_limits(void)
1095{
Jens Axboeb98ab712012-03-21 12:48:32 +01001096 struct gui *ui = &main_ui;
Jens Axboea1e79722012-03-23 10:52:25 +01001097 GdkEvent *ev;
Jens Axboe8577f4f2012-03-09 19:28:27 +01001098
Jens Axboea1e79722012-03-23 10:52:25 +01001099 __update_graph_settings(&ui->graphs);
Jens Axboe8577f4f2012-03-09 19:28:27 +01001100
Jens Axboea1e79722012-03-23 10:52:25 +01001101 ev = gdk_event_new(GDK_EXPOSE);
Jens Axboeb6ab6a32012-03-26 19:34:15 +02001102 g_signal_emit_by_name(G_OBJECT(ui->graphs.drawing_area), GFIO_DRAW_EVENT, GTK_WIDGET(ui->graphs.drawing_area), ev, &ui->graphs);
Jens Axboea1e79722012-03-23 10:52:25 +01001103 gdk_event_free(ev);
1104
1105 g_hash_table_foreach(ui->ge_hash, ge_update_settings_fn, NULL);
Jens Axboe8577f4f2012-03-09 19:28:27 +01001106}
1107
Jens Axboe46974a72012-03-02 19:34:13 +01001108static void preferences(GtkWidget *w, gpointer data)
1109{
Jens Axboef3e84402012-03-07 13:14:32 +01001110 GtkWidget *dialog, *frame, *box, **buttons, *vbox, *font;
Jens Axboe1cf6bca2012-03-09 20:20:17 +01001111 GtkWidget *hbox, *spin, *entry, *spin_int;
Jens Axboe6e02ad62012-03-20 12:25:36 +01001112 struct gui *ui = (struct gui *) data;
Jens Axboe46974a72012-03-02 19:34:13 +01001113 int i;
1114
1115 dialog = gtk_dialog_new_with_buttons("Preferences",
Jens Axboe6e02ad62012-03-20 12:25:36 +01001116 GTK_WINDOW(ui->window),
Jens Axboe46974a72012-03-02 19:34:13 +01001117 GTK_DIALOG_DESTROY_WITH_PARENT,
1118 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
1119 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
1120 NULL);
1121
Jens Axboe8577f4f2012-03-09 19:28:27 +01001122 frame = gtk_frame_new("Graphing");
Jens Axboef762cef2012-03-26 13:51:11 +02001123 vbox = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
1124 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
Jens Axboef3e84402012-03-07 13:14:32 +01001125 vbox = gtk_vbox_new(FALSE, 6);
1126 gtk_container_add(GTK_CONTAINER(frame), vbox);
1127
Jens Axboe1cf6bca2012-03-09 20:20:17 +01001128 hbox = gtk_hbox_new(FALSE, 5);
1129 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 5);
1130 entry = gtk_label_new("Font face to use for graph labels");
1131 gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 5);
1132
Jens Axboea1e79722012-03-23 10:52:25 +01001133 font = gtk_font_button_new_with_font(gfio_graph_font);
Jens Axboe1cf6bca2012-03-09 20:20:17 +01001134 gtk_box_pack_start(GTK_BOX(hbox), font, FALSE, FALSE, 5);
Jens Axboef3e84402012-03-07 13:14:32 +01001135
Jens Axboe8577f4f2012-03-09 19:28:27 +01001136 box = gtk_vbox_new(FALSE, 6);
1137 gtk_box_pack_start(GTK_BOX(vbox), box, FALSE, FALSE, 5);
1138
1139 hbox = gtk_hbox_new(FALSE, 5);
Jens Axboe1cf6bca2012-03-09 20:20:17 +01001140 gtk_box_pack_start(GTK_BOX(box), hbox, TRUE, TRUE, 5);
Jens Axboe8577f4f2012-03-09 19:28:27 +01001141 entry = gtk_label_new("Maximum number of data points in graph (seconds)");
1142 gtk_box_pack_start(GTK_BOX(hbox), entry, FALSE, FALSE, 5);
1143
Jens Axboec05d9052012-03-11 13:05:35 +01001144 spin = create_spinbutton(hbox, 10, 1000000, gfio_graph_limit);
Jens Axboe8577f4f2012-03-09 19:28:27 +01001145
Jens Axboe1cf6bca2012-03-09 20:20:17 +01001146 box = gtk_vbox_new(FALSE, 6);
1147 gtk_box_pack_start(GTK_BOX(vbox), box, FALSE, FALSE, 5);
1148
1149 hbox = gtk_hbox_new(FALSE, 5);
1150 gtk_box_pack_start(GTK_BOX(box), hbox, TRUE, TRUE, 5);
1151 entry = gtk_label_new("Client ETA request interval (msec)");
1152 gtk_box_pack_start(GTK_BOX(hbox), entry, FALSE, FALSE, 5);
1153
1154 spin_int = create_spinbutton(hbox, 100, 100000, gfio_client_ops.eta_msec);
Jens Axboea31d9fa2012-03-09 20:23:05 +01001155 frame = gtk_frame_new("Debug logging");
Jens Axboef762cef2012-03-26 13:51:11 +02001156 vbox = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
1157 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
Jens Axboea31d9fa2012-03-09 20:23:05 +01001158 vbox = gtk_vbox_new(FALSE, 6);
1159 gtk_container_add(GTK_CONTAINER(frame), vbox);
1160
1161 box = gtk_hbox_new(FALSE, 6);
1162 gtk_container_add(GTK_CONTAINER(vbox), box);
1163
1164 buttons = malloc(sizeof(GtkWidget *) * FD_DEBUG_MAX);
1165
1166 for (i = 0; i < FD_DEBUG_MAX; i++) {
1167 if (i == 7) {
1168 box = gtk_hbox_new(FALSE, 6);
1169 gtk_container_add(GTK_CONTAINER(vbox), box);
1170 }
1171
1172
1173 buttons[i] = gtk_check_button_new_with_label(debug_levels[i].name);
1174 gtk_widget_set_tooltip_text(buttons[i], debug_levels[i].help);
1175 gtk_box_pack_start(GTK_BOX(box), buttons[i], FALSE, FALSE, 6);
1176 }
1177
Jens Axboe46974a72012-03-02 19:34:13 +01001178 gtk_widget_show_all(dialog);
1179
1180 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT) {
1181 gtk_widget_destroy(dialog);
1182 return;
1183 }
1184
1185 for (i = 0; i < FD_DEBUG_MAX; i++) {
1186 int set;
1187
1188 set = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(buttons[i]));
1189 if (set)
1190 fio_debug |= (1UL << i);
1191 }
1192
Jens Axboef3e84402012-03-07 13:14:32 +01001193 gfio_graph_font = strdup(gtk_font_button_get_font_name(GTK_FONT_BUTTON(font)));
Jens Axboe8577f4f2012-03-09 19:28:27 +01001194 gfio_graph_limit = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spin));
1195 update_graph_limits();
Jens Axboe1cf6bca2012-03-09 20:20:17 +01001196 gfio_client_ops.eta_msec = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spin_int));
Jens Axboe8577f4f2012-03-09 19:28:27 +01001197
Jens Axboe46974a72012-03-02 19:34:13 +01001198 gtk_widget_destroy(dialog);
1199}
1200
Jens Axboe0420ba62012-02-29 11:16:52 +01001201static void about_dialog(GtkWidget *w, gpointer data)
1202{
Jens Axboe81e4ea62012-03-07 14:18:28 +01001203 const char *authors[] = {
1204 "Jens Axboe <axboe@kernel.dk>",
1205 "Stephen Carmeron <stephenmcameron@gmail.com>",
1206 NULL
1207 };
Jens Axboe84a72ed2012-03-07 14:24:57 +01001208 const char *license[] = {
1209 "Fio is free software; you can redistribute it and/or modify "
1210 "it under the terms of the GNU General Public License as published by "
1211 "the Free Software Foundation; either version 2 of the License, or "
1212 "(at your option) any later version.\n",
1213 "Fio is distributed in the hope that it will be useful, "
1214 "but WITHOUT ANY WARRANTY; without even the implied warranty of "
1215 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the "
1216 "GNU General Public License for more details.\n",
1217 "You should have received a copy of the GNU General Public License "
1218 "along with Fio; if not, write to the Free Software Foundation, Inc., "
1219 "51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n"
1220 };
1221 char *license_trans;
1222
1223 license_trans = g_strconcat(license[0], "\n", license[1], "\n",
1224 license[2], "\n", NULL);
Jens Axboe81e4ea62012-03-07 14:18:28 +01001225
Jens Axboe0420ba62012-02-29 11:16:52 +01001226 gtk_show_about_dialog(NULL,
1227 "program-name", "gfio",
1228 "comments", "Gtk2 UI for fio",
Jens Axboe84a72ed2012-03-07 14:24:57 +01001229 "license", license_trans,
Jens Axboe81e4ea62012-03-07 14:18:28 +01001230 "website", "http://git.kernel.dk/?p=fio.git;a=summary",
1231 "authors", authors,
Jens Axboe0420ba62012-02-29 11:16:52 +01001232 "version", fio_version_string,
Jens Axboe81e4ea62012-03-07 14:18:28 +01001233 "copyright", "© 2012 Jens Axboe <axboe@kernel.dk>",
Jens Axboe0420ba62012-02-29 11:16:52 +01001234 "logo-icon-name", "fio",
1235 /* Must be last: */
Jens Axboe81e4ea62012-03-07 14:18:28 +01001236 "wrap-license", TRUE,
Jens Axboe0420ba62012-02-29 11:16:52 +01001237 NULL);
Jens Axboe84a72ed2012-03-07 14:24:57 +01001238
Jens Axboe2f99deb2012-03-09 14:37:29 +01001239 g_free(license_trans);
Jens Axboe0420ba62012-02-29 11:16:52 +01001240}
1241
1242static GtkActionEntry menu_items[] = {
Jens Axboe46974a72012-03-02 19:34:13 +01001243 { "FileMenuAction", GTK_STOCK_FILE, "File", NULL, NULL, NULL},
Jens Axboe9b260bd2012-03-06 11:02:52 +01001244 { "ViewMenuAction", GTK_STOCK_FILE, "View", NULL, NULL, NULL},
Jens Axboe16ce5ad2012-03-12 11:56:09 +01001245 { "JobMenuAction", GTK_STOCK_FILE, "Job", NULL, NULL, NULL},
Jens Axboe46974a72012-03-02 19:34:13 +01001246 { "HelpMenuAction", GTK_STOCK_HELP, "Help", NULL, NULL, NULL},
Jens Axboe2f99deb2012-03-09 14:37:29 +01001247 { "NewFile", GTK_STOCK_NEW, "New", "<Control>N", NULL, G_CALLBACK(file_new) },
Jens Axboe16ce5ad2012-03-12 11:56:09 +01001248 { "CloseFile", GTK_STOCK_CLOSE, "Close", "<Control>W", NULL, G_CALLBACK(file_close) },
Jens Axboe46974a72012-03-02 19:34:13 +01001249 { "OpenFile", GTK_STOCK_OPEN, NULL, "<Control>O", NULL, G_CALLBACK(file_open) },
1250 { "SaveFile", GTK_STOCK_SAVE, NULL, "<Control>S", NULL, G_CALLBACK(file_save) },
1251 { "Preferences", GTK_STOCK_PREFERENCES, NULL, "<Control>p", NULL, G_CALLBACK(preferences) },
Jens Axboe9b260bd2012-03-06 11:02:52 +01001252 { "ViewLog", NULL, "Log", "<Control>l", NULL, G_CALLBACK(view_log) },
Jens Axboe781ccba2012-03-15 09:44:42 +01001253 { "ViewResults", NULL, "Results", "<Control>R", NULL, G_CALLBACK(view_results) },
Jens Axboebc271d82012-03-15 21:57:40 +01001254 { "ConnectJob", NULL, "Connect", "<Control>D", NULL, G_CALLBACK(connect_job_entry) },
Jens Axboe85dd01e2012-03-12 14:33:16 +01001255 { "EditJob", NULL, "Edit job", "<Control>E", NULL, G_CALLBACK(edit_job_entry) },
1256 { "SendJob", NULL, "Send job", "<Control>X", NULL, G_CALLBACK(send_job_entry) },
1257 { "StartJob", NULL, "Start job", "<Control>L", NULL, G_CALLBACK(start_job_entry) },
Jens Axboe46974a72012-03-02 19:34:13 +01001258 { "Quit", GTK_STOCK_QUIT, NULL, "<Control>Q", NULL, G_CALLBACK(quit_clicked) },
1259 { "About", GTK_STOCK_ABOUT, NULL, NULL, NULL, G_CALLBACK(about_dialog) },
Jens Axboe0420ba62012-02-29 11:16:52 +01001260};
Jens Axboe3e47bd22012-02-29 13:45:02 +01001261static gint nmenu_items = sizeof(menu_items) / sizeof(menu_items[0]);
Jens Axboe0420ba62012-02-29 11:16:52 +01001262
1263static const gchar *ui_string = " \
1264 <ui> \
1265 <menubar name=\"MainMenu\"> \
1266 <menu name=\"FileMenu\" action=\"FileMenuAction\"> \
Jens Axboe2f99deb2012-03-09 14:37:29 +01001267 <menuitem name=\"New\" action=\"NewFile\" /> \
Jens Axboebf641382012-03-15 13:46:16 +01001268 <menuitem name=\"Open\" action=\"OpenFile\" /> \
Jens Axboe16ce5ad2012-03-12 11:56:09 +01001269 <menuitem name=\"Close\" action=\"CloseFile\" /> \
Jens Axboe2f99deb2012-03-09 14:37:29 +01001270 <separator name=\"Separator1\"/> \
Jens Axboe0420ba62012-02-29 11:16:52 +01001271 <menuitem name=\"Save\" action=\"SaveFile\" /> \
Jens Axboe46974a72012-03-02 19:34:13 +01001272 <separator name=\"Separator2\"/> \
Jens Axboe2f99deb2012-03-09 14:37:29 +01001273 <menuitem name=\"Preferences\" action=\"Preferences\" /> \
1274 <separator name=\"Separator3\"/> \
Jens Axboe261f21d2012-03-12 14:58:22 +01001275 <placeholder name=\"FileRecentFiles\"/> \
1276 <separator name=\"Separator4\"/> \
Jens Axboe0420ba62012-02-29 11:16:52 +01001277 <menuitem name=\"Quit\" action=\"Quit\" /> \
1278 </menu> \
Jens Axboe16ce5ad2012-03-12 11:56:09 +01001279 <menu name=\"JobMenu\" action=\"JobMenuAction\"> \
Jens Axboe85dd01e2012-03-12 14:33:16 +01001280 <menuitem name=\"Connect\" action=\"ConnectJob\" /> \
Jens Axboe261f21d2012-03-12 14:58:22 +01001281 <separator name=\"Separator5\"/> \
Jens Axboe85dd01e2012-03-12 14:33:16 +01001282 <menuitem name=\"Edit job\" action=\"EditJob\" /> \
1283 <menuitem name=\"Send job\" action=\"SendJob\" /> \
Jens Axboe261f21d2012-03-12 14:58:22 +01001284 <separator name=\"Separator6\"/> \
Jens Axboe85dd01e2012-03-12 14:33:16 +01001285 <menuitem name=\"Start job\" action=\"StartJob\" /> \
Jens Axboe16ce5ad2012-03-12 11:56:09 +01001286 </menu>\
Jens Axboe9b260bd2012-03-06 11:02:52 +01001287 <menu name=\"ViewMenu\" action=\"ViewMenuAction\"> \
Jens Axboe781ccba2012-03-15 09:44:42 +01001288 <menuitem name=\"Results\" action=\"ViewResults\" /> \
1289 <separator name=\"Separator7\"/> \
Jens Axboe9b260bd2012-03-06 11:02:52 +01001290 <menuitem name=\"Log\" action=\"ViewLog\" /> \
1291 </menu>\
Jens Axboe0420ba62012-02-29 11:16:52 +01001292 <menu name=\"Help\" action=\"HelpMenuAction\"> \
1293 <menuitem name=\"About\" action=\"About\" /> \
1294 </menu> \
1295 </menubar> \
1296 </ui> \
1297";
1298
Jens Axboe4cbe7212012-03-06 13:36:17 +01001299static GtkWidget *get_menubar_menu(GtkWidget *window, GtkUIManager *ui_manager,
1300 struct gui *ui)
Jens Axboe0420ba62012-02-29 11:16:52 +01001301{
Jens Axboeca664f42012-03-14 19:49:40 +01001302 GtkActionGroup *action_group;
Jens Axboe0420ba62012-02-29 11:16:52 +01001303 GError *error = 0;
1304
1305 action_group = gtk_action_group_new("Menu");
Jens Axboe4cbe7212012-03-06 13:36:17 +01001306 gtk_action_group_add_actions(action_group, menu_items, nmenu_items, ui);
Jens Axboe0420ba62012-02-29 11:16:52 +01001307
1308 gtk_ui_manager_insert_action_group(ui_manager, action_group, 0);
1309 gtk_ui_manager_add_ui_from_string(GTK_UI_MANAGER(ui_manager), ui_string, -1, &error);
1310
1311 gtk_window_add_accel_group(GTK_WINDOW(window), gtk_ui_manager_get_accel_group(ui_manager));
Jens Axboe02421e62012-03-12 12:05:50 +01001312
Jens Axboe0420ba62012-02-29 11:16:52 +01001313 return gtk_ui_manager_get_widget(ui_manager, "/MainMenu");
1314}
1315
1316void gfio_ui_setup(GtkSettings *settings, GtkWidget *menubar,
Jens Axboe1252d8f2012-03-21 11:13:31 +01001317 GtkWidget *vbox, GtkUIManager *ui_manager)
Jens Axboe0420ba62012-02-29 11:16:52 +01001318{
Jens Axboe1252d8f2012-03-21 11:13:31 +01001319 gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 0);
Jens Axboe0420ba62012-02-29 11:16:52 +01001320}
1321
Jens Axboec80b74b2012-03-12 10:23:28 +01001322static void combo_entry_changed(GtkComboBox *box, gpointer data)
1323{
1324 struct gui_entry *ge = (struct gui_entry *) data;
1325 gint index;
1326
1327 index = gtk_combo_box_get_active(box);
1328
1329 multitext_set_entry(&ge->eta.iotype, index);
Jens Axboe99d633a2012-03-15 15:55:04 +01001330 multitext_set_entry(&ge->eta.bs, index);
Jens Axboec80b74b2012-03-12 10:23:28 +01001331 multitext_set_entry(&ge->eta.ioengine, index);
1332 multitext_set_entry(&ge->eta.iodepth, index);
1333}
1334
1335static void combo_entry_destroy(GtkWidget *widget, gpointer data)
1336{
1337 struct gui_entry *ge = (struct gui_entry *) data;
1338
1339 multitext_free(&ge->eta.iotype);
Jens Axboe99d633a2012-03-15 15:55:04 +01001340 multitext_free(&ge->eta.bs);
Jens Axboec80b74b2012-03-12 10:23:28 +01001341 multitext_free(&ge->eta.ioengine);
1342 multitext_free(&ge->eta.iodepth);
1343}
1344
Jens Axboe2f99deb2012-03-09 14:37:29 +01001345static GtkWidget *new_client_page(struct gui_entry *ge)
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001346{
Jens Axboe2f99deb2012-03-09 14:37:29 +01001347 GtkWidget *main_vbox, *probe, *probe_frame, *probe_box;
Jens Axboe65476332012-03-13 10:37:04 +01001348 GtkWidget *scrolled_window, *bottom_align, *top_align, *top_vbox;
Jens Axboe0420ba62012-02-29 11:16:52 +01001349
Jens Axboe2f99deb2012-03-09 14:37:29 +01001350 main_vbox = gtk_vbox_new(FALSE, 3);
Stephen M. Cameron45032dd2012-02-24 08:17:31 +01001351
Jens Axboe65476332012-03-13 10:37:04 +01001352 top_align = gtk_alignment_new(0, 0, 1, 0);
1353 top_vbox = gtk_vbox_new(FALSE, 3);
1354 gtk_container_add(GTK_CONTAINER(top_align), top_vbox);
1355 gtk_box_pack_start(GTK_BOX(main_vbox), top_align, FALSE, FALSE, 0);
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +01001356
Jens Axboe3e47bd22012-02-29 13:45:02 +01001357 probe = gtk_frame_new("Job");
Jens Axboe2f99deb2012-03-09 14:37:29 +01001358 gtk_box_pack_start(GTK_BOX(main_vbox), probe, FALSE, FALSE, 3);
Jens Axboe843ad232012-02-29 11:44:53 +01001359 probe_frame = gtk_vbox_new(FALSE, 3);
1360 gtk_container_add(GTK_CONTAINER(probe), probe_frame);
1361
1362 probe_box = gtk_hbox_new(FALSE, 3);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001363 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, FALSE, FALSE, 3);
1364 ge->probe.hostname = new_info_label_in_frame(probe_box, "Host");
1365 ge->probe.os = new_info_label_in_frame(probe_box, "OS");
1366 ge->probe.arch = new_info_label_in_frame(probe_box, "Architecture");
1367 ge->probe.fio_ver = new_info_label_in_frame(probe_box, "Fio version");
Jens Axboe843ad232012-02-29 11:44:53 +01001368
Jens Axboe3e47bd22012-02-29 13:45:02 +01001369 probe_box = gtk_hbox_new(FALSE, 3);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001370 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, FALSE, FALSE, 3);
1371
Jens Axboe3863d1a2012-03-09 17:39:05 +01001372 ge->eta.names = new_combo_entry_in_frame(probe_box, "Jobs");
Jens Axboec80b74b2012-03-12 10:23:28 +01001373 g_signal_connect(ge->eta.names, "changed", G_CALLBACK(combo_entry_changed), ge);
1374 g_signal_connect(ge->eta.names, "destroy", G_CALLBACK(combo_entry_destroy), ge);
1375 ge->eta.iotype.entry = new_info_entry_in_frame(probe_box, "IO");
Jens Axboe99d633a2012-03-15 15:55:04 +01001376 ge->eta.bs.entry = new_info_entry_in_frame(probe_box, "Blocksize (Read/Write)");
Jens Axboec80b74b2012-03-12 10:23:28 +01001377 ge->eta.ioengine.entry = new_info_entry_in_frame(probe_box, "IO Engine");
1378 ge->eta.iodepth.entry = new_info_entry_in_frame(probe_box, "IO Depth");
Jens Axboe2f99deb2012-03-09 14:37:29 +01001379 ge->eta.jobs = new_info_entry_in_frame(probe_box, "Jobs");
1380 ge->eta.files = new_info_entry_in_frame(probe_box, "Open files");
1381
1382 probe_box = gtk_hbox_new(FALSE, 3);
1383 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, FALSE, FALSE, 3);
1384 ge->eta.read_bw = new_info_entry_in_frame(probe_box, "Read BW");
1385 ge->eta.read_iops = new_info_entry_in_frame(probe_box, "IOPS");
1386 ge->eta.write_bw = new_info_entry_in_frame(probe_box, "Write BW");
1387 ge->eta.write_iops = new_info_entry_in_frame(probe_box, "IOPS");
1388
1389 /*
1390 * Only add this if we have a commit rate
1391 */
1392#if 0
1393 probe_box = gtk_hbox_new(FALSE, 3);
Jens Axboe3e47bd22012-02-29 13:45:02 +01001394 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, TRUE, FALSE, 3);
Jens Axboe807f9972012-03-02 10:25:24 +01001395
Jens Axboe2f99deb2012-03-09 14:37:29 +01001396 ge->eta.cr_bw = new_info_label_in_frame(probe_box, "Commit BW");
1397 ge->eta.cr_iops = new_info_label_in_frame(probe_box, "Commit IOPS");
1398
1399 ge->eta.cw_bw = new_info_label_in_frame(probe_box, "Commit BW");
1400 ge->eta.cw_iops = new_info_label_in_frame(probe_box, "Commit IOPS");
1401#endif
1402
1403 /*
1404 * Set up a drawing area and IOPS and bandwidth graphs
1405 */
Jens Axboe2f99deb2012-03-09 14:37:29 +01001406 ge->graphs.drawing_area = gtk_drawing_area_new();
Jens Axboe2f99deb2012-03-09 14:37:29 +01001407 gtk_widget_set_size_request(GTK_WIDGET(ge->graphs.drawing_area),
Stephen M. Cameron57f9d282012-03-11 11:36:51 +01001408 DRAWING_AREA_XDIM, DRAWING_AREA_YDIM);
Jens Axboe2a95f712012-04-16 11:48:45 +02001409 gtk_widget_modify_bg(ge->graphs.drawing_area, GTK_STATE_NORMAL, &gfio_color_lightyellow);
Jens Axboeb6ab6a32012-03-26 19:34:15 +02001410 g_signal_connect(G_OBJECT(ge->graphs.drawing_area), GFIO_DRAW_EVENT,
Jens Axboe2f99deb2012-03-09 14:37:29 +01001411 G_CALLBACK(on_expose_drawing_area), &ge->graphs);
1412 g_signal_connect(G_OBJECT(ge->graphs.drawing_area), "configure_event",
1413 G_CALLBACK(on_config_drawing_area), &ge->graphs);
Jens Axboe65476332012-03-13 10:37:04 +01001414 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
1415 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
Jens Axboe2f99deb2012-03-09 14:37:29 +01001416 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
Jens Axboe65476332012-03-13 10:37:04 +01001417 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled_window),
Jens Axboe2f99deb2012-03-09 14:37:29 +01001418 ge->graphs.drawing_area);
Jens Axboe65476332012-03-13 10:37:04 +01001419 gtk_box_pack_start(GTK_BOX(main_vbox), scrolled_window, TRUE, TRUE, 0);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001420
1421 setup_graphs(&ge->graphs);
1422
1423 /*
Jens Axboe3c3ed072012-03-27 09:12:39 +02001424 * Set up alignments for widgets at the bottom of ui,
Jens Axboe2f99deb2012-03-09 14:37:29 +01001425 * align bottom left, expand horizontally but not vertically
1426 */
Jens Axboe65476332012-03-13 10:37:04 +01001427 bottom_align = gtk_alignment_new(0, 1, 1, 0);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001428 ge->buttonbox = gtk_hbox_new(FALSE, 0);
Jens Axboe65476332012-03-13 10:37:04 +01001429 gtk_container_add(GTK_CONTAINER(bottom_align), ge->buttonbox);
1430 gtk_box_pack_start(GTK_BOX(main_vbox), bottom_align, FALSE, FALSE, 0);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001431
Jens Axboe05775432012-03-21 14:07:11 +01001432 add_buttons(ge, buttonspeclist, ARRAY_SIZE(buttonspeclist));
Jens Axboe2f99deb2012-03-09 14:37:29 +01001433
1434 /*
1435 * Set up thread status progress bar
1436 */
1437 ge->thread_status_pb = gtk_progress_bar_new();
1438 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(ge->thread_status_pb), 0.0);
1439 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(ge->thread_status_pb), "No connections");
1440 gtk_container_add(GTK_CONTAINER(ge->buttonbox), ge->thread_status_pb);
1441
1442
1443 return main_vbox;
1444}
1445
1446static GtkWidget *new_main_page(struct gui *ui)
1447{
1448 GtkWidget *main_vbox, *probe, *probe_frame, *probe_box;
Jens Axboe65476332012-03-13 10:37:04 +01001449 GtkWidget *scrolled_window, *bottom_align, *top_align, *top_vbox;
Jens Axboe2f99deb2012-03-09 14:37:29 +01001450
1451 main_vbox = gtk_vbox_new(FALSE, 3);
1452
1453 /*
1454 * Set up alignments for widgets at the top of ui,
1455 * align top left, expand horizontally but not vertically
1456 */
Jens Axboe65476332012-03-13 10:37:04 +01001457 top_align = gtk_alignment_new(0, 0, 1, 0);
1458 top_vbox = gtk_vbox_new(FALSE, 0);
1459 gtk_container_add(GTK_CONTAINER(top_align), top_vbox);
1460 gtk_box_pack_start(GTK_BOX(main_vbox), top_align, FALSE, FALSE, 0);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001461
1462 probe = gtk_frame_new("Run statistics");
1463 gtk_box_pack_start(GTK_BOX(main_vbox), probe, FALSE, FALSE, 3);
1464 probe_frame = gtk_vbox_new(FALSE, 3);
1465 gtk_container_add(GTK_CONTAINER(probe), probe_frame);
Jens Axboe3e47bd22012-02-29 13:45:02 +01001466
1467 probe_box = gtk_hbox_new(FALSE, 3);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001468 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, FALSE, FALSE, 3);
Jens Axboe3863d1a2012-03-09 17:39:05 +01001469 ui->eta.jobs = new_info_entry_in_frame(probe_box, "Running");
Jens Axboeca850992012-03-05 20:04:43 +01001470 ui->eta.read_bw = new_info_entry_in_frame(probe_box, "Read BW");
1471 ui->eta.read_iops = new_info_entry_in_frame(probe_box, "IOPS");
1472 ui->eta.write_bw = new_info_entry_in_frame(probe_box, "Write BW");
1473 ui->eta.write_iops = new_info_entry_in_frame(probe_box, "IOPS");
Jens Axboe807f9972012-03-02 10:25:24 +01001474
1475 /*
1476 * Only add this if we have a commit rate
1477 */
1478#if 0
1479 probe_box = gtk_hbox_new(FALSE, 3);
1480 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, TRUE, FALSE, 3);
1481
Jens Axboe3e47bd22012-02-29 13:45:02 +01001482 ui->eta.cr_bw = new_info_label_in_frame(probe_box, "Commit BW");
1483 ui->eta.cr_iops = new_info_label_in_frame(probe_box, "Commit IOPS");
1484
Jens Axboe3e47bd22012-02-29 13:45:02 +01001485 ui->eta.cw_bw = new_info_label_in_frame(probe_box, "Commit BW");
1486 ui->eta.cw_iops = new_info_label_in_frame(probe_box, "Commit IOPS");
Jens Axboe807f9972012-03-02 10:25:24 +01001487#endif
Jens Axboe3e47bd22012-02-29 13:45:02 +01001488
Stephen M. Cameron45032dd2012-02-24 08:17:31 +01001489 /*
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001490 * Set up a drawing area and IOPS and bandwidth graphs
Stephen M. Cameron736f2df2012-02-24 08:17:32 +01001491 */
Jens Axboe2f99deb2012-03-09 14:37:29 +01001492 ui->graphs.drawing_area = gtk_drawing_area_new();
Jens Axboe2f99deb2012-03-09 14:37:29 +01001493 gtk_widget_set_size_request(GTK_WIDGET(ui->graphs.drawing_area),
Stephen M. Cameron57f9d282012-03-11 11:36:51 +01001494 DRAWING_AREA_XDIM, DRAWING_AREA_YDIM);
Jens Axboe2a95f712012-04-16 11:48:45 +02001495 gtk_widget_modify_bg(ui->graphs.drawing_area, GTK_STATE_NORMAL, &gfio_color_lightyellow);
Jens Axboeb6ab6a32012-03-26 19:34:15 +02001496 g_signal_connect(G_OBJECT(ui->graphs.drawing_area), GFIO_DRAW_EVENT,
Jens Axboe2f99deb2012-03-09 14:37:29 +01001497 G_CALLBACK(on_expose_drawing_area), &ui->graphs);
1498 g_signal_connect(G_OBJECT(ui->graphs.drawing_area), "configure_event",
1499 G_CALLBACK(on_config_drawing_area), &ui->graphs);
Jens Axboe65476332012-03-13 10:37:04 +01001500 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
1501 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
Stephen M. Cameron736f2df2012-02-24 08:17:32 +01001502 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
Jens Axboe65476332012-03-13 10:37:04 +01001503 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled_window),
Jens Axboe2f99deb2012-03-09 14:37:29 +01001504 ui->graphs.drawing_area);
Jens Axboe65476332012-03-13 10:37:04 +01001505 gtk_box_pack_start(GTK_BOX(main_vbox), scrolled_window,
Stephen M. Camerone1645342012-02-24 08:17:32 +01001506 TRUE, TRUE, 0);
Stephen M. Cameron736f2df2012-02-24 08:17:32 +01001507
Jens Axboe2f99deb2012-03-09 14:37:29 +01001508 setup_graphs(&ui->graphs);
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001509
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +01001510 /*
Jens Axboe3c3ed072012-03-27 09:12:39 +02001511 * Set up alignments for widgets at the bottom of ui,
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +01001512 * align bottom left, expand horizontally but not vertically
1513 */
Jens Axboe65476332012-03-13 10:37:04 +01001514 bottom_align = gtk_alignment_new(0, 1, 1, 0);
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +01001515 ui->buttonbox = gtk_hbox_new(FALSE, 0);
Jens Axboe65476332012-03-13 10:37:04 +01001516 gtk_container_add(GTK_CONTAINER(bottom_align), ui->buttonbox);
1517 gtk_box_pack_start(GTK_BOX(main_vbox), bottom_align, FALSE, FALSE, 0);
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +01001518
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001519 /*
1520 * Set up thread status progress bar
1521 */
1522 ui->thread_status_pb = gtk_progress_bar_new();
1523 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(ui->thread_status_pb), 0.0);
Jens Axboe8663ea62012-03-02 14:04:30 +01001524 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(ui->thread_status_pb), "No connections");
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001525 gtk_container_add(GTK_CONTAINER(ui->buttonbox), ui->thread_status_pb);
1526
Jens Axboe2f99deb2012-03-09 14:37:29 +01001527 return main_vbox;
1528}
1529
1530static gboolean notebook_switch_page(GtkNotebook *notebook, GtkWidget *widget,
1531 guint page, gpointer data)
1532
1533{
Jens Axboe02421e62012-03-12 12:05:50 +01001534 struct gui *ui = (struct gui *) data;
Jens Axboe85dd01e2012-03-12 14:33:16 +01001535 struct gui_entry *ge;
Jens Axboe02421e62012-03-12 12:05:50 +01001536
Jens Axboe85dd01e2012-03-12 14:33:16 +01001537 if (!page) {
1538 set_job_menu_visible(ui, 0);
Jens Axboe781ccba2012-03-15 09:44:42 +01001539 set_view_results_visible(ui, 0);
Jens Axboe85dd01e2012-03-12 14:33:16 +01001540 return TRUE;
1541 }
1542
1543 set_job_menu_visible(ui, 1);
Jens Axboe6e02ad62012-03-20 12:25:36 +01001544 ge = get_ge_from_page(ui, page, NULL);
Jens Axboe85dd01e2012-03-12 14:33:16 +01001545 if (ge)
1546 update_button_states(ui, ge);
1547
Jens Axboe2f99deb2012-03-09 14:37:29 +01001548 return TRUE;
1549}
1550
Jens Axboe38634cb2012-03-13 12:26:41 +01001551static gint compare_recent_items(GtkRecentInfo *a, GtkRecentInfo *b)
1552{
1553 time_t time_a = gtk_recent_info_get_visited(a);
1554 time_t time_b = gtk_recent_info_get_visited(b);
1555
1556 return time_b - time_a;
1557}
1558
1559static void add_recent_file_items(struct gui *ui)
1560{
1561 const gchar *gfio = g_get_application_name();
1562 GList *items, *item;
1563 int i = 0;
1564
1565 if (ui->recent_ui_id) {
1566 gtk_ui_manager_remove_ui(ui->uimanager, ui->recent_ui_id);
1567 gtk_ui_manager_ensure_update(ui->uimanager);
1568 }
1569 ui->recent_ui_id = gtk_ui_manager_new_merge_id(ui->uimanager);
1570
1571 if (ui->actiongroup) {
1572 gtk_ui_manager_remove_action_group(ui->uimanager, ui->actiongroup);
1573 g_object_unref(ui->actiongroup);
1574 }
1575 ui->actiongroup = gtk_action_group_new("RecentFileActions");
1576
1577 gtk_ui_manager_insert_action_group(ui->uimanager, ui->actiongroup, -1);
1578
1579 items = gtk_recent_manager_get_items(ui->recentmanager);
1580 items = g_list_sort(items, (GCompareFunc) compare_recent_items);
1581
1582 for (item = items; item && item->data; item = g_list_next(item)) {
1583 GtkRecentInfo *info = (GtkRecentInfo *) item->data;
1584 gchar *action_name;
1585 const gchar *label;
1586 GtkAction *action;
1587
1588 if (!gtk_recent_info_has_application(info, gfio))
1589 continue;
1590
1591 /*
1592 * We only support local files for now
1593 */
1594 if (!gtk_recent_info_is_local(info) || !gtk_recent_info_exists(info))
1595 continue;
1596
1597 action_name = g_strdup_printf("RecentFile%u", i++);
1598 label = gtk_recent_info_get_display_name(info);
1599
1600 action = g_object_new(GTK_TYPE_ACTION,
1601 "name", action_name,
1602 "label", label, NULL);
1603
1604 g_object_set_data_full(G_OBJECT(action), "gtk-recent-info",
1605 gtk_recent_info_ref(info),
1606 (GDestroyNotify) gtk_recent_info_unref);
1607
1608
1609 g_signal_connect(action, "activate", G_CALLBACK(recent_open), ui);
1610
1611 gtk_action_group_add_action(ui->actiongroup, action);
1612 g_object_unref(action);
1613
1614 gtk_ui_manager_add_ui(ui->uimanager, ui->recent_ui_id,
1615 "/MainMenu/FileMenu/FileRecentFiles",
1616 label, action_name,
1617 GTK_UI_MANAGER_MENUITEM, FALSE);
1618
1619 g_free(action_name);
1620
1621 if (i == 8)
1622 break;
1623 }
1624
1625 g_list_foreach(items, (GFunc) gtk_recent_info_unref, NULL);
1626 g_list_free(items);
1627}
1628
Jens Axboea6790902012-03-13 15:16:11 +01001629static void drag_and_drop_received(GtkWidget *widget, GdkDragContext *ctx,
Jens Axboe6e02ad62012-03-20 12:25:36 +01001630 gint x, gint y, GtkSelectionData *seldata,
1631 guint info, guint time, gpointer *data)
Jens Axboea6790902012-03-13 15:16:11 +01001632{
Jens Axboe6e02ad62012-03-20 12:25:36 +01001633 struct gui *ui = (struct gui *) data;
Jens Axboea6790902012-03-13 15:16:11 +01001634 gchar **uris;
1635 GtkWidget *source;
Jens Axboea6790902012-03-13 15:16:11 +01001636
1637 source = gtk_drag_get_source_widget(ctx);
1638 if (source && widget == gtk_widget_get_toplevel(source)) {
1639 gtk_drag_finish(ctx, FALSE, FALSE, time);
1640 return;
1641 }
1642
Jens Axboe6e02ad62012-03-20 12:25:36 +01001643 uris = gtk_selection_data_get_uris(seldata);
Jens Axboea6790902012-03-13 15:16:11 +01001644 if (!uris) {
1645 gtk_drag_finish(ctx, FALSE, FALSE, time);
1646 return;
1647 }
1648
Jens Axboe0cf3ece2012-03-21 10:15:20 +01001649 if (uris[0])
1650 do_file_open_with_tab(ui, uris[0]);
Jens Axboea6790902012-03-13 15:16:11 +01001651
1652 gtk_drag_finish(ctx, TRUE, FALSE, time);
1653 g_strfreev(uris);
1654}
1655
Jens Axboe2f99deb2012-03-09 14:37:29 +01001656static void init_ui(int *argc, char **argv[], struct gui *ui)
1657{
1658 GtkSettings *settings;
Jens Axboe02421e62012-03-12 12:05:50 +01001659 GtkWidget *vbox;
Jens Axboe2f99deb2012-03-09 14:37:29 +01001660
1661 /* Magical g*thread incantation, you just need this thread stuff.
1662 * Without it, the update that happens in gfio_update_thread_status
1663 * doesn't really happen in a timely fashion, you need expose events
1664 */
1665 if (!g_thread_supported())
1666 g_thread_init(NULL);
1667 gdk_threads_init();
1668
1669 gtk_init(argc, argv);
1670 settings = gtk_settings_get_default();
1671 gtk_settings_set_long_property(settings, "gtk_tooltip_timeout", 10, "gfio setting");
1672 g_type_init();
Jens Axboe2a95f712012-04-16 11:48:45 +02001673 gdk_color_parse("#ffffee", &gfio_color_lightyellow);
Jens Axboe1252d8f2012-03-21 11:13:31 +01001674 gdk_color_parse("white", &gfio_color_white);
Jens Axboe3c3ed072012-03-27 09:12:39 +02001675
Jens Axboe2f99deb2012-03-09 14:37:29 +01001676 ui->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
Stephen M. Cameron814479d2012-03-15 07:58:14 +01001677 gtk_window_set_title(GTK_WINDOW(ui->window), "fio");
Jens Axboe2f99deb2012-03-09 14:37:29 +01001678 gtk_window_set_default_size(GTK_WINDOW(ui->window), 1024, 768);
1679
Jens Axboe6e02ad62012-03-20 12:25:36 +01001680 g_signal_connect(ui->window, "delete-event", G_CALLBACK(quit_clicked), ui);
1681 g_signal_connect(ui->window, "destroy", G_CALLBACK(quit_clicked), ui);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001682
1683 ui->vbox = gtk_vbox_new(FALSE, 0);
1684 gtk_container_add(GTK_CONTAINER(ui->window), ui->vbox);
1685
Jens Axboe02421e62012-03-12 12:05:50 +01001686 ui->uimanager = gtk_ui_manager_new();
1687 ui->menu = get_menubar_menu(ui->window, ui->uimanager, ui);
1688 gfio_ui_setup(settings, ui->menu, ui->vbox, ui->uimanager);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001689
Jens Axboe38634cb2012-03-13 12:26:41 +01001690 ui->recentmanager = gtk_recent_manager_get_default();
1691 add_recent_file_items(ui);
1692
Jens Axboe2f99deb2012-03-09 14:37:29 +01001693 ui->notebook = gtk_notebook_new();
1694 g_signal_connect(ui->notebook, "switch-page", G_CALLBACK(notebook_switch_page), ui);
Jens Axboeb870c312012-03-09 17:22:01 +01001695 gtk_notebook_set_scrollable(GTK_NOTEBOOK(ui->notebook), 1);
Jens Axboe0aa928c2012-03-09 17:24:07 +01001696 gtk_notebook_popup_enable(GTK_NOTEBOOK(ui->notebook));
Jens Axboe2f99deb2012-03-09 14:37:29 +01001697 gtk_container_add(GTK_CONTAINER(ui->vbox), ui->notebook);
1698
1699 vbox = new_main_page(ui);
Jens Axboe0cf3ece2012-03-21 10:15:20 +01001700 gtk_drag_dest_set(GTK_WIDGET(ui->window), GTK_DEST_DEFAULT_ALL, NULL, 1, GDK_ACTION_COPY);
Jens Axboea6790902012-03-13 15:16:11 +01001701 gtk_drag_dest_add_uri_targets(GTK_WIDGET(ui->window));
1702 g_signal_connect(ui->window, "drag-data-received", G_CALLBACK(drag_and_drop_received), ui);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001703
1704 gtk_notebook_append_page(GTK_NOTEBOOK(ui->notebook), vbox, gtk_label_new("Main"));
1705
Jens Axboe9b260bd2012-03-06 11:02:52 +01001706 gfio_ui_setup_log(ui);
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001707
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001708 gtk_widget_show_all(ui->window);
1709}
1710
Stephen M. Cameron8232e282012-02-24 08:17:31 +01001711int main(int argc, char *argv[], char *envp[])
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001712{
Stephen M. Cameron8232e282012-02-24 08:17:31 +01001713 if (initialize_fio(envp))
1714 return 1;
Jens Axboe0420ba62012-02-29 11:16:52 +01001715 if (fio_init_options())
1716 return 1;
Stephen M. Camerona1820202012-02-24 08:17:31 +01001717
Jens Axboe753e9e62012-03-24 20:22:29 +01001718 gopt_init();
1719
Jens Axboe2f99deb2012-03-09 14:37:29 +01001720 memset(&main_ui, 0, sizeof(main_ui));
Jens Axboeb98ab712012-03-21 12:48:32 +01001721 main_ui.ge_hash = g_hash_table_new(g_int_hash, g_int_equal);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001722
1723 init_ui(&argc, &argv, &main_ui);
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +01001724
Stephen M. Cameron2839f0c2012-02-24 08:17:31 +01001725 gdk_threads_enter();
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001726 gtk_main();
Stephen M. Cameron2839f0c2012-02-24 08:17:31 +01001727 gdk_threads_leave();
Jens Axboeb98ab712012-03-21 12:48:32 +01001728
1729 g_hash_table_destroy(main_ui.ge_hash);
Jens Axboe753e9e62012-03-24 20:22:29 +01001730
1731 gopt_exit();
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001732 return 0;
1733}