blob: d1d1313bdaefc279c5010bff27431138541a7da8 [file] [log] [blame]
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001/*
2 * gfio - gui front end for fio - the flexible io tester
3 *
4 * 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;
44const char *gfio_graph_font;
Jens Axboe3e47bd22012-02-29 13:45:02 +010045
Stephen M. Cameronf3074002012-02-24 08:17:30 +010046typedef void (*clickfunction)(GtkWidget *widget, gpointer data);
47
Jens Axboe3e47bd22012-02-29 13:45:02 +010048static void connect_clicked(GtkWidget *widget, gpointer data);
Stephen M. Cameronf3074002012-02-24 08:17:30 +010049static void start_job_clicked(GtkWidget *widget, gpointer data);
Jens Axboeb9d2f302012-03-08 20:36:28 +010050static void send_clicked(GtkWidget *widget, gpointer data);
Stephen M. Cameronf3074002012-02-24 08:17:30 +010051
52static struct button_spec {
53 const char *buttontext;
54 clickfunction f;
Jens Axboe014f4022012-03-15 14:03:01 +010055 const char *tooltiptext[2];
56 const int start_sensitive;
Stephen M. Cameronf3074002012-02-24 08:17:30 +010057} buttonspeclist[] = {
Jens Axboe53e0e852012-03-15 19:38:01 +010058 {
59 .buttontext = "Connect",
60 .f = connect_clicked,
61 .tooltiptext = { "Disconnect from host", "Connect to host" },
62 .start_sensitive = 1,
63 },
64 {
65 .buttontext = "Send",
66 .f = send_clicked,
67 .tooltiptext = { "Send job description to host", NULL },
68 .start_sensitive = 0,
69 },
70 {
71 .buttontext = "Start Job",
72 .f = start_job_clicked,
73 .tooltiptext = { "Start the current job on the server", NULL },
74 .start_sensitive = 0,
75 },
Jens Axboee0681f32012-03-06 12:14:42 +010076};
77
Jens Axboe2f99deb2012-03-09 14:37:29 +010078static struct graph *setup_iops_graph(void)
Jens Axboe2fd3bb02012-03-07 08:07:39 +010079{
Jens Axboe2f99deb2012-03-09 14:37:29 +010080 struct graph *g;
81
82 g = graph_new(DRAWING_AREA_XDIM / 2.0, DRAWING_AREA_YDIM, gfio_graph_font);
Jens Axboed8fbeef2012-03-14 10:25:44 +010083 graph_title(g, "IOPS (IOs/sec)");
Jens Axboe2f99deb2012-03-09 14:37:29 +010084 graph_x_title(g, "Time (secs)");
Jens Axboe2f99deb2012-03-09 14:37:29 +010085 graph_add_label(g, "Read IOPS");
86 graph_add_label(g, "Write IOPS");
87 graph_set_color(g, "Read IOPS", 0.13, 0.54, 0.13);
88 graph_set_color(g, "Write IOPS", 1.0, 0.0, 0.0);
Jens Axboe8577f4f2012-03-09 19:28:27 +010089 line_graph_set_data_count_limit(g, gfio_graph_limit);
Jens Axboed8fbeef2012-03-14 10:25:44 +010090 graph_add_extra_space(g, 0.0, 0.0, 0.0, 0.0);
Jens Axboe2f99deb2012-03-09 14:37:29 +010091 return g;
Jens Axboe2fd3bb02012-03-07 08:07:39 +010092}
93
Jens Axboe2f99deb2012-03-09 14:37:29 +010094static struct graph *setup_bandwidth_graph(void)
Jens Axboe2fd3bb02012-03-07 08:07:39 +010095{
Jens Axboe2f99deb2012-03-09 14:37:29 +010096 struct graph *g;
97
98 g = graph_new(DRAWING_AREA_XDIM / 2.0, DRAWING_AREA_YDIM, gfio_graph_font);
Jens Axboed8fbeef2012-03-14 10:25:44 +010099 graph_title(g, "Bandwidth (bytes/sec)");
Jens Axboe2f99deb2012-03-09 14:37:29 +0100100 graph_x_title(g, "Time (secs)");
Jens Axboe2f99deb2012-03-09 14:37:29 +0100101 graph_add_label(g, "Read Bandwidth");
102 graph_add_label(g, "Write Bandwidth");
103 graph_set_color(g, "Read Bandwidth", 0.13, 0.54, 0.13);
104 graph_set_color(g, "Write Bandwidth", 1.0, 0.0, 0.0);
Jens Axboed8fbeef2012-03-14 10:25:44 +0100105 graph_set_base_offset(g, 1);
Jens Axboe2f99deb2012-03-09 14:37:29 +0100106 line_graph_set_data_count_limit(g, 100);
Jens Axboed8fbeef2012-03-14 10:25:44 +0100107 graph_add_extra_space(g, 0.0, 0.0, 0.0, 0.0);
Jens Axboe2f99deb2012-03-09 14:37:29 +0100108 return g;
Jens Axboe2fd3bb02012-03-07 08:07:39 +0100109}
110
Jens Axboe2f99deb2012-03-09 14:37:29 +0100111static void setup_graphs(struct gfio_graphs *g)
Jens Axboe8663ea62012-03-02 14:04:30 +0100112{
Jens Axboe2f99deb2012-03-09 14:37:29 +0100113 g->iops_graph = setup_iops_graph();
114 g->bandwidth_graph = setup_bandwidth_graph();
115}
116
Jens Axboe1252d8f2012-03-21 11:13:31 +0100117void clear_ge_ui_info(struct gui_entry *ge)
Jens Axboe2f99deb2012-03-09 14:37:29 +0100118{
119 gtk_label_set_text(GTK_LABEL(ge->probe.hostname), "");
120 gtk_label_set_text(GTK_LABEL(ge->probe.os), "");
121 gtk_label_set_text(GTK_LABEL(ge->probe.arch), "");
122 gtk_label_set_text(GTK_LABEL(ge->probe.fio_ver), "");
Jens Axboe3863d1a2012-03-09 17:39:05 +0100123#if 0
124 /* should we empty it... */
Jens Axboe2f99deb2012-03-09 14:37:29 +0100125 gtk_entry_set_text(GTK_ENTRY(ge->eta.name), "");
Jens Axboe3863d1a2012-03-09 17:39:05 +0100126#endif
Jens Axboec80b74b2012-03-12 10:23:28 +0100127 multitext_update_entry(&ge->eta.iotype, 0, "");
Jens Axboe99d633a2012-03-15 15:55:04 +0100128 multitext_update_entry(&ge->eta.bs, 0, "");
Jens Axboec80b74b2012-03-12 10:23:28 +0100129 multitext_update_entry(&ge->eta.ioengine, 0, "");
130 multitext_update_entry(&ge->eta.iodepth, 0, "");
Jens Axboe2f99deb2012-03-09 14:37:29 +0100131 gtk_entry_set_text(GTK_ENTRY(ge->eta.jobs), "");
132 gtk_entry_set_text(GTK_ENTRY(ge->eta.files), "");
133 gtk_entry_set_text(GTK_ENTRY(ge->eta.read_bw), "");
134 gtk_entry_set_text(GTK_ENTRY(ge->eta.read_iops), "");
135 gtk_entry_set_text(GTK_ENTRY(ge->eta.write_bw), "");
136 gtk_entry_set_text(GTK_ENTRY(ge->eta.write_iops), "");
Jens Axboe8663ea62012-03-02 14:04:30 +0100137}
138
Jens Axboe781ccba2012-03-15 09:44:42 +0100139static void set_menu_entry_text(struct gui *ui, const char *path,
140 const char *text)
141{
142 GtkWidget *w;
143
144 w = gtk_ui_manager_get_widget(ui->uimanager, path);
145 if (w)
146 gtk_menu_item_set_label(GTK_MENU_ITEM(w), text);
147 else
148 fprintf(stderr, "gfio: can't find path %s\n", path);
149}
150
151
152static void set_menu_entry_visible(struct gui *ui, const char *path, int show)
153{
154 GtkWidget *w;
155
156 w = gtk_ui_manager_get_widget(ui->uimanager, path);
157 if (w)
158 gtk_widget_set_sensitive(w, show);
159 else
160 fprintf(stderr, "gfio: can't find path %s\n", path);
161}
162
163static void set_job_menu_visible(struct gui *ui, int visible)
164{
165 set_menu_entry_visible(ui, "/MainMenu/JobMenu", visible);
166}
167
168static void set_view_results_visible(struct gui *ui, int visible)
169{
170 set_menu_entry_visible(ui, "/MainMenu/ViewMenu/Results", visible);
171}
172
Jens Axboe014f4022012-03-15 14:03:01 +0100173static const char *get_button_tooltip(struct button_spec *s, int sensitive)
174{
175 if (s->tooltiptext[sensitive])
176 return s->tooltiptext[sensitive];
177
178 return s->tooltiptext[0];
179}
180
181static GtkWidget *add_button(GtkWidget *buttonbox,
182 struct button_spec *buttonspec, gpointer data)
183{
184 GtkWidget *button = gtk_button_new_with_label(buttonspec->buttontext);
185 gboolean sens = buttonspec->start_sensitive;
186
187 g_signal_connect(button, "clicked", G_CALLBACK(buttonspec->f), data);
188 gtk_box_pack_start(GTK_BOX(buttonbox), button, FALSE, FALSE, 3);
189
190 sens = buttonspec->start_sensitive;
191 gtk_widget_set_tooltip_text(button, get_button_tooltip(buttonspec, sens));
192 gtk_widget_set_sensitive(button, sens);
193
194 return button;
195}
196
197static void add_buttons(struct gui_entry *ge, struct button_spec *buttonlist,
198 int nbuttons)
199{
200 int i;
201
202 for (i = 0; i < nbuttons; i++)
203 ge->button[i] = add_button(ge->buttonbox, &buttonlist[i], ge);
204}
205
Jens Axboe85dd01e2012-03-12 14:33:16 +0100206/*
207 * Update sensitivity of job buttons and job menu items, based on the
208 * state of the client.
209 */
210static void update_button_states(struct gui *ui, struct gui_entry *ge)
211{
212 unsigned int connect_state, send_state, start_state, edit_state;
213 const char *connect_str = NULL;
Jens Axboe85dd01e2012-03-12 14:33:16 +0100214
215 switch (ge->state) {
Jens Axboe1252d8f2012-03-21 11:13:31 +0100216 default:
217 gfio_report_error(ge, "Bad client state: %u\n", ge->state);
Jens Axboe85dd01e2012-03-12 14:33:16 +0100218 /* fall through to new state */
Jens Axboe85dd01e2012-03-12 14:33:16 +0100219 case GE_STATE_NEW:
220 connect_state = 1;
Jens Axboe9af4a242012-03-16 10:13:49 +0100221 edit_state = 1;
Jens Axboe85dd01e2012-03-12 14:33:16 +0100222 connect_str = "Connect";
223 send_state = 0;
224 start_state = 0;
225 break;
226 case GE_STATE_CONNECTED:
227 connect_state = 1;
Jens Axboe9af4a242012-03-16 10:13:49 +0100228 edit_state = 1;
Jens Axboe85dd01e2012-03-12 14:33:16 +0100229 connect_str = "Disconnect";
230 send_state = 1;
231 start_state = 0;
232 break;
233 case GE_STATE_JOB_SENT:
234 connect_state = 1;
Jens Axboe9af4a242012-03-16 10:13:49 +0100235 edit_state = 1;
Jens Axboe85dd01e2012-03-12 14:33:16 +0100236 connect_str = "Disconnect";
237 send_state = 0;
238 start_state = 1;
239 break;
240 case GE_STATE_JOB_STARTED:
241 connect_state = 1;
242 edit_state = 1;
243 connect_str = "Disconnect";
244 send_state = 0;
245 start_state = 1;
246 break;
247 case GE_STATE_JOB_RUNNING:
248 connect_state = 1;
249 edit_state = 0;
250 connect_str = "Disconnect";
251 send_state = 0;
252 start_state = 0;
253 break;
254 case GE_STATE_JOB_DONE:
255 connect_state = 1;
256 edit_state = 0;
257 connect_str = "Connect";
258 send_state = 0;
259 start_state = 0;
260 break;
261 }
262
Jens Axboe53e0e852012-03-15 19:38:01 +0100263 gtk_widget_set_sensitive(ge->button[GFIO_BUTTON_CONNECT], connect_state);
264 gtk_widget_set_sensitive(ge->button[GFIO_BUTTON_SEND], send_state);
265 gtk_widget_set_sensitive(ge->button[GFIO_BUTTON_START], start_state);
266 gtk_button_set_label(GTK_BUTTON(ge->button[GFIO_BUTTON_CONNECT]), connect_str);
267 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 +0100268
Jens Axboe781ccba2012-03-15 09:44:42 +0100269 set_menu_entry_visible(ui, "/MainMenu/JobMenu/Connect", connect_state);
270 set_menu_entry_text(ui, "/MainMenu/JobMenu/Connect", connect_str);
Jens Axboe85dd01e2012-03-12 14:33:16 +0100271
Jens Axboe781ccba2012-03-15 09:44:42 +0100272 set_menu_entry_visible(ui, "/MainMenu/JobMenu/Edit job", edit_state);
273 set_menu_entry_visible(ui, "/MainMenu/JobMenu/Send job", send_state);
274 set_menu_entry_visible(ui, "/MainMenu/JobMenu/Start job", start_state);
Jens Axboe85dd01e2012-03-12 14:33:16 +0100275
Jens Axboe781ccba2012-03-15 09:44:42 +0100276 if (ge->client && ge->client->nr_results)
277 set_view_results_visible(ui, 1);
278 else
279 set_view_results_visible(ui, 0);
Jens Axboe85dd01e2012-03-12 14:33:16 +0100280}
281
Jens Axboe1252d8f2012-03-21 11:13:31 +0100282void gfio_set_state(struct gui_entry *ge, unsigned int state)
Jens Axboe85dd01e2012-03-12 14:33:16 +0100283{
284 ge->state = state;
285 update_button_states(ge->ui, ge);
286}
287
Jens Axboe9b260bd2012-03-06 11:02:52 +0100288static void gfio_ui_setup_log(struct gui *ui)
289{
290 GtkTreeSelection *selection;
291 GtkListStore *model;
292 GtkWidget *tree_view;
293
294 model = gtk_list_store_new(4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT, G_TYPE_STRING);
295
296 tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
297 gtk_widget_set_can_focus(tree_view, FALSE);
298
299 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
300 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_BROWSE);
Jens Axboe661f7412012-03-06 13:55:45 +0100301 g_object_set(G_OBJECT(tree_view), "headers-visible", TRUE,
302 "enable-grid-lines", GTK_TREE_VIEW_GRID_LINES_BOTH, NULL);
Jens Axboe9b260bd2012-03-06 11:02:52 +0100303
304 tree_view_column(tree_view, 0, "Time", ALIGN_RIGHT | UNSORTABLE);
305 tree_view_column(tree_view, 1, "Host", ALIGN_RIGHT | UNSORTABLE);
306 tree_view_column(tree_view, 2, "Level", ALIGN_RIGHT | UNSORTABLE);
Jens Axboef095d562012-03-06 13:49:12 +0100307 tree_view_column(tree_view, 3, "Text", ALIGN_LEFT | UNSORTABLE);
Jens Axboe9b260bd2012-03-06 11:02:52 +0100308
309 ui->log_model = model;
310 ui->log_tree = tree_view;
311}
312
Jens Axboe2f99deb2012-03-09 14:37:29 +0100313static gint on_config_drawing_area(GtkWidget *w, GdkEventConfigure *event,
314 gpointer data)
Stephen M. Cameron3ea48b82012-03-07 19:40:58 +0100315{
Jens Axboe2f99deb2012-03-09 14:37:29 +0100316 struct gfio_graphs *g = data;
317
Stephen M. Cameron57f9d282012-03-11 11:36:51 +0100318 graph_set_size(g->iops_graph, w->allocation.width / 2.0, w->allocation.height);
319 graph_set_position(g->iops_graph, w->allocation.width / 2.0, 0.0);
320 graph_set_size(g->bandwidth_graph, w->allocation.width / 2.0, w->allocation.height);
321 graph_set_position(g->bandwidth_graph, 0, 0);
Stephen M. Cameron3ea48b82012-03-07 19:40:58 +0100322 return TRUE;
323}
324
Stephen M. Cameron57f9d282012-03-11 11:36:51 +0100325static void draw_graph(struct graph *g, cairo_t *cr)
326{
327 line_graph_draw(g, cr);
328 cairo_stroke(cr);
329}
330
Jens Axboe93e2db22012-03-13 09:45:22 +0100331static gboolean graph_tooltip(GtkWidget *w, gint x, gint y,
332 gboolean keyboard_mode, GtkTooltip *tooltip,
333 gpointer data)
334{
335 struct gfio_graphs *g = data;
336 const char *text = NULL;
337
338 if (graph_contains_xy(g->iops_graph, x, y))
339 text = graph_find_tooltip(g->iops_graph, x, y);
340 else if (graph_contains_xy(g->bandwidth_graph, x, y))
341 text = graph_find_tooltip(g->bandwidth_graph, x, y);
342
343 if (text) {
344 gtk_tooltip_set_text(tooltip, text);
345 return TRUE;
346 }
347
348 return FALSE;
349}
350
Jens Axboe2fd3bb02012-03-07 08:07:39 +0100351static int on_expose_drawing_area(GtkWidget *w, GdkEvent *event, gpointer p)
352{
Jens Axboe2f99deb2012-03-09 14:37:29 +0100353 struct gfio_graphs *g = p;
Jens Axboe2fd3bb02012-03-07 08:07:39 +0100354 cairo_t *cr;
355
356 cr = gdk_cairo_create(w->window);
Jens Axboe93e2db22012-03-13 09:45:22 +0100357
358 if (graph_has_tooltips(g->iops_graph) ||
359 graph_has_tooltips(g->bandwidth_graph)) {
360 g_object_set(w, "has-tooltip", TRUE, NULL);
361 g_signal_connect(w, "query-tooltip", G_CALLBACK(graph_tooltip), g);
362 }
363
Jens Axboe2fd3bb02012-03-07 08:07:39 +0100364 cairo_set_source_rgb(cr, 0, 0, 0);
Stephen M. Cameron57f9d282012-03-11 11:36:51 +0100365 draw_graph(g->iops_graph, cr);
366 draw_graph(g->bandwidth_graph, cr);
Jens Axboe2fd3bb02012-03-07 08:07:39 +0100367 cairo_destroy(cr);
368
369 return FALSE;
370}
371
Jens Axboe2f99deb2012-03-09 14:37:29 +0100372/*
Jens Axboe0fd18982012-03-14 10:34:48 +0100373 * FIXME: need more handling here
374 */
375static void ge_destroy(struct gui_entry *ge)
376{
377 struct gfio_client *gc = ge->client;
378
379 if (gc && gc->client) {
380 if (ge->state >= GE_STATE_CONNECTED)
381 fio_client_terminate(gc->client);
382
383 fio_put_client(gc->client);
384 }
385
Jens Axboe0cf3ece2012-03-21 10:15:20 +0100386 free(ge->job_file);
387 free(ge->host);
Jens Axboe0fd18982012-03-14 10:34:48 +0100388 flist_del(&ge->list);
389 free(ge);
390}
391
392static void ge_widget_destroy(GtkWidget *w, gpointer data)
393{
Jens Axboe2eb98bf2012-03-20 08:20:48 +0100394 struct gui_entry *ge = (struct gui_entry *) data;
395
396 ge_destroy(ge);
Jens Axboe0fd18982012-03-14 10:34:48 +0100397}
398
399static void gfio_quit(struct gui *ui)
400{
401 struct gui_entry *ge;
402
403 while (!flist_empty(&ui->list)) {
404 ge = flist_entry(ui->list.next, struct gui_entry, list);
405 ge_destroy(ge);
406 }
407
408 gtk_main_quit();
409}
410
Stephen M. Cameronff1f3282012-02-24 08:17:30 +0100411static void quit_clicked(__attribute__((unused)) GtkWidget *widget,
412 __attribute__((unused)) gpointer data)
413{
Jens Axboe6e02ad62012-03-20 12:25:36 +0100414 struct gui *ui = (struct gui *) data;
415
416 gfio_quit(ui);
Stephen M. Cameronff1f3282012-02-24 08:17:30 +0100417}
418
Stephen M. Cameron25927252012-02-24 08:17:31 +0100419static void *job_thread(void *arg)
Stephen M. Cameronf3074002012-02-24 08:17:30 +0100420{
Jens Axboea9eccde2012-03-09 14:59:42 +0100421 struct gui *ui = arg;
422
423 ui->handler_running = 1;
Stephen M. Cameron25927252012-02-24 08:17:31 +0100424 fio_handle_clients(&gfio_client_ops);
Jens Axboea9eccde2012-03-09 14:59:42 +0100425 ui->handler_running = 0;
Stephen M. Cameron25927252012-02-24 08:17:31 +0100426 return NULL;
427}
428
Jens Axboe0cf3ece2012-03-21 10:15:20 +0100429static int send_job_file(struct gui_entry *ge)
Stephen M. Cameron60f6b332012-02-24 08:17:32 +0100430{
Jens Axboe9988ca72012-03-09 15:14:06 +0100431 struct gfio_client *gc = ge->client;
Jens Axboe0cf3ece2012-03-21 10:15:20 +0100432 int ret = 0;
Stephen M. Cameron60f6b332012-02-24 08:17:32 +0100433
Jens Axboe0cf3ece2012-03-21 10:15:20 +0100434 ret = fio_client_send_ini(gc->client, ge->job_file);
435 if (!ret)
436 return 0;
Jens Axboec7249262012-03-09 17:11:04 +0100437
Jens Axboe41666582012-03-21 10:25:29 +0100438 gfio_report_error(ge, "Failed to send file %s: %s\n", ge->job_file, strerror(-ret));
Jens Axboe0cf3ece2012-03-21 10:15:20 +0100439 return 1;
Stephen M. Cameron60f6b332012-02-24 08:17:32 +0100440}
441
Jens Axboe63a130b2012-03-06 20:08:59 +0100442static void *server_thread(void *arg)
443{
444 is_backend = 1;
445 gfio_server_running = 1;
446 fio_start_server(NULL);
447 gfio_server_running = 0;
448 return NULL;
449}
450
Jens Axboe6e02ad62012-03-20 12:25:36 +0100451static void gfio_start_server(struct gui *ui)
Jens Axboe63a130b2012-03-06 20:08:59 +0100452{
453 if (!gfio_server_running) {
454 gfio_server_running = 1;
455 pthread_create(&ui->server_t, NULL, server_thread, NULL);
Jens Axboee34f6ad2012-03-06 20:47:15 +0100456 pthread_detach(ui->server_t);
Jens Axboe63a130b2012-03-06 20:08:59 +0100457 }
458}
459
Stephen M. Cameron25927252012-02-24 08:17:31 +0100460static void start_job_clicked(__attribute__((unused)) GtkWidget *widget,
461 gpointer data)
462{
Jens Axboe2f99deb2012-03-09 14:37:29 +0100463 struct gui_entry *ge = data;
464 struct gfio_client *gc = ge->client;
Stephen M. Cameron25927252012-02-24 08:17:31 +0100465
Jens Axboe78cb2fe2012-03-12 23:05:29 +0100466 if (gc)
467 fio_start_client(gc->client);
Stephen M. Cameronf3074002012-02-24 08:17:30 +0100468}
469
Jens Axboedf06f222012-03-02 13:32:04 +0100470static void file_open(GtkWidget *w, gpointer data);
471
Jens Axboe62bc9372012-03-07 11:45:07 +0100472struct connection_widgets
473{
474 GtkWidget *hentry;
475 GtkWidget *combo;
476 GtkWidget *button;
477};
478
479static void hostname_cb(GtkEntry *entry, gpointer data)
480{
481 struct connection_widgets *cw = data;
482 int uses_net = 0, is_localhost = 0;
483 const gchar *text;
484 gchar *ctext;
485
486 /*
487 * Check whether to display the 'auto start backend' box
488 * or not. Show it if we are a localhost and using network,
489 * or using a socket.
490 */
491 ctext = gtk_combo_box_get_active_text(GTK_COMBO_BOX(cw->combo));
492 if (!ctext || !strncmp(ctext, "IPv4", 4) || !strncmp(ctext, "IPv6", 4))
493 uses_net = 1;
494 g_free(ctext);
495
496 if (uses_net) {
497 text = gtk_entry_get_text(GTK_ENTRY(cw->hentry));
498 if (!strcmp(text, "127.0.0.1") || !strcmp(text, "localhost") ||
499 !strcmp(text, "::1") || !strcmp(text, "ip6-localhost") ||
500 !strcmp(text, "ip6-loopback"))
501 is_localhost = 1;
502 }
503
504 if (!uses_net || is_localhost) {
505 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cw->button), 1);
506 gtk_widget_set_sensitive(cw->button, 1);
507 } else {
508 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cw->button), 0);
509 gtk_widget_set_sensitive(cw->button, 0);
510 }
Jens Axboea7a42ce2012-03-02 13:12:04 +0100511 }
512
Jens Axboe1252d8f2012-03-21 11:13:31 +0100513 static int get_connection_details(struct gui_entry *ge)
514 {
515 GtkWidget *dialog, *box, *vbox, *hbox, *frame, *pentry;
516 struct connection_widgets cw;
517 struct gui *ui = ge->ui;
518 char *typeentry;
Jens Axboea7a42ce2012-03-02 13:12:04 +0100519
Jens Axboe1252d8f2012-03-21 11:13:31 +0100520 if (ge->host)
521 return 0;
Jens Axboea7a42ce2012-03-02 13:12:04 +0100522
Jens Axboe1252d8f2012-03-21 11:13:31 +0100523 dialog = gtk_dialog_new_with_buttons("Connection details",
524 GTK_WINDOW(ui->window),
525 GTK_DIALOG_DESTROY_WITH_PARENT,
526 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
527 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, NULL);
Jens Axboeb9f3c7e2012-03-02 14:27:17 +0100528
Jens Axboe1252d8f2012-03-21 11:13:31 +0100529 frame = gtk_frame_new("Hostname / socket name");
530 /* gtk_dialog_get_content_area() is 2.14 and newer */
531 vbox = GTK_DIALOG(dialog)->vbox;
532 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
Jens Axboea7a42ce2012-03-02 13:12:04 +0100533
Jens Axboe1252d8f2012-03-21 11:13:31 +0100534 box = gtk_vbox_new(FALSE, 6);
535 gtk_container_add(GTK_CONTAINER(frame), box);
Jens Axboe0cf3ece2012-03-21 10:15:20 +0100536
Jens Axboe1252d8f2012-03-21 11:13:31 +0100537 hbox = gtk_hbox_new(TRUE, 10);
538 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
539 cw.hentry = gtk_entry_new();
540 gtk_entry_set_text(GTK_ENTRY(cw.hentry), "localhost");
541 gtk_box_pack_start(GTK_BOX(hbox), cw.hentry, TRUE, TRUE, 0);
Jens Axboee0681f32012-03-06 12:14:42 +0100542
Jens Axboe1252d8f2012-03-21 11:13:31 +0100543 frame = gtk_frame_new("Port");
544 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
545 box = gtk_vbox_new(FALSE, 10);
546 gtk_container_add(GTK_CONTAINER(frame), box);
Jens Axboee0681f32012-03-06 12:14:42 +0100547
Jens Axboe1252d8f2012-03-21 11:13:31 +0100548 hbox = gtk_hbox_new(TRUE, 4);
549 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
550 pentry = create_spinbutton(hbox, 1, 65535, FIO_NET_PORT);
Jens Axboe0cf3ece2012-03-21 10:15:20 +0100551
Jens Axboe1252d8f2012-03-21 11:13:31 +0100552 frame = gtk_frame_new("Type");
553 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
554 box = gtk_vbox_new(FALSE, 10);
555 gtk_container_add(GTK_CONTAINER(frame), box);
Jens Axboe0cf3ece2012-03-21 10:15:20 +0100556
Jens Axboe1252d8f2012-03-21 11:13:31 +0100557 hbox = gtk_hbox_new(TRUE, 4);
558 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
Jens Axboe0cf3ece2012-03-21 10:15:20 +0100559
Jens Axboe1252d8f2012-03-21 11:13:31 +0100560 cw.combo = gtk_combo_box_new_text();
561 gtk_combo_box_append_text(GTK_COMBO_BOX(cw.combo), "IPv4");
562 gtk_combo_box_append_text(GTK_COMBO_BOX(cw.combo), "IPv6");
563 gtk_combo_box_append_text(GTK_COMBO_BOX(cw.combo), "local socket");
564 gtk_combo_box_set_active(GTK_COMBO_BOX(cw.combo), 0);
Jens Axboe0cf3ece2012-03-21 10:15:20 +0100565
Jens Axboe1252d8f2012-03-21 11:13:31 +0100566 gtk_container_add(GTK_CONTAINER(hbox), cw.combo);
Jens Axboe0cf3ece2012-03-21 10:15:20 +0100567
Jens Axboe1252d8f2012-03-21 11:13:31 +0100568 frame = gtk_frame_new("Options");
569 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
570 box = gtk_vbox_new(FALSE, 10);
571 gtk_container_add(GTK_CONTAINER(frame), box);
Jens Axboe0cf3ece2012-03-21 10:15:20 +0100572
Jens Axboe1252d8f2012-03-21 11:13:31 +0100573 hbox = gtk_hbox_new(TRUE, 4);
574 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
575
576 cw.button = gtk_check_button_new_with_label("Auto-spawn fio backend");
577 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cw.button), 1);
578 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.");
579 gtk_box_pack_start(GTK_BOX(hbox), cw.button, FALSE, FALSE, 6);
580
581 /*
582 * Connect edit signal, so we can show/not-show the auto start button
583 */
584 g_signal_connect(GTK_OBJECT(cw.hentry), "changed", G_CALLBACK(hostname_cb), &cw);
585 g_signal_connect(GTK_OBJECT(cw.combo), "changed", G_CALLBACK(hostname_cb), &cw);
586
587 gtk_widget_show_all(dialog);
588
589 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT) {
590 gtk_widget_destroy(dialog);
591 return 1;
Jens Axboe0cf3ece2012-03-21 10:15:20 +0100592 }
593
Jens Axboe1252d8f2012-03-21 11:13:31 +0100594 ge->host = strdup(gtk_entry_get_text(GTK_ENTRY(cw.hentry)));
595 ge->port = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(pentry));
596
597 typeentry = gtk_combo_box_get_active_text(GTK_COMBO_BOX(cw.combo));
598 if (!typeentry || !strncmp(typeentry, "IPv4", 4))
599 ge->type = Fio_client_ipv4;
600 else if (!strncmp(typeentry, "IPv6", 4))
601 ge->type = Fio_client_ipv6;
602 else
603 ge->type = Fio_client_socket;
604 g_free(typeentry);
605
606 ge->server_start = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cw.button));
607
608 gtk_widget_destroy(dialog);
609 return 0;
610 }
611
612 static void gfio_set_client(struct gfio_client *gc, struct fio_client *client)
613 {
614 gc->client = fio_get_client(client);
615 client->client_data = gc;
616 }
617
618 static void gfio_client_added(struct gui_entry *ge, struct fio_client *client)
619 {
620 struct gfio_client *gc;
621
622 gc = malloc(sizeof(*gc));
623 memset(gc, 0, sizeof(*gc));
624 options_default_fill(&gc->o);
625 gc->ge = ge;
626 ge->client = gc;
627 gfio_set_client(gc, client);
628 }
629
630 static void connect_clicked(GtkWidget *widget, gpointer data)
631 {
632 struct gui_entry *ge = data;
633 struct gfio_client *gc = ge->client;
634
635 if (ge->state == GE_STATE_NEW) {
636 int ret;
637
638 if (!ge->job_file)
639 file_open(widget, ge->ui);
640 if (!ge->job_file)
641 return;
642
643 gc = ge->client;
644
645 if (!gc->client) {
646 struct fio_client *client;
647
648 if (get_connection_details(ge)) {
649 gfio_report_error(ge, "Failed to get connection details\n");
650 return;
651 }
652
653 client = fio_client_add_explicit(&gfio_client_ops, ge->host, ge->type, ge->port);
654 if (!client) {
655 gfio_report_error(ge, "Failed to add client %s\n", ge->host);
656 free(ge->host);
657 ge->host = NULL;
658 return;
659 }
660 gfio_set_client(gc, client);
661 }
662
663 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(ge->thread_status_pb), "No jobs running");
664 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(ge->thread_status_pb), 0.0);
665 ret = fio_client_connect(gc->client);
666 if (!ret) {
667 if (!ge->ui->handler_running)
668 pthread_create(&ge->ui->t, NULL, job_thread, ge->ui);
669 gfio_set_state(ge, GE_STATE_CONNECTED);
670 } else {
671 gfio_report_error(ge, "Failed to connect to %s: %s\n", ge->client->client->hostname, strerror(-ret));
672 }
Jens Axboe0cf3ece2012-03-21 10:15:20 +0100673 } else {
Jens Axboe1252d8f2012-03-21 11:13:31 +0100674 fio_client_terminate(gc->client);
675 gfio_set_state(ge, GE_STATE_NEW);
676 clear_ge_ui_info(ge);
Jens Axboe0cf3ece2012-03-21 10:15:20 +0100677 }
Jens Axboe38634cb2012-03-13 12:26:41 +0100678 }
679
Jens Axboe1252d8f2012-03-21 11:13:31 +0100680 static void send_clicked(GtkWidget *widget, gpointer data)
681 {
682 struct gui_entry *ge = data;
Jens Axboe2f99deb2012-03-09 14:37:29 +0100683
Jens Axboe1252d8f2012-03-21 11:13:31 +0100684 if (send_job_file(ge))
685 gtk_widget_set_sensitive(ge->button[GFIO_BUTTON_START], 1);
Jens Axboe2f99deb2012-03-09 14:37:29 +0100686 }
687
Jens Axboe1252d8f2012-03-21 11:13:31 +0100688 static GtkWidget *new_client_page(struct gui_entry *ge);
Jens Axboe2f99deb2012-03-09 14:37:29 +0100689
Jens Axboe1252d8f2012-03-21 11:13:31 +0100690 static struct gui_entry *alloc_new_gui_entry(struct gui *ui)
691 {
692 struct gui_entry *ge;
Jens Axboe85dd01e2012-03-12 14:33:16 +0100693
Jens Axboe1252d8f2012-03-21 11:13:31 +0100694 ge = malloc(sizeof(*ge));
695 memset(ge, 0, sizeof(*ge));
696 ge->state = GE_STATE_NEW;
697 INIT_FLIST_HEAD(&ge->list);
698 flist_add_tail(&ge->list, &ui->list);
699 ge->ui = ui;
700 return ge;
Jens Axboe16ce5ad2012-03-12 11:56:09 +0100701 }
702
Jens Axboe1252d8f2012-03-21 11:13:31 +0100703 static struct gui_entry *get_new_ge_with_tab(struct gui *ui, const char *name)
704 {
705 struct gui_entry *ge;
706
707 ge = alloc_new_gui_entry(ui);
708
709 ge->vbox = new_client_page(ge);
710 g_signal_connect(ge->vbox, "destroy", G_CALLBACK(ge_widget_destroy), ge);
711
712 ge->page_label = gtk_label_new(name);
713 ge->page_num = gtk_notebook_append_page(GTK_NOTEBOOK(ui->notebook), ge->vbox, ge->page_label);
714
715 gtk_widget_show_all(ui->window);
716 return ge;
Jens Axboef5c67262012-03-13 08:20:41 +0100717 }
718
Jens Axboe1252d8f2012-03-21 11:13:31 +0100719 static void file_new(GtkWidget *w, gpointer data)
720 {
721 struct gui *ui = (struct gui *) data;
722 struct gui_entry *ge;
Jens Axboe16ce5ad2012-03-12 11:56:09 +0100723
Jens Axboe0cf3ece2012-03-21 10:15:20 +0100724 ge = get_new_ge_with_tab(ui, "Untitled");
Jens Axboe1252d8f2012-03-21 11:13:31 +0100725 gtk_notebook_set_current_page(GTK_NOTEBOOK(ui->notebook), ge->page_num);
Jens Axboe38634cb2012-03-13 12:26:41 +0100726 }
Jens Axboe2f99deb2012-03-09 14:37:29 +0100727
Jens Axboe1252d8f2012-03-21 11:13:31 +0100728 /*
729 * Return the 'ge' corresponding to the tab. If the active tab is the
730 * main tab, open a new tab.
731 */
732 static struct gui_entry *get_ge_from_page(struct gui *ui, gint cur_page,
733 int *created)
734 {
735 struct flist_head *entry;
736 struct gui_entry *ge;
Jens Axboe0420ba62012-02-29 11:16:52 +0100737
Jens Axboe1252d8f2012-03-21 11:13:31 +0100738 if (!cur_page) {
739 if (created)
740 *created = 1;
741 return get_new_ge_with_tab(ui, "Untitled");
742 }
743
744 if (created)
745 *created = 0;
746
747 flist_for_each(entry, &ui->list) {
748 ge = flist_entry(entry, struct gui_entry, list);
749 if (ge->page_num == cur_page)
750 return ge;
751 }
752
753 return NULL;
754 }
755
756 static struct gui_entry *get_ge_from_cur_tab(struct gui *ui)
757 {
758 gint cur_page;
759
760 /*
761 * Main tab is tab 0, so any current page other than 0 holds
762 * a ge entry.
763 */
764 cur_page = gtk_notebook_get_current_page(GTK_NOTEBOOK(ui->notebook));
765 if (cur_page)
766 return get_ge_from_page(ui, cur_page, NULL);
767
768 return NULL;
769 }
770
771 static void file_close(GtkWidget *w, gpointer data)
772 {
773 struct gui *ui = (struct gui *) data;
774 struct gui_entry *ge;
775
776 /*
777 * Can't close the main tab
778 */
779 ge = get_ge_from_cur_tab(ui);
780 if (ge) {
Jens Axboea6790902012-03-13 15:16:11 +0100781 gtk_widget_destroy(ge->vbox);
Jens Axboe1252d8f2012-03-21 11:13:31 +0100782 return;
783 }
784
785 if (!flist_empty(&ui->list)) {
786 gfio_report_info(ui, "Error", "The main page view cannot be closed\n");
787 return;
788 }
789
790 gfio_quit(ui);
791 }
792
793 static void file_add_recent(struct gui *ui, const gchar *uri)
794 {
795 GtkRecentData grd;
796
797 memset(&grd, 0, sizeof(grd));
798 grd.display_name = strdup("gfio");
799 grd.description = strdup("Fio job file");
800 grd.mime_type = strdup(GFIO_MIME);
801 grd.app_name = strdup(g_get_application_name());
802 grd.app_exec = strdup("gfio %f/%u");
803
804 gtk_recent_manager_add_full(ui->recentmanager, uri, &grd);
805 }
806
807 static gchar *get_filename_from_uri(const gchar *uri)
808 {
809 if (strncmp(uri, "file://", 7))
810 return strdup(uri);
811
812 return strdup(uri + 7);
813 }
814
815 static int do_file_open(struct gui_entry *ge, const gchar *uri)
816 {
817 struct fio_client *client;
818
819 assert(!ge->job_file);
820
821 ge->job_file = get_filename_from_uri(uri);
822
823 client = fio_client_add_explicit(&gfio_client_ops, ge->host, ge->type, ge->port);
824 if (client) {
825 gfio_client_added(ge, client);
826 file_add_recent(ge->ui, uri);
827 return 0;
828 }
829
830 gfio_report_error(ge, "Failed to add client %s\n", ge->host);
831 free(ge->host);
832 ge->host = NULL;
Jens Axboea6790902012-03-13 15:16:11 +0100833 return 1;
834 }
835
Jens Axboe1252d8f2012-03-21 11:13:31 +0100836 static int do_file_open_with_tab(struct gui *ui, const gchar *uri)
837 {
838 struct gui_entry *ge;
839 gint cur_page;
840 int ret, ge_is_new = 0;
Jens Axboea6790902012-03-13 15:16:11 +0100841
Jens Axboe1252d8f2012-03-21 11:13:31 +0100842 /*
843 * Creates new tab if current tab is the main window, or the
844 * current tab already has a client.
845 */
846 cur_page = gtk_notebook_get_current_page(GTK_NOTEBOOK(ui->notebook));
847 ge = get_ge_from_page(ui, cur_page, &ge_is_new);
848 if (ge->client) {
849 ge = get_new_ge_with_tab(ui, "Untitled");
850 ge_is_new = 1;
851 }
852
853 gtk_notebook_set_current_page(GTK_NOTEBOOK(ui->notebook), ge->page_num);
854
855 if (get_connection_details(ge)) {
856 if (ge_is_new)
857 gtk_widget_destroy(ge->vbox);
858
859 return 1;
860 }
861
862 ret = do_file_open(ge, uri);
863
864 if (!ret) {
865 if (ge->server_start)
866 gfio_start_server(ui);
867 } else {
868 if (ge_is_new)
869 gtk_widget_destroy(ge->vbox);
870 }
871
872 return ret;
Jens Axboea6790902012-03-13 15:16:11 +0100873 }
874
Jens Axboe1252d8f2012-03-21 11:13:31 +0100875 static void recent_open(GtkAction *action, gpointer data)
876 {
877 struct gui *ui = (struct gui *) data;
878 GtkRecentInfo *info;
879 const gchar *uri;
Jens Axboea6790902012-03-13 15:16:11 +0100880
Jens Axboe1252d8f2012-03-21 11:13:31 +0100881 info = g_object_get_data(G_OBJECT(action), "gtk-recent-info");
882 uri = gtk_recent_info_get_uri(info);
Jens Axboea6790902012-03-13 15:16:11 +0100883
Jens Axboe1252d8f2012-03-21 11:13:31 +0100884 do_file_open_with_tab(ui, uri);
Jens Axboe0420ba62012-02-29 11:16:52 +0100885 }
886
Jens Axboe1252d8f2012-03-21 11:13:31 +0100887 static void file_open(GtkWidget *w, gpointer data)
888 {
889 struct gui *ui = data;
890 GtkWidget *dialog;
891 GtkFileFilter *filter;
892 gchar *filename;
Jens Axboea7a42ce2012-03-02 13:12:04 +0100893
Jens Axboe1252d8f2012-03-21 11:13:31 +0100894 dialog = gtk_file_chooser_dialog_new("Open File",
895 GTK_WINDOW(ui->window),
896 GTK_FILE_CHOOSER_ACTION_OPEN,
897 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
898 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
899 NULL);
900 gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), FALSE);
Jens Axboea7a42ce2012-03-02 13:12:04 +0100901
Jens Axboe1252d8f2012-03-21 11:13:31 +0100902 filter = gtk_file_filter_new();
903 gtk_file_filter_add_pattern(filter, "*.fio");
904 gtk_file_filter_add_pattern(filter, "*.job");
905 gtk_file_filter_add_pattern(filter, "*.ini");
906 gtk_file_filter_add_mime_type(filter, GFIO_MIME);
907 gtk_file_filter_set_name(filter, "Fio job file");
908 gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(dialog), filter);
Jens Axboe0420ba62012-02-29 11:16:52 +0100909
Jens Axboe1252d8f2012-03-21 11:13:31 +0100910 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT) {
911 gtk_widget_destroy(dialog);
912 return;
913 }
Jens Axboe0420ba62012-02-29 11:16:52 +0100914
915 filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
Jens Axboe1252d8f2012-03-21 11:13:31 +0100916
917 gtk_widget_destroy(dialog);
918
919 do_file_open_with_tab(ui, filename);
Jens Axboe0420ba62012-02-29 11:16:52 +0100920 g_free(filename);
921 }
Jens Axboe1252d8f2012-03-21 11:13:31 +0100922
923 static void file_save(GtkWidget *w, gpointer data)
924 {
925 struct gui *ui = data;
926 GtkWidget *dialog;
927
928 dialog = gtk_file_chooser_dialog_new("Save File",
929 GTK_WINDOW(ui->window),
930 GTK_FILE_CHOOSER_ACTION_SAVE,
931 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
932 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
933 NULL);
934
935 gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE);
936 gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), "Untitled document");
937
938 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
939 char *filename;
940
941 filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
942 // save_job_file(filename);
943 g_free(filename);
944 }
945 gtk_widget_destroy(dialog);
946 }
Jens Axboe0420ba62012-02-29 11:16:52 +0100947
Jens Axboe9b260bd2012-03-06 11:02:52 +0100948static void view_log_destroy(GtkWidget *w, gpointer data)
949{
950 struct gui *ui = (struct gui *) data;
951
952 gtk_widget_ref(ui->log_tree);
953 gtk_container_remove(GTK_CONTAINER(w), ui->log_tree);
954 gtk_widget_destroy(w);
Jens Axboe4cbe7212012-03-06 13:36:17 +0100955 ui->log_view = NULL;
Jens Axboe9b260bd2012-03-06 11:02:52 +0100956}
957
Jens Axboe1252d8f2012-03-21 11:13:31 +0100958void gfio_view_log(struct gui *ui)
Jens Axboe9b260bd2012-03-06 11:02:52 +0100959{
Jens Axboe4cbe7212012-03-06 13:36:17 +0100960 GtkWidget *win, *scroll, *vbox, *box;
Jens Axboe9b260bd2012-03-06 11:02:52 +0100961
Jens Axboe4cbe7212012-03-06 13:36:17 +0100962 if (ui->log_view)
963 return;
964
965 ui->log_view = win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
Jens Axboe9b260bd2012-03-06 11:02:52 +0100966 gtk_window_set_title(GTK_WINDOW(win), "Log");
Jens Axboe4cbe7212012-03-06 13:36:17 +0100967 gtk_window_set_default_size(GTK_WINDOW(win), 700, 500);
Jens Axboe9b260bd2012-03-06 11:02:52 +0100968
Jens Axboe4cbe7212012-03-06 13:36:17 +0100969 scroll = gtk_scrolled_window_new(NULL, NULL);
Jens Axboe9b260bd2012-03-06 11:02:52 +0100970
Jens Axboe4cbe7212012-03-06 13:36:17 +0100971 gtk_container_set_border_width(GTK_CONTAINER(scroll), 5);
972
973 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
974
975 box = gtk_hbox_new(TRUE, 0);
976 gtk_box_pack_start_defaults(GTK_BOX(box), ui->log_tree);
977 g_signal_connect(box, "destroy", G_CALLBACK(view_log_destroy), ui);
978 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroll), box);
979
980 vbox = gtk_vbox_new(TRUE, 5);
981 gtk_box_pack_start_defaults(GTK_BOX(vbox), scroll);
982
983 gtk_container_add(GTK_CONTAINER(win), vbox);
Jens Axboe9b260bd2012-03-06 11:02:52 +0100984 gtk_widget_show_all(win);
985}
986
Jens Axboe1252d8f2012-03-21 11:13:31 +0100987static void view_log(GtkWidget *w, gpointer data)
988{
989 struct gui *ui = (struct gui *) data;
990
991 gfio_view_log(ui);
992}
993
Jens Axboe85dd01e2012-03-12 14:33:16 +0100994static void connect_job_entry(GtkWidget *w, gpointer data)
Jens Axboe16ce5ad2012-03-12 11:56:09 +0100995{
Jens Axboe85dd01e2012-03-12 14:33:16 +0100996 struct gui *ui = (struct gui *) data;
997 struct gui_entry *ge;
998
999 ge = get_ge_from_cur_tab(ui);
1000 if (ge)
1001 connect_clicked(w, ge);
1002}
1003
1004static void send_job_entry(GtkWidget *w, gpointer data)
1005{
1006 struct gui *ui = (struct gui *) data;
1007 struct gui_entry *ge;
1008
1009 ge = get_ge_from_cur_tab(ui);
1010 if (ge)
1011 send_clicked(w, ge);
Jens Axboe85dd01e2012-03-12 14:33:16 +01001012}
1013
1014static void edit_job_entry(GtkWidget *w, gpointer data)
1015{
Jens Axboe9af4a242012-03-16 10:13:49 +01001016 struct gui *ui = (struct gui *) data;
Jens Axboe789f4cc2012-03-16 14:56:44 +01001017 struct gui_entry *ge;
Jens Axboe9af4a242012-03-16 10:13:49 +01001018
Jens Axboe789f4cc2012-03-16 14:56:44 +01001019 ge = get_ge_from_cur_tab(ui);
1020 if (ge && ge->client)
1021 gopt_get_options_window(ui->window, &ge->client->o);
Jens Axboe85dd01e2012-03-12 14:33:16 +01001022}
1023
1024static void start_job_entry(GtkWidget *w, gpointer data)
1025{
1026 struct gui *ui = (struct gui *) data;
1027 struct gui_entry *ge;
1028
1029 ge = get_ge_from_cur_tab(ui);
1030 if (ge)
1031 start_job_clicked(w, ge);
Jens Axboe16ce5ad2012-03-12 11:56:09 +01001032}
1033
Jens Axboe781ccba2012-03-15 09:44:42 +01001034static void view_results(GtkWidget *w, gpointer data)
1035{
1036 struct gui *ui = (struct gui *) data;
1037 struct gfio_client *gc;
1038 struct gui_entry *ge;
1039
1040 ge = get_ge_from_cur_tab(ui);
1041 if (!ge)
1042 return;
1043
1044 if (ge->results_window)
1045 return;
1046
1047 gc = ge->client;
1048 if (gc && gc->nr_results)
1049 gfio_display_end_results(gc);
1050}
1051
Jens Axboe8577f4f2012-03-09 19:28:27 +01001052static void __update_graph_limits(struct gfio_graphs *g)
1053{
1054 line_graph_set_data_count_limit(g->iops_graph, gfio_graph_limit);
1055 line_graph_set_data_count_limit(g->bandwidth_graph, gfio_graph_limit);
1056}
1057
1058static void update_graph_limits(void)
1059{
1060 struct flist_head *entry;
1061 struct gui_entry *ge;
1062
1063 __update_graph_limits(&main_ui.graphs);
1064
1065 flist_for_each(entry, &main_ui.list) {
1066 ge = flist_entry(entry, struct gui_entry, list);
1067 __update_graph_limits(&ge->graphs);
1068 }
1069}
1070
Jens Axboe46974a72012-03-02 19:34:13 +01001071static void preferences(GtkWidget *w, gpointer data)
1072{
Jens Axboef3e84402012-03-07 13:14:32 +01001073 GtkWidget *dialog, *frame, *box, **buttons, *vbox, *font;
Jens Axboe1cf6bca2012-03-09 20:20:17 +01001074 GtkWidget *hbox, *spin, *entry, *spin_int;
Jens Axboe6e02ad62012-03-20 12:25:36 +01001075 struct gui *ui = (struct gui *) data;
Jens Axboe46974a72012-03-02 19:34:13 +01001076 int i;
1077
1078 dialog = gtk_dialog_new_with_buttons("Preferences",
Jens Axboe6e02ad62012-03-20 12:25:36 +01001079 GTK_WINDOW(ui->window),
Jens Axboe46974a72012-03-02 19:34:13 +01001080 GTK_DIALOG_DESTROY_WITH_PARENT,
1081 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
1082 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
1083 NULL);
1084
Jens Axboe8577f4f2012-03-09 19:28:27 +01001085 frame = gtk_frame_new("Graphing");
Jens Axboef3e84402012-03-07 13:14:32 +01001086 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), frame, FALSE, FALSE, 5);
1087 vbox = gtk_vbox_new(FALSE, 6);
1088 gtk_container_add(GTK_CONTAINER(frame), vbox);
1089
Jens Axboe1cf6bca2012-03-09 20:20:17 +01001090 hbox = gtk_hbox_new(FALSE, 5);
1091 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 5);
1092 entry = gtk_label_new("Font face to use for graph labels");
1093 gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 5);
1094
Jens Axboef3e84402012-03-07 13:14:32 +01001095 font = gtk_font_button_new();
Jens Axboe1cf6bca2012-03-09 20:20:17 +01001096 gtk_box_pack_start(GTK_BOX(hbox), font, FALSE, FALSE, 5);
Jens Axboef3e84402012-03-07 13:14:32 +01001097
Jens Axboe8577f4f2012-03-09 19:28:27 +01001098 box = gtk_vbox_new(FALSE, 6);
1099 gtk_box_pack_start(GTK_BOX(vbox), box, FALSE, FALSE, 5);
1100
1101 hbox = gtk_hbox_new(FALSE, 5);
Jens Axboe1cf6bca2012-03-09 20:20:17 +01001102 gtk_box_pack_start(GTK_BOX(box), hbox, TRUE, TRUE, 5);
Jens Axboe8577f4f2012-03-09 19:28:27 +01001103 entry = gtk_label_new("Maximum number of data points in graph (seconds)");
1104 gtk_box_pack_start(GTK_BOX(hbox), entry, FALSE, FALSE, 5);
1105
Jens Axboec05d9052012-03-11 13:05:35 +01001106 spin = create_spinbutton(hbox, 10, 1000000, gfio_graph_limit);
Jens Axboe8577f4f2012-03-09 19:28:27 +01001107
Jens Axboe1cf6bca2012-03-09 20:20:17 +01001108 box = gtk_vbox_new(FALSE, 6);
1109 gtk_box_pack_start(GTK_BOX(vbox), box, FALSE, FALSE, 5);
1110
1111 hbox = gtk_hbox_new(FALSE, 5);
1112 gtk_box_pack_start(GTK_BOX(box), hbox, TRUE, TRUE, 5);
1113 entry = gtk_label_new("Client ETA request interval (msec)");
1114 gtk_box_pack_start(GTK_BOX(hbox), entry, FALSE, FALSE, 5);
1115
1116 spin_int = create_spinbutton(hbox, 100, 100000, gfio_client_ops.eta_msec);
Jens Axboea31d9fa2012-03-09 20:23:05 +01001117 frame = gtk_frame_new("Debug logging");
1118 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), frame, FALSE, FALSE, 5);
1119 vbox = gtk_vbox_new(FALSE, 6);
1120 gtk_container_add(GTK_CONTAINER(frame), vbox);
1121
1122 box = gtk_hbox_new(FALSE, 6);
1123 gtk_container_add(GTK_CONTAINER(vbox), box);
1124
1125 buttons = malloc(sizeof(GtkWidget *) * FD_DEBUG_MAX);
1126
1127 for (i = 0; i < FD_DEBUG_MAX; i++) {
1128 if (i == 7) {
1129 box = gtk_hbox_new(FALSE, 6);
1130 gtk_container_add(GTK_CONTAINER(vbox), box);
1131 }
1132
1133
1134 buttons[i] = gtk_check_button_new_with_label(debug_levels[i].name);
1135 gtk_widget_set_tooltip_text(buttons[i], debug_levels[i].help);
1136 gtk_box_pack_start(GTK_BOX(box), buttons[i], FALSE, FALSE, 6);
1137 }
1138
Jens Axboe46974a72012-03-02 19:34:13 +01001139 gtk_widget_show_all(dialog);
1140
1141 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT) {
1142 gtk_widget_destroy(dialog);
1143 return;
1144 }
1145
1146 for (i = 0; i < FD_DEBUG_MAX; i++) {
1147 int set;
1148
1149 set = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(buttons[i]));
1150 if (set)
1151 fio_debug |= (1UL << i);
1152 }
1153
Jens Axboef3e84402012-03-07 13:14:32 +01001154 gfio_graph_font = strdup(gtk_font_button_get_font_name(GTK_FONT_BUTTON(font)));
Jens Axboe8577f4f2012-03-09 19:28:27 +01001155 gfio_graph_limit = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spin));
1156 update_graph_limits();
Jens Axboe1cf6bca2012-03-09 20:20:17 +01001157 gfio_client_ops.eta_msec = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spin_int));
Jens Axboe8577f4f2012-03-09 19:28:27 +01001158
Jens Axboe46974a72012-03-02 19:34:13 +01001159 gtk_widget_destroy(dialog);
1160}
1161
Jens Axboe0420ba62012-02-29 11:16:52 +01001162static void about_dialog(GtkWidget *w, gpointer data)
1163{
Jens Axboe81e4ea62012-03-07 14:18:28 +01001164 const char *authors[] = {
1165 "Jens Axboe <axboe@kernel.dk>",
1166 "Stephen Carmeron <stephenmcameron@gmail.com>",
1167 NULL
1168 };
Jens Axboe84a72ed2012-03-07 14:24:57 +01001169 const char *license[] = {
1170 "Fio is free software; you can redistribute it and/or modify "
1171 "it under the terms of the GNU General Public License as published by "
1172 "the Free Software Foundation; either version 2 of the License, or "
1173 "(at your option) any later version.\n",
1174 "Fio is distributed in the hope that it will be useful, "
1175 "but WITHOUT ANY WARRANTY; without even the implied warranty of "
1176 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the "
1177 "GNU General Public License for more details.\n",
1178 "You should have received a copy of the GNU General Public License "
1179 "along with Fio; if not, write to the Free Software Foundation, Inc., "
1180 "51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n"
1181 };
1182 char *license_trans;
1183
1184 license_trans = g_strconcat(license[0], "\n", license[1], "\n",
1185 license[2], "\n", NULL);
Jens Axboe81e4ea62012-03-07 14:18:28 +01001186
Jens Axboe0420ba62012-02-29 11:16:52 +01001187 gtk_show_about_dialog(NULL,
1188 "program-name", "gfio",
1189 "comments", "Gtk2 UI for fio",
Jens Axboe84a72ed2012-03-07 14:24:57 +01001190 "license", license_trans,
Jens Axboe81e4ea62012-03-07 14:18:28 +01001191 "website", "http://git.kernel.dk/?p=fio.git;a=summary",
1192 "authors", authors,
Jens Axboe0420ba62012-02-29 11:16:52 +01001193 "version", fio_version_string,
Jens Axboe81e4ea62012-03-07 14:18:28 +01001194 "copyright", "© 2012 Jens Axboe <axboe@kernel.dk>",
Jens Axboe0420ba62012-02-29 11:16:52 +01001195 "logo-icon-name", "fio",
1196 /* Must be last: */
Jens Axboe81e4ea62012-03-07 14:18:28 +01001197 "wrap-license", TRUE,
Jens Axboe0420ba62012-02-29 11:16:52 +01001198 NULL);
Jens Axboe84a72ed2012-03-07 14:24:57 +01001199
Jens Axboe2f99deb2012-03-09 14:37:29 +01001200 g_free(license_trans);
Jens Axboe0420ba62012-02-29 11:16:52 +01001201}
1202
1203static GtkActionEntry menu_items[] = {
Jens Axboe46974a72012-03-02 19:34:13 +01001204 { "FileMenuAction", GTK_STOCK_FILE, "File", NULL, NULL, NULL},
Jens Axboe9b260bd2012-03-06 11:02:52 +01001205 { "ViewMenuAction", GTK_STOCK_FILE, "View", NULL, NULL, NULL},
Jens Axboe16ce5ad2012-03-12 11:56:09 +01001206 { "JobMenuAction", GTK_STOCK_FILE, "Job", NULL, NULL, NULL},
Jens Axboe46974a72012-03-02 19:34:13 +01001207 { "HelpMenuAction", GTK_STOCK_HELP, "Help", NULL, NULL, NULL},
Jens Axboe2f99deb2012-03-09 14:37:29 +01001208 { "NewFile", GTK_STOCK_NEW, "New", "<Control>N", NULL, G_CALLBACK(file_new) },
Jens Axboe16ce5ad2012-03-12 11:56:09 +01001209 { "CloseFile", GTK_STOCK_CLOSE, "Close", "<Control>W", NULL, G_CALLBACK(file_close) },
Jens Axboe46974a72012-03-02 19:34:13 +01001210 { "OpenFile", GTK_STOCK_OPEN, NULL, "<Control>O", NULL, G_CALLBACK(file_open) },
1211 { "SaveFile", GTK_STOCK_SAVE, NULL, "<Control>S", NULL, G_CALLBACK(file_save) },
1212 { "Preferences", GTK_STOCK_PREFERENCES, NULL, "<Control>p", NULL, G_CALLBACK(preferences) },
Jens Axboe9b260bd2012-03-06 11:02:52 +01001213 { "ViewLog", NULL, "Log", "<Control>l", NULL, G_CALLBACK(view_log) },
Jens Axboe781ccba2012-03-15 09:44:42 +01001214 { "ViewResults", NULL, "Results", "<Control>R", NULL, G_CALLBACK(view_results) },
Jens Axboebc271d82012-03-15 21:57:40 +01001215 { "ConnectJob", NULL, "Connect", "<Control>D", NULL, G_CALLBACK(connect_job_entry) },
Jens Axboe85dd01e2012-03-12 14:33:16 +01001216 { "EditJob", NULL, "Edit job", "<Control>E", NULL, G_CALLBACK(edit_job_entry) },
1217 { "SendJob", NULL, "Send job", "<Control>X", NULL, G_CALLBACK(send_job_entry) },
1218 { "StartJob", NULL, "Start job", "<Control>L", NULL, G_CALLBACK(start_job_entry) },
Jens Axboe46974a72012-03-02 19:34:13 +01001219 { "Quit", GTK_STOCK_QUIT, NULL, "<Control>Q", NULL, G_CALLBACK(quit_clicked) },
1220 { "About", GTK_STOCK_ABOUT, NULL, NULL, NULL, G_CALLBACK(about_dialog) },
Jens Axboe0420ba62012-02-29 11:16:52 +01001221};
Jens Axboe3e47bd22012-02-29 13:45:02 +01001222static gint nmenu_items = sizeof(menu_items) / sizeof(menu_items[0]);
Jens Axboe0420ba62012-02-29 11:16:52 +01001223
1224static const gchar *ui_string = " \
1225 <ui> \
1226 <menubar name=\"MainMenu\"> \
1227 <menu name=\"FileMenu\" action=\"FileMenuAction\"> \
Jens Axboe2f99deb2012-03-09 14:37:29 +01001228 <menuitem name=\"New\" action=\"NewFile\" /> \
Jens Axboebf641382012-03-15 13:46:16 +01001229 <menuitem name=\"Open\" action=\"OpenFile\" /> \
Jens Axboe16ce5ad2012-03-12 11:56:09 +01001230 <menuitem name=\"Close\" action=\"CloseFile\" /> \
Jens Axboe2f99deb2012-03-09 14:37:29 +01001231 <separator name=\"Separator1\"/> \
Jens Axboe0420ba62012-02-29 11:16:52 +01001232 <menuitem name=\"Save\" action=\"SaveFile\" /> \
Jens Axboe46974a72012-03-02 19:34:13 +01001233 <separator name=\"Separator2\"/> \
Jens Axboe2f99deb2012-03-09 14:37:29 +01001234 <menuitem name=\"Preferences\" action=\"Preferences\" /> \
1235 <separator name=\"Separator3\"/> \
Jens Axboe261f21d2012-03-12 14:58:22 +01001236 <placeholder name=\"FileRecentFiles\"/> \
1237 <separator name=\"Separator4\"/> \
Jens Axboe0420ba62012-02-29 11:16:52 +01001238 <menuitem name=\"Quit\" action=\"Quit\" /> \
1239 </menu> \
Jens Axboe16ce5ad2012-03-12 11:56:09 +01001240 <menu name=\"JobMenu\" action=\"JobMenuAction\"> \
Jens Axboe85dd01e2012-03-12 14:33:16 +01001241 <menuitem name=\"Connect\" action=\"ConnectJob\" /> \
Jens Axboe261f21d2012-03-12 14:58:22 +01001242 <separator name=\"Separator5\"/> \
Jens Axboe85dd01e2012-03-12 14:33:16 +01001243 <menuitem name=\"Edit job\" action=\"EditJob\" /> \
1244 <menuitem name=\"Send job\" action=\"SendJob\" /> \
Jens Axboe261f21d2012-03-12 14:58:22 +01001245 <separator name=\"Separator6\"/> \
Jens Axboe85dd01e2012-03-12 14:33:16 +01001246 <menuitem name=\"Start job\" action=\"StartJob\" /> \
Jens Axboe16ce5ad2012-03-12 11:56:09 +01001247 </menu>\
Jens Axboe9b260bd2012-03-06 11:02:52 +01001248 <menu name=\"ViewMenu\" action=\"ViewMenuAction\"> \
Jens Axboe781ccba2012-03-15 09:44:42 +01001249 <menuitem name=\"Results\" action=\"ViewResults\" /> \
1250 <separator name=\"Separator7\"/> \
Jens Axboe9b260bd2012-03-06 11:02:52 +01001251 <menuitem name=\"Log\" action=\"ViewLog\" /> \
1252 </menu>\
Jens Axboe0420ba62012-02-29 11:16:52 +01001253 <menu name=\"Help\" action=\"HelpMenuAction\"> \
1254 <menuitem name=\"About\" action=\"About\" /> \
1255 </menu> \
1256 </menubar> \
1257 </ui> \
1258";
1259
Jens Axboe4cbe7212012-03-06 13:36:17 +01001260static GtkWidget *get_menubar_menu(GtkWidget *window, GtkUIManager *ui_manager,
1261 struct gui *ui)
Jens Axboe0420ba62012-02-29 11:16:52 +01001262{
Jens Axboeca664f42012-03-14 19:49:40 +01001263 GtkActionGroup *action_group;
Jens Axboe0420ba62012-02-29 11:16:52 +01001264 GError *error = 0;
1265
1266 action_group = gtk_action_group_new("Menu");
Jens Axboe4cbe7212012-03-06 13:36:17 +01001267 gtk_action_group_add_actions(action_group, menu_items, nmenu_items, ui);
Jens Axboe0420ba62012-02-29 11:16:52 +01001268
1269 gtk_ui_manager_insert_action_group(ui_manager, action_group, 0);
1270 gtk_ui_manager_add_ui_from_string(GTK_UI_MANAGER(ui_manager), ui_string, -1, &error);
1271
1272 gtk_window_add_accel_group(GTK_WINDOW(window), gtk_ui_manager_get_accel_group(ui_manager));
Jens Axboe02421e62012-03-12 12:05:50 +01001273
Jens Axboe0420ba62012-02-29 11:16:52 +01001274 return gtk_ui_manager_get_widget(ui_manager, "/MainMenu");
1275}
1276
1277void gfio_ui_setup(GtkSettings *settings, GtkWidget *menubar,
Jens Axboe1252d8f2012-03-21 11:13:31 +01001278 GtkWidget *vbox, GtkUIManager *ui_manager)
Jens Axboe0420ba62012-02-29 11:16:52 +01001279{
Jens Axboe1252d8f2012-03-21 11:13:31 +01001280 gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 0);
Jens Axboe0420ba62012-02-29 11:16:52 +01001281}
1282
Jens Axboec80b74b2012-03-12 10:23:28 +01001283static void combo_entry_changed(GtkComboBox *box, gpointer data)
1284{
1285 struct gui_entry *ge = (struct gui_entry *) data;
1286 gint index;
1287
1288 index = gtk_combo_box_get_active(box);
1289
1290 multitext_set_entry(&ge->eta.iotype, index);
Jens Axboe99d633a2012-03-15 15:55:04 +01001291 multitext_set_entry(&ge->eta.bs, index);
Jens Axboec80b74b2012-03-12 10:23:28 +01001292 multitext_set_entry(&ge->eta.ioengine, index);
1293 multitext_set_entry(&ge->eta.iodepth, index);
1294}
1295
1296static void combo_entry_destroy(GtkWidget *widget, gpointer data)
1297{
1298 struct gui_entry *ge = (struct gui_entry *) data;
1299
1300 multitext_free(&ge->eta.iotype);
Jens Axboe99d633a2012-03-15 15:55:04 +01001301 multitext_free(&ge->eta.bs);
Jens Axboec80b74b2012-03-12 10:23:28 +01001302 multitext_free(&ge->eta.ioengine);
1303 multitext_free(&ge->eta.iodepth);
1304}
1305
Jens Axboe2f99deb2012-03-09 14:37:29 +01001306static GtkWidget *new_client_page(struct gui_entry *ge)
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001307{
Jens Axboe2f99deb2012-03-09 14:37:29 +01001308 GtkWidget *main_vbox, *probe, *probe_frame, *probe_box;
Jens Axboe65476332012-03-13 10:37:04 +01001309 GtkWidget *scrolled_window, *bottom_align, *top_align, *top_vbox;
Jens Axboe0420ba62012-02-29 11:16:52 +01001310
Jens Axboe2f99deb2012-03-09 14:37:29 +01001311 main_vbox = gtk_vbox_new(FALSE, 3);
Stephen M. Cameron45032dd2012-02-24 08:17:31 +01001312
Jens Axboe65476332012-03-13 10:37:04 +01001313 top_align = gtk_alignment_new(0, 0, 1, 0);
1314 top_vbox = gtk_vbox_new(FALSE, 3);
1315 gtk_container_add(GTK_CONTAINER(top_align), top_vbox);
1316 gtk_box_pack_start(GTK_BOX(main_vbox), top_align, FALSE, FALSE, 0);
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +01001317
Jens Axboe3e47bd22012-02-29 13:45:02 +01001318 probe = gtk_frame_new("Job");
Jens Axboe2f99deb2012-03-09 14:37:29 +01001319 gtk_box_pack_start(GTK_BOX(main_vbox), probe, FALSE, FALSE, 3);
Jens Axboe843ad232012-02-29 11:44:53 +01001320 probe_frame = gtk_vbox_new(FALSE, 3);
1321 gtk_container_add(GTK_CONTAINER(probe), probe_frame);
1322
1323 probe_box = gtk_hbox_new(FALSE, 3);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001324 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, FALSE, FALSE, 3);
1325 ge->probe.hostname = new_info_label_in_frame(probe_box, "Host");
1326 ge->probe.os = new_info_label_in_frame(probe_box, "OS");
1327 ge->probe.arch = new_info_label_in_frame(probe_box, "Architecture");
1328 ge->probe.fio_ver = new_info_label_in_frame(probe_box, "Fio version");
Jens Axboe843ad232012-02-29 11:44:53 +01001329
Jens Axboe3e47bd22012-02-29 13:45:02 +01001330 probe_box = gtk_hbox_new(FALSE, 3);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001331 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, FALSE, FALSE, 3);
1332
Jens Axboe3863d1a2012-03-09 17:39:05 +01001333 ge->eta.names = new_combo_entry_in_frame(probe_box, "Jobs");
Jens Axboec80b74b2012-03-12 10:23:28 +01001334 g_signal_connect(ge->eta.names, "changed", G_CALLBACK(combo_entry_changed), ge);
1335 g_signal_connect(ge->eta.names, "destroy", G_CALLBACK(combo_entry_destroy), ge);
1336 ge->eta.iotype.entry = new_info_entry_in_frame(probe_box, "IO");
Jens Axboe99d633a2012-03-15 15:55:04 +01001337 ge->eta.bs.entry = new_info_entry_in_frame(probe_box, "Blocksize (Read/Write)");
Jens Axboec80b74b2012-03-12 10:23:28 +01001338 ge->eta.ioengine.entry = new_info_entry_in_frame(probe_box, "IO Engine");
1339 ge->eta.iodepth.entry = new_info_entry_in_frame(probe_box, "IO Depth");
Jens Axboe2f99deb2012-03-09 14:37:29 +01001340 ge->eta.jobs = new_info_entry_in_frame(probe_box, "Jobs");
1341 ge->eta.files = new_info_entry_in_frame(probe_box, "Open files");
1342
1343 probe_box = gtk_hbox_new(FALSE, 3);
1344 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, FALSE, FALSE, 3);
1345 ge->eta.read_bw = new_info_entry_in_frame(probe_box, "Read BW");
1346 ge->eta.read_iops = new_info_entry_in_frame(probe_box, "IOPS");
1347 ge->eta.write_bw = new_info_entry_in_frame(probe_box, "Write BW");
1348 ge->eta.write_iops = new_info_entry_in_frame(probe_box, "IOPS");
1349
1350 /*
1351 * Only add this if we have a commit rate
1352 */
1353#if 0
1354 probe_box = gtk_hbox_new(FALSE, 3);
Jens Axboe3e47bd22012-02-29 13:45:02 +01001355 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, TRUE, FALSE, 3);
Jens Axboe807f9972012-03-02 10:25:24 +01001356
Jens Axboe2f99deb2012-03-09 14:37:29 +01001357 ge->eta.cr_bw = new_info_label_in_frame(probe_box, "Commit BW");
1358 ge->eta.cr_iops = new_info_label_in_frame(probe_box, "Commit IOPS");
1359
1360 ge->eta.cw_bw = new_info_label_in_frame(probe_box, "Commit BW");
1361 ge->eta.cw_iops = new_info_label_in_frame(probe_box, "Commit IOPS");
1362#endif
1363
1364 /*
1365 * Set up a drawing area and IOPS and bandwidth graphs
1366 */
Jens Axboe2f99deb2012-03-09 14:37:29 +01001367 ge->graphs.drawing_area = gtk_drawing_area_new();
Jens Axboe2f99deb2012-03-09 14:37:29 +01001368 gtk_widget_set_size_request(GTK_WIDGET(ge->graphs.drawing_area),
Stephen M. Cameron57f9d282012-03-11 11:36:51 +01001369 DRAWING_AREA_XDIM, DRAWING_AREA_YDIM);
Jens Axboe1252d8f2012-03-21 11:13:31 +01001370 gtk_widget_modify_bg(ge->graphs.drawing_area, GTK_STATE_NORMAL, &gfio_color_white);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001371 g_signal_connect(G_OBJECT(ge->graphs.drawing_area), "expose_event",
1372 G_CALLBACK(on_expose_drawing_area), &ge->graphs);
1373 g_signal_connect(G_OBJECT(ge->graphs.drawing_area), "configure_event",
1374 G_CALLBACK(on_config_drawing_area), &ge->graphs);
Jens Axboe65476332012-03-13 10:37:04 +01001375 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
1376 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
Jens Axboe2f99deb2012-03-09 14:37:29 +01001377 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
Jens Axboe65476332012-03-13 10:37:04 +01001378 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled_window),
Jens Axboe2f99deb2012-03-09 14:37:29 +01001379 ge->graphs.drawing_area);
Jens Axboe65476332012-03-13 10:37:04 +01001380 gtk_box_pack_start(GTK_BOX(main_vbox), scrolled_window, TRUE, TRUE, 0);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001381
1382 setup_graphs(&ge->graphs);
1383
1384 /*
1385 * Set up alignments for widgets at the bottom of ui,
1386 * align bottom left, expand horizontally but not vertically
1387 */
Jens Axboe65476332012-03-13 10:37:04 +01001388 bottom_align = gtk_alignment_new(0, 1, 1, 0);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001389 ge->buttonbox = gtk_hbox_new(FALSE, 0);
Jens Axboe65476332012-03-13 10:37:04 +01001390 gtk_container_add(GTK_CONTAINER(bottom_align), ge->buttonbox);
1391 gtk_box_pack_start(GTK_BOX(main_vbox), bottom_align, FALSE, FALSE, 0);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001392
1393 add_buttons(ge, buttonspeclist, ARRAYSIZE(buttonspeclist));
1394
1395 /*
1396 * Set up thread status progress bar
1397 */
1398 ge->thread_status_pb = gtk_progress_bar_new();
1399 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(ge->thread_status_pb), 0.0);
1400 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(ge->thread_status_pb), "No connections");
1401 gtk_container_add(GTK_CONTAINER(ge->buttonbox), ge->thread_status_pb);
1402
1403
1404 return main_vbox;
1405}
1406
1407static GtkWidget *new_main_page(struct gui *ui)
1408{
1409 GtkWidget *main_vbox, *probe, *probe_frame, *probe_box;
Jens Axboe65476332012-03-13 10:37:04 +01001410 GtkWidget *scrolled_window, *bottom_align, *top_align, *top_vbox;
Jens Axboe2f99deb2012-03-09 14:37:29 +01001411
1412 main_vbox = gtk_vbox_new(FALSE, 3);
1413
1414 /*
1415 * Set up alignments for widgets at the top of ui,
1416 * align top left, expand horizontally but not vertically
1417 */
Jens Axboe65476332012-03-13 10:37:04 +01001418 top_align = gtk_alignment_new(0, 0, 1, 0);
1419 top_vbox = gtk_vbox_new(FALSE, 0);
1420 gtk_container_add(GTK_CONTAINER(top_align), top_vbox);
1421 gtk_box_pack_start(GTK_BOX(main_vbox), top_align, FALSE, FALSE, 0);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001422
1423 probe = gtk_frame_new("Run statistics");
1424 gtk_box_pack_start(GTK_BOX(main_vbox), probe, FALSE, FALSE, 3);
1425 probe_frame = gtk_vbox_new(FALSE, 3);
1426 gtk_container_add(GTK_CONTAINER(probe), probe_frame);
Jens Axboe3e47bd22012-02-29 13:45:02 +01001427
1428 probe_box = gtk_hbox_new(FALSE, 3);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001429 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, FALSE, FALSE, 3);
Jens Axboe3863d1a2012-03-09 17:39:05 +01001430 ui->eta.jobs = new_info_entry_in_frame(probe_box, "Running");
Jens Axboeca850992012-03-05 20:04:43 +01001431 ui->eta.read_bw = new_info_entry_in_frame(probe_box, "Read BW");
1432 ui->eta.read_iops = new_info_entry_in_frame(probe_box, "IOPS");
1433 ui->eta.write_bw = new_info_entry_in_frame(probe_box, "Write BW");
1434 ui->eta.write_iops = new_info_entry_in_frame(probe_box, "IOPS");
Jens Axboe807f9972012-03-02 10:25:24 +01001435
1436 /*
1437 * Only add this if we have a commit rate
1438 */
1439#if 0
1440 probe_box = gtk_hbox_new(FALSE, 3);
1441 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, TRUE, FALSE, 3);
1442
Jens Axboe3e47bd22012-02-29 13:45:02 +01001443 ui->eta.cr_bw = new_info_label_in_frame(probe_box, "Commit BW");
1444 ui->eta.cr_iops = new_info_label_in_frame(probe_box, "Commit IOPS");
1445
Jens Axboe3e47bd22012-02-29 13:45:02 +01001446 ui->eta.cw_bw = new_info_label_in_frame(probe_box, "Commit BW");
1447 ui->eta.cw_iops = new_info_label_in_frame(probe_box, "Commit IOPS");
Jens Axboe807f9972012-03-02 10:25:24 +01001448#endif
Jens Axboe3e47bd22012-02-29 13:45:02 +01001449
Stephen M. Cameron45032dd2012-02-24 08:17:31 +01001450 /*
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001451 * Set up a drawing area and IOPS and bandwidth graphs
Stephen M. Cameron736f2df2012-02-24 08:17:32 +01001452 */
Jens Axboe2f99deb2012-03-09 14:37:29 +01001453 ui->graphs.drawing_area = gtk_drawing_area_new();
Jens Axboe2f99deb2012-03-09 14:37:29 +01001454 gtk_widget_set_size_request(GTK_WIDGET(ui->graphs.drawing_area),
Stephen M. Cameron57f9d282012-03-11 11:36:51 +01001455 DRAWING_AREA_XDIM, DRAWING_AREA_YDIM);
Jens Axboe1252d8f2012-03-21 11:13:31 +01001456 gtk_widget_modify_bg(ui->graphs.drawing_area, GTK_STATE_NORMAL, &gfio_color_white);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001457 g_signal_connect(G_OBJECT(ui->graphs.drawing_area), "expose_event",
1458 G_CALLBACK(on_expose_drawing_area), &ui->graphs);
1459 g_signal_connect(G_OBJECT(ui->graphs.drawing_area), "configure_event",
1460 G_CALLBACK(on_config_drawing_area), &ui->graphs);
Jens Axboe65476332012-03-13 10:37:04 +01001461 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
1462 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
Stephen M. Cameron736f2df2012-02-24 08:17:32 +01001463 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
Jens Axboe65476332012-03-13 10:37:04 +01001464 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled_window),
Jens Axboe2f99deb2012-03-09 14:37:29 +01001465 ui->graphs.drawing_area);
Jens Axboe65476332012-03-13 10:37:04 +01001466 gtk_box_pack_start(GTK_BOX(main_vbox), scrolled_window,
Stephen M. Camerone1645342012-02-24 08:17:32 +01001467 TRUE, TRUE, 0);
Stephen M. Cameron736f2df2012-02-24 08:17:32 +01001468
Jens Axboe2f99deb2012-03-09 14:37:29 +01001469 setup_graphs(&ui->graphs);
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001470
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +01001471 /*
1472 * Set up alignments for widgets at the bottom of ui,
1473 * align bottom left, expand horizontally but not vertically
1474 */
Jens Axboe65476332012-03-13 10:37:04 +01001475 bottom_align = gtk_alignment_new(0, 1, 1, 0);
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +01001476 ui->buttonbox = gtk_hbox_new(FALSE, 0);
Jens Axboe65476332012-03-13 10:37:04 +01001477 gtk_container_add(GTK_CONTAINER(bottom_align), ui->buttonbox);
1478 gtk_box_pack_start(GTK_BOX(main_vbox), bottom_align, FALSE, FALSE, 0);
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +01001479
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001480 /*
1481 * Set up thread status progress bar
1482 */
1483 ui->thread_status_pb = gtk_progress_bar_new();
1484 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(ui->thread_status_pb), 0.0);
Jens Axboe8663ea62012-03-02 14:04:30 +01001485 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(ui->thread_status_pb), "No connections");
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001486 gtk_container_add(GTK_CONTAINER(ui->buttonbox), ui->thread_status_pb);
1487
Jens Axboe2f99deb2012-03-09 14:37:29 +01001488 return main_vbox;
1489}
1490
1491static gboolean notebook_switch_page(GtkNotebook *notebook, GtkWidget *widget,
1492 guint page, gpointer data)
1493
1494{
Jens Axboe02421e62012-03-12 12:05:50 +01001495 struct gui *ui = (struct gui *) data;
Jens Axboe85dd01e2012-03-12 14:33:16 +01001496 struct gui_entry *ge;
Jens Axboe02421e62012-03-12 12:05:50 +01001497
Jens Axboe85dd01e2012-03-12 14:33:16 +01001498 if (!page) {
1499 set_job_menu_visible(ui, 0);
Jens Axboe781ccba2012-03-15 09:44:42 +01001500 set_view_results_visible(ui, 0);
Jens Axboe85dd01e2012-03-12 14:33:16 +01001501 return TRUE;
1502 }
1503
1504 set_job_menu_visible(ui, 1);
Jens Axboe6e02ad62012-03-20 12:25:36 +01001505 ge = get_ge_from_page(ui, page, NULL);
Jens Axboe85dd01e2012-03-12 14:33:16 +01001506 if (ge)
1507 update_button_states(ui, ge);
1508
Jens Axboe2f99deb2012-03-09 14:37:29 +01001509 return TRUE;
1510}
1511
Jens Axboe38634cb2012-03-13 12:26:41 +01001512static gint compare_recent_items(GtkRecentInfo *a, GtkRecentInfo *b)
1513{
1514 time_t time_a = gtk_recent_info_get_visited(a);
1515 time_t time_b = gtk_recent_info_get_visited(b);
1516
1517 return time_b - time_a;
1518}
1519
1520static void add_recent_file_items(struct gui *ui)
1521{
1522 const gchar *gfio = g_get_application_name();
1523 GList *items, *item;
1524 int i = 0;
1525
1526 if (ui->recent_ui_id) {
1527 gtk_ui_manager_remove_ui(ui->uimanager, ui->recent_ui_id);
1528 gtk_ui_manager_ensure_update(ui->uimanager);
1529 }
1530 ui->recent_ui_id = gtk_ui_manager_new_merge_id(ui->uimanager);
1531
1532 if (ui->actiongroup) {
1533 gtk_ui_manager_remove_action_group(ui->uimanager, ui->actiongroup);
1534 g_object_unref(ui->actiongroup);
1535 }
1536 ui->actiongroup = gtk_action_group_new("RecentFileActions");
1537
1538 gtk_ui_manager_insert_action_group(ui->uimanager, ui->actiongroup, -1);
1539
1540 items = gtk_recent_manager_get_items(ui->recentmanager);
1541 items = g_list_sort(items, (GCompareFunc) compare_recent_items);
1542
1543 for (item = items; item && item->data; item = g_list_next(item)) {
1544 GtkRecentInfo *info = (GtkRecentInfo *) item->data;
1545 gchar *action_name;
1546 const gchar *label;
1547 GtkAction *action;
1548
1549 if (!gtk_recent_info_has_application(info, gfio))
1550 continue;
1551
1552 /*
1553 * We only support local files for now
1554 */
1555 if (!gtk_recent_info_is_local(info) || !gtk_recent_info_exists(info))
1556 continue;
1557
1558 action_name = g_strdup_printf("RecentFile%u", i++);
1559 label = gtk_recent_info_get_display_name(info);
1560
1561 action = g_object_new(GTK_TYPE_ACTION,
1562 "name", action_name,
1563 "label", label, NULL);
1564
1565 g_object_set_data_full(G_OBJECT(action), "gtk-recent-info",
1566 gtk_recent_info_ref(info),
1567 (GDestroyNotify) gtk_recent_info_unref);
1568
1569
1570 g_signal_connect(action, "activate", G_CALLBACK(recent_open), ui);
1571
1572 gtk_action_group_add_action(ui->actiongroup, action);
1573 g_object_unref(action);
1574
1575 gtk_ui_manager_add_ui(ui->uimanager, ui->recent_ui_id,
1576 "/MainMenu/FileMenu/FileRecentFiles",
1577 label, action_name,
1578 GTK_UI_MANAGER_MENUITEM, FALSE);
1579
1580 g_free(action_name);
1581
1582 if (i == 8)
1583 break;
1584 }
1585
1586 g_list_foreach(items, (GFunc) gtk_recent_info_unref, NULL);
1587 g_list_free(items);
1588}
1589
Jens Axboea6790902012-03-13 15:16:11 +01001590static void drag_and_drop_received(GtkWidget *widget, GdkDragContext *ctx,
Jens Axboe6e02ad62012-03-20 12:25:36 +01001591 gint x, gint y, GtkSelectionData *seldata,
1592 guint info, guint time, gpointer *data)
Jens Axboea6790902012-03-13 15:16:11 +01001593{
Jens Axboe6e02ad62012-03-20 12:25:36 +01001594 struct gui *ui = (struct gui *) data;
Jens Axboea6790902012-03-13 15:16:11 +01001595 gchar **uris;
1596 GtkWidget *source;
Jens Axboea6790902012-03-13 15:16:11 +01001597
1598 source = gtk_drag_get_source_widget(ctx);
1599 if (source && widget == gtk_widget_get_toplevel(source)) {
1600 gtk_drag_finish(ctx, FALSE, FALSE, time);
1601 return;
1602 }
1603
Jens Axboe6e02ad62012-03-20 12:25:36 +01001604 uris = gtk_selection_data_get_uris(seldata);
Jens Axboea6790902012-03-13 15:16:11 +01001605 if (!uris) {
1606 gtk_drag_finish(ctx, FALSE, FALSE, time);
1607 return;
1608 }
1609
Jens Axboe0cf3ece2012-03-21 10:15:20 +01001610 if (uris[0])
1611 do_file_open_with_tab(ui, uris[0]);
Jens Axboea6790902012-03-13 15:16:11 +01001612
1613 gtk_drag_finish(ctx, TRUE, FALSE, time);
1614 g_strfreev(uris);
1615}
1616
Jens Axboe2f99deb2012-03-09 14:37:29 +01001617static void init_ui(int *argc, char **argv[], struct gui *ui)
1618{
1619 GtkSettings *settings;
Jens Axboe02421e62012-03-12 12:05:50 +01001620 GtkWidget *vbox;
Jens Axboe2f99deb2012-03-09 14:37:29 +01001621
1622 /* Magical g*thread incantation, you just need this thread stuff.
1623 * Without it, the update that happens in gfio_update_thread_status
1624 * doesn't really happen in a timely fashion, you need expose events
1625 */
1626 if (!g_thread_supported())
1627 g_thread_init(NULL);
1628 gdk_threads_init();
1629
1630 gtk_init(argc, argv);
1631 settings = gtk_settings_get_default();
1632 gtk_settings_set_long_property(settings, "gtk_tooltip_timeout", 10, "gfio setting");
1633 g_type_init();
Jens Axboe1252d8f2012-03-21 11:13:31 +01001634 gdk_color_parse("white", &gfio_color_white);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001635
1636 ui->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
Stephen M. Cameron814479d2012-03-15 07:58:14 +01001637 gtk_window_set_title(GTK_WINDOW(ui->window), "fio");
Jens Axboe2f99deb2012-03-09 14:37:29 +01001638 gtk_window_set_default_size(GTK_WINDOW(ui->window), 1024, 768);
1639
Jens Axboe6e02ad62012-03-20 12:25:36 +01001640 g_signal_connect(ui->window, "delete-event", G_CALLBACK(quit_clicked), ui);
1641 g_signal_connect(ui->window, "destroy", G_CALLBACK(quit_clicked), ui);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001642
1643 ui->vbox = gtk_vbox_new(FALSE, 0);
1644 gtk_container_add(GTK_CONTAINER(ui->window), ui->vbox);
1645
Jens Axboe02421e62012-03-12 12:05:50 +01001646 ui->uimanager = gtk_ui_manager_new();
1647 ui->menu = get_menubar_menu(ui->window, ui->uimanager, ui);
1648 gfio_ui_setup(settings, ui->menu, ui->vbox, ui->uimanager);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001649
Jens Axboe38634cb2012-03-13 12:26:41 +01001650 ui->recentmanager = gtk_recent_manager_get_default();
1651 add_recent_file_items(ui);
1652
Jens Axboe2f99deb2012-03-09 14:37:29 +01001653 ui->notebook = gtk_notebook_new();
1654 g_signal_connect(ui->notebook, "switch-page", G_CALLBACK(notebook_switch_page), ui);
Jens Axboeb870c312012-03-09 17:22:01 +01001655 gtk_notebook_set_scrollable(GTK_NOTEBOOK(ui->notebook), 1);
Jens Axboe0aa928c2012-03-09 17:24:07 +01001656 gtk_notebook_popup_enable(GTK_NOTEBOOK(ui->notebook));
Jens Axboe2f99deb2012-03-09 14:37:29 +01001657 gtk_container_add(GTK_CONTAINER(ui->vbox), ui->notebook);
1658
1659 vbox = new_main_page(ui);
Jens Axboe0cf3ece2012-03-21 10:15:20 +01001660 gtk_drag_dest_set(GTK_WIDGET(ui->window), GTK_DEST_DEFAULT_ALL, NULL, 1, GDK_ACTION_COPY);
Jens Axboea6790902012-03-13 15:16:11 +01001661 gtk_drag_dest_add_uri_targets(GTK_WIDGET(ui->window));
1662 g_signal_connect(ui->window, "drag-data-received", G_CALLBACK(drag_and_drop_received), ui);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001663
1664 gtk_notebook_append_page(GTK_NOTEBOOK(ui->notebook), vbox, gtk_label_new("Main"));
1665
Jens Axboe9b260bd2012-03-06 11:02:52 +01001666 gfio_ui_setup_log(ui);
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001667
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001668 gtk_widget_show_all(ui->window);
1669}
1670
Stephen M. Cameron8232e282012-02-24 08:17:31 +01001671int main(int argc, char *argv[], char *envp[])
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001672{
Stephen M. Cameron8232e282012-02-24 08:17:31 +01001673 if (initialize_fio(envp))
1674 return 1;
Jens Axboe0420ba62012-02-29 11:16:52 +01001675 if (fio_init_options())
1676 return 1;
Stephen M. Camerona1820202012-02-24 08:17:31 +01001677
Jens Axboe2f99deb2012-03-09 14:37:29 +01001678 memset(&main_ui, 0, sizeof(main_ui));
1679 INIT_FLIST_HEAD(&main_ui.list);
1680
1681 init_ui(&argc, &argv, &main_ui);
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +01001682
Stephen M. Cameron2839f0c2012-02-24 08:17:31 +01001683 gdk_threads_enter();
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001684 gtk_main();
Stephen M. Cameron2839f0c2012-02-24 08:17:31 +01001685 gdk_threads_leave();
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001686 return 0;
1687}