blob: d7ae6fe9fa83a86071888ff5f78332f447dd7b63 [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
Jens Axboe470cdbb2012-03-21 12:02:13 +0100379 if (gc) {
380 if (gc->client) {
381 if (ge->state >= GE_STATE_CONNECTED)
382 fio_client_terminate(gc->client);
Jens Axboe0fd18982012-03-14 10:34:48 +0100383
Jens Axboe470cdbb2012-03-21 12:02:13 +0100384 fio_put_client(gc->client);
385 }
386 free(gc);
Jens Axboe0fd18982012-03-14 10:34:48 +0100387 }
388
Jens Axboe0cf3ece2012-03-21 10:15:20 +0100389 free(ge->job_file);
390 free(ge->host);
Jens Axboe0fd18982012-03-14 10:34:48 +0100391 flist_del(&ge->list);
392 free(ge);
393}
394
395static void ge_widget_destroy(GtkWidget *w, gpointer data)
396{
Jens Axboe2eb98bf2012-03-20 08:20:48 +0100397 struct gui_entry *ge = (struct gui_entry *) data;
398
399 ge_destroy(ge);
Jens Axboe0fd18982012-03-14 10:34:48 +0100400}
401
402static void gfio_quit(struct gui *ui)
403{
404 struct gui_entry *ge;
405
406 while (!flist_empty(&ui->list)) {
407 ge = flist_entry(ui->list.next, struct gui_entry, list);
408 ge_destroy(ge);
409 }
410
411 gtk_main_quit();
412}
413
Stephen M. Cameronff1f3282012-02-24 08:17:30 +0100414static void quit_clicked(__attribute__((unused)) GtkWidget *widget,
415 __attribute__((unused)) gpointer data)
416{
Jens Axboe6e02ad62012-03-20 12:25:36 +0100417 struct gui *ui = (struct gui *) data;
418
419 gfio_quit(ui);
Stephen M. Cameronff1f3282012-02-24 08:17:30 +0100420}
421
Stephen M. Cameron25927252012-02-24 08:17:31 +0100422static void *job_thread(void *arg)
Stephen M. Cameronf3074002012-02-24 08:17:30 +0100423{
Jens Axboea9eccde2012-03-09 14:59:42 +0100424 struct gui *ui = arg;
425
426 ui->handler_running = 1;
Stephen M. Cameron25927252012-02-24 08:17:31 +0100427 fio_handle_clients(&gfio_client_ops);
Jens Axboea9eccde2012-03-09 14:59:42 +0100428 ui->handler_running = 0;
Stephen M. Cameron25927252012-02-24 08:17:31 +0100429 return NULL;
430}
431
Jens Axboe0cf3ece2012-03-21 10:15:20 +0100432static int send_job_file(struct gui_entry *ge)
Stephen M. Cameron60f6b332012-02-24 08:17:32 +0100433{
Jens Axboe9988ca72012-03-09 15:14:06 +0100434 struct gfio_client *gc = ge->client;
Jens Axboe0cf3ece2012-03-21 10:15:20 +0100435 int ret = 0;
Stephen M. Cameron60f6b332012-02-24 08:17:32 +0100436
Jens Axboe0cf3ece2012-03-21 10:15:20 +0100437 ret = fio_client_send_ini(gc->client, ge->job_file);
438 if (!ret)
439 return 0;
Jens Axboec7249262012-03-09 17:11:04 +0100440
Jens Axboe41666582012-03-21 10:25:29 +0100441 gfio_report_error(ge, "Failed to send file %s: %s\n", ge->job_file, strerror(-ret));
Jens Axboe0cf3ece2012-03-21 10:15:20 +0100442 return 1;
Stephen M. Cameron60f6b332012-02-24 08:17:32 +0100443}
444
Jens Axboe63a130b2012-03-06 20:08:59 +0100445static void *server_thread(void *arg)
446{
447 is_backend = 1;
448 gfio_server_running = 1;
449 fio_start_server(NULL);
450 gfio_server_running = 0;
451 return NULL;
452}
453
Jens Axboe6e02ad62012-03-20 12:25:36 +0100454static void gfio_start_server(struct gui *ui)
Jens Axboe63a130b2012-03-06 20:08:59 +0100455{
456 if (!gfio_server_running) {
457 gfio_server_running = 1;
458 pthread_create(&ui->server_t, NULL, server_thread, NULL);
Jens Axboee34f6ad2012-03-06 20:47:15 +0100459 pthread_detach(ui->server_t);
Jens Axboe63a130b2012-03-06 20:08:59 +0100460 }
461}
462
Stephen M. Cameron25927252012-02-24 08:17:31 +0100463static void start_job_clicked(__attribute__((unused)) GtkWidget *widget,
464 gpointer data)
465{
Jens Axboe2f99deb2012-03-09 14:37:29 +0100466 struct gui_entry *ge = data;
467 struct gfio_client *gc = ge->client;
Stephen M. Cameron25927252012-02-24 08:17:31 +0100468
Jens Axboe78cb2fe2012-03-12 23:05:29 +0100469 if (gc)
470 fio_start_client(gc->client);
Stephen M. Cameronf3074002012-02-24 08:17:30 +0100471}
472
Jens Axboedf06f222012-03-02 13:32:04 +0100473static void file_open(GtkWidget *w, gpointer data);
474
Jens Axboe62bc9372012-03-07 11:45:07 +0100475struct connection_widgets
476{
477 GtkWidget *hentry;
478 GtkWidget *combo;
479 GtkWidget *button;
480};
481
482static void hostname_cb(GtkEntry *entry, gpointer data)
483{
484 struct connection_widgets *cw = data;
485 int uses_net = 0, is_localhost = 0;
486 const gchar *text;
487 gchar *ctext;
488
489 /*
490 * Check whether to display the 'auto start backend' box
491 * or not. Show it if we are a localhost and using network,
492 * or using a socket.
493 */
494 ctext = gtk_combo_box_get_active_text(GTK_COMBO_BOX(cw->combo));
495 if (!ctext || !strncmp(ctext, "IPv4", 4) || !strncmp(ctext, "IPv6", 4))
496 uses_net = 1;
497 g_free(ctext);
498
499 if (uses_net) {
500 text = gtk_entry_get_text(GTK_ENTRY(cw->hentry));
501 if (!strcmp(text, "127.0.0.1") || !strcmp(text, "localhost") ||
502 !strcmp(text, "::1") || !strcmp(text, "ip6-localhost") ||
503 !strcmp(text, "ip6-loopback"))
504 is_localhost = 1;
505 }
506
507 if (!uses_net || is_localhost) {
508 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cw->button), 1);
509 gtk_widget_set_sensitive(cw->button, 1);
510 } else {
511 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cw->button), 0);
512 gtk_widget_set_sensitive(cw->button, 0);
513 }
Jens Axboeb0500cc2012-03-21 11:59:18 +0100514}
Jens Axboea7a42ce2012-03-02 13:12:04 +0100515
Jens Axboeb0500cc2012-03-21 11:59:18 +0100516static int get_connection_details(struct gui_entry *ge)
517{
518 GtkWidget *dialog, *box, *vbox, *hbox, *frame, *pentry;
519 struct connection_widgets cw;
520 struct gui *ui = ge->ui;
521 char *typeentry;
Jens Axboea7a42ce2012-03-02 13:12:04 +0100522
Jens Axboeb0500cc2012-03-21 11:59:18 +0100523 if (ge->host)
Jens Axboe1252d8f2012-03-21 11:13:31 +0100524 return 0;
Jens Axboe1252d8f2012-03-21 11:13:31 +0100525
Jens Axboeb0500cc2012-03-21 11:59:18 +0100526 dialog = gtk_dialog_new_with_buttons("Connection details",
527 GTK_WINDOW(ui->window),
528 GTK_DIALOG_DESTROY_WITH_PARENT,
529 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
530 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, NULL);
Jens Axboe1252d8f2012-03-21 11:13:31 +0100531
Jens Axboeb0500cc2012-03-21 11:59:18 +0100532 frame = gtk_frame_new("Hostname / socket name");
533 /* gtk_dialog_get_content_area() is 2.14 and newer */
534 vbox = GTK_DIALOG(dialog)->vbox;
535 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
Jens Axboe1252d8f2012-03-21 11:13:31 +0100536
Jens Axboeb0500cc2012-03-21 11:59:18 +0100537 box = gtk_vbox_new(FALSE, 6);
538 gtk_container_add(GTK_CONTAINER(frame), box);
Jens Axboe1252d8f2012-03-21 11:13:31 +0100539
Jens Axboeb0500cc2012-03-21 11:59:18 +0100540 hbox = gtk_hbox_new(TRUE, 10);
541 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
542 cw.hentry = gtk_entry_new();
543 gtk_entry_set_text(GTK_ENTRY(cw.hentry), "localhost");
544 gtk_box_pack_start(GTK_BOX(hbox), cw.hentry, TRUE, TRUE, 0);
Jens Axboe1252d8f2012-03-21 11:13:31 +0100545
Jens Axboeb0500cc2012-03-21 11:59:18 +0100546 frame = gtk_frame_new("Port");
547 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
548 box = gtk_vbox_new(FALSE, 10);
549 gtk_container_add(GTK_CONTAINER(frame), box);
Jens Axboe1252d8f2012-03-21 11:13:31 +0100550
Jens Axboeb0500cc2012-03-21 11:59:18 +0100551 hbox = gtk_hbox_new(TRUE, 4);
552 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
553 pentry = create_spinbutton(hbox, 1, 65535, FIO_NET_PORT);
Jens Axboe1252d8f2012-03-21 11:13:31 +0100554
Jens Axboeb0500cc2012-03-21 11:59:18 +0100555 frame = gtk_frame_new("Type");
556 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
557 box = gtk_vbox_new(FALSE, 10);
558 gtk_container_add(GTK_CONTAINER(frame), box);
Jens Axboe1252d8f2012-03-21 11:13:31 +0100559
Jens Axboeb0500cc2012-03-21 11:59:18 +0100560 hbox = gtk_hbox_new(TRUE, 4);
561 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
Jens Axboe1252d8f2012-03-21 11:13:31 +0100562
Jens Axboeb0500cc2012-03-21 11:59:18 +0100563 cw.combo = gtk_combo_box_new_text();
564 gtk_combo_box_append_text(GTK_COMBO_BOX(cw.combo), "IPv4");
565 gtk_combo_box_append_text(GTK_COMBO_BOX(cw.combo), "IPv6");
566 gtk_combo_box_append_text(GTK_COMBO_BOX(cw.combo), "local socket");
567 gtk_combo_box_set_active(GTK_COMBO_BOX(cw.combo), 0);
Jens Axboe1252d8f2012-03-21 11:13:31 +0100568
Jens Axboeb0500cc2012-03-21 11:59:18 +0100569 gtk_container_add(GTK_CONTAINER(hbox), cw.combo);
Jens Axboe1252d8f2012-03-21 11:13:31 +0100570
Jens Axboeb0500cc2012-03-21 11:59:18 +0100571 frame = gtk_frame_new("Options");
572 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
573 box = gtk_vbox_new(FALSE, 10);
574 gtk_container_add(GTK_CONTAINER(frame), box);
Jens Axboe38634cb2012-03-13 12:26:41 +0100575
Jens Axboeb0500cc2012-03-21 11:59:18 +0100576 hbox = gtk_hbox_new(TRUE, 4);
577 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
Jens Axboe2f99deb2012-03-09 14:37:29 +0100578
Jens Axboeb0500cc2012-03-21 11:59:18 +0100579 cw.button = gtk_check_button_new_with_label("Auto-spawn fio backend");
580 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cw.button), 1);
581 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.");
582 gtk_box_pack_start(GTK_BOX(hbox), cw.button, FALSE, FALSE, 6);
Jens Axboe2f99deb2012-03-09 14:37:29 +0100583
Jens Axboe1252d8f2012-03-21 11:13:31 +0100584 /*
Jens Axboeb0500cc2012-03-21 11:59:18 +0100585 * Connect edit signal, so we can show/not-show the auto start button
Jens Axboe1252d8f2012-03-21 11:13:31 +0100586 */
Jens Axboeb0500cc2012-03-21 11:59:18 +0100587 g_signal_connect(GTK_OBJECT(cw.hentry), "changed", G_CALLBACK(hostname_cb), &cw);
588 g_signal_connect(GTK_OBJECT(cw.combo), "changed", G_CALLBACK(hostname_cb), &cw);
Jens Axboe0420ba62012-02-29 11:16:52 +0100589
Jens Axboeb0500cc2012-03-21 11:59:18 +0100590 gtk_widget_show_all(dialog);
Jens Axboe1252d8f2012-03-21 11:13:31 +0100591
Jens Axboeb0500cc2012-03-21 11:59:18 +0100592 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT) {
593 gtk_widget_destroy(dialog);
Jens Axboea6790902012-03-13 15:16:11 +0100594 return 1;
595 }
596
Jens Axboeb0500cc2012-03-21 11:59:18 +0100597 ge->host = strdup(gtk_entry_get_text(GTK_ENTRY(cw.hentry)));
598 ge->port = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(pentry));
Jens Axboea6790902012-03-13 15:16:11 +0100599
Jens Axboeb0500cc2012-03-21 11:59:18 +0100600 typeentry = gtk_combo_box_get_active_text(GTK_COMBO_BOX(cw.combo));
601 if (!typeentry || !strncmp(typeentry, "IPv4", 4))
602 ge->type = Fio_client_ipv4;
603 else if (!strncmp(typeentry, "IPv6", 4))
604 ge->type = Fio_client_ipv6;
605 else
606 ge->type = Fio_client_socket;
607 g_free(typeentry);
Jens Axboe1252d8f2012-03-21 11:13:31 +0100608
Jens Axboeb0500cc2012-03-21 11:59:18 +0100609 ge->server_start = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cw.button));
Jens Axboe1252d8f2012-03-21 11:13:31 +0100610
Jens Axboeb0500cc2012-03-21 11:59:18 +0100611 gtk_widget_destroy(dialog);
612 return 0;
613}
Jens Axboe1252d8f2012-03-21 11:13:31 +0100614
Jens Axboeb0500cc2012-03-21 11:59:18 +0100615static void gfio_set_client(struct gfio_client *gc, struct fio_client *client)
616{
617 gc->client = fio_get_client(client);
618 client->client_data = gc;
619}
Jens Axboe1252d8f2012-03-21 11:13:31 +0100620
Jens Axboeb0500cc2012-03-21 11:59:18 +0100621static void gfio_client_added(struct gui_entry *ge, struct fio_client *client)
622{
623 struct gfio_client *gc;
Jens Axboe1252d8f2012-03-21 11:13:31 +0100624
Jens Axboeb0500cc2012-03-21 11:59:18 +0100625 gc = malloc(sizeof(*gc));
626 memset(gc, 0, sizeof(*gc));
627 options_default_fill(&gc->o);
628 gc->ge = ge;
629 ge->client = gc;
630 gfio_set_client(gc, client);
631}
Jens Axboea6790902012-03-13 15:16:11 +0100632
Jens Axboeb0500cc2012-03-21 11:59:18 +0100633static void connect_clicked(GtkWidget *widget, gpointer data)
634{
635 struct gui_entry *ge = data;
636 struct gfio_client *gc = ge->client;
Jens Axboea6790902012-03-13 15:16:11 +0100637
Jens Axboeb0500cc2012-03-21 11:59:18 +0100638 if (ge->state == GE_STATE_NEW) {
639 int ret;
Jens Axboea6790902012-03-13 15:16:11 +0100640
Jens Axboeb0500cc2012-03-21 11:59:18 +0100641 if (!ge->job_file)
642 file_open(widget, ge->ui);
643 if (!ge->job_file)
Jens Axboe1252d8f2012-03-21 11:13:31 +0100644 return;
Jens Axboeb0500cc2012-03-21 11:59:18 +0100645
646 gc = ge->client;
647
648 if (!gc->client) {
649 struct fio_client *client;
650
651 if (get_connection_details(ge)) {
652 gfio_report_error(ge, "Failed to get connection details\n");
653 return;
654 }
655
656 client = fio_client_add_explicit(&gfio_client_ops, ge->host, ge->type, ge->port);
657 if (!client) {
658 gfio_report_error(ge, "Failed to add client %s\n", ge->host);
659 free(ge->host);
660 ge->host = NULL;
661 return;
662 }
663 gfio_set_client(gc, client);
Jens Axboe1252d8f2012-03-21 11:13:31 +0100664 }
Jens Axboe0420ba62012-02-29 11:16:52 +0100665
Jens Axboeb0500cc2012-03-21 11:59:18 +0100666 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(ge->thread_status_pb), "No jobs running");
667 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(ge->thread_status_pb), 0.0);
668 ret = fio_client_connect(gc->client);
669 if (!ret) {
670 if (!ge->ui->handler_running)
671 pthread_create(&ge->ui->t, NULL, job_thread, ge->ui);
672 gfio_set_state(ge, GE_STATE_CONNECTED);
673 } else {
674 gfio_report_error(ge, "Failed to connect to %s: %s\n", ge->client->client->hostname, strerror(-ret));
675 }
676 } else {
677 fio_client_terminate(gc->client);
678 gfio_set_state(ge, GE_STATE_NEW);
679 clear_ge_ui_info(ge);
680 }
681}
682
683static void send_clicked(GtkWidget *widget, gpointer data)
684{
685 struct gui_entry *ge = data;
686
687 if (send_job_file(ge))
688 gtk_widget_set_sensitive(ge->button[GFIO_BUTTON_START], 1);
689}
690
691static GtkWidget *new_client_page(struct gui_entry *ge);
692
693static struct gui_entry *alloc_new_gui_entry(struct gui *ui)
694{
695 struct gui_entry *ge;
696
697 ge = malloc(sizeof(*ge));
698 memset(ge, 0, sizeof(*ge));
699 ge->state = GE_STATE_NEW;
700 INIT_FLIST_HEAD(&ge->list);
701 flist_add_tail(&ge->list, &ui->list);
702 ge->ui = ui;
703 return ge;
704}
705
706static struct gui_entry *get_new_ge_with_tab(struct gui *ui, const char *name)
707{
708 struct gui_entry *ge;
709
710 ge = alloc_new_gui_entry(ui);
711
712 ge->vbox = new_client_page(ge);
713 g_signal_connect(ge->vbox, "destroy", G_CALLBACK(ge_widget_destroy), ge);
714
715 ge->page_label = gtk_label_new(name);
716 ge->page_num = gtk_notebook_append_page(GTK_NOTEBOOK(ui->notebook), ge->vbox, ge->page_label);
717
718 gtk_widget_show_all(ui->window);
719 return ge;
720}
721
722static void file_new(GtkWidget *w, gpointer data)
723{
724 struct gui *ui = (struct gui *) data;
725 struct gui_entry *ge;
726
727 ge = get_new_ge_with_tab(ui, "Untitled");
728 gtk_notebook_set_current_page(GTK_NOTEBOOK(ui->notebook), ge->page_num);
729}
730
731/*
732 * Return the 'ge' corresponding to the tab. If the active tab is the
733 * main tab, open a new tab.
734 */
735static struct gui_entry *get_ge_from_page(struct gui *ui, gint cur_page,
736 int *created)
737{
738 struct flist_head *entry;
739 struct gui_entry *ge;
740
741 if (!cur_page) {
742 if (created)
743 *created = 1;
744 return get_new_ge_with_tab(ui, "Untitled");
745 }
746
747 if (created)
748 *created = 0;
749
750 flist_for_each(entry, &ui->list) {
751 ge = flist_entry(entry, struct gui_entry, list);
752 if (ge->page_num == cur_page)
753 return ge;
754 }
755
756 return NULL;
757}
758
759static struct gui_entry *get_ge_from_cur_tab(struct gui *ui)
760{
761 gint cur_page;
762
763 /*
764 * Main tab is tab 0, so any current page other than 0 holds
765 * a ge entry.
766 */
767 cur_page = gtk_notebook_get_current_page(GTK_NOTEBOOK(ui->notebook));
768 if (cur_page)
769 return get_ge_from_page(ui, cur_page, NULL);
770
771 return NULL;
772}
773
774static void file_close(GtkWidget *w, gpointer data)
775{
776 struct gui *ui = (struct gui *) data;
777 struct gui_entry *ge;
778
779 /*
780 * Can't close the main tab
781 */
782 ge = get_ge_from_cur_tab(ui);
783 if (ge) {
784 gtk_widget_destroy(ge->vbox);
785 return;
786 }
787
788 if (!flist_empty(&ui->list)) {
789 gfio_report_info(ui, "Error", "The main page view cannot be closed\n");
790 return;
791 }
792
793 gfio_quit(ui);
794}
795
796static void file_add_recent(struct gui *ui, const gchar *uri)
797{
798 GtkRecentData grd;
799
800 memset(&grd, 0, sizeof(grd));
801 grd.display_name = strdup("gfio");
802 grd.description = strdup("Fio job file");
803 grd.mime_type = strdup(GFIO_MIME);
804 grd.app_name = strdup(g_get_application_name());
805 grd.app_exec = strdup("gfio %f/%u");
806
807 gtk_recent_manager_add_full(ui->recentmanager, uri, &grd);
808}
809
810static gchar *get_filename_from_uri(const gchar *uri)
811{
812 if (strncmp(uri, "file://", 7))
813 return strdup(uri);
814
815 return strdup(uri + 7);
816}
817
818static int do_file_open(struct gui_entry *ge, const gchar *uri)
819{
820 struct fio_client *client;
821
822 assert(!ge->job_file);
823
824 ge->job_file = get_filename_from_uri(uri);
825
826 client = fio_client_add_explicit(&gfio_client_ops, ge->host, ge->type, ge->port);
827 if (client) {
828 gfio_client_added(ge, client);
829 file_add_recent(ge->ui, uri);
830 return 0;
831 }
832
833 gfio_report_error(ge, "Failed to add client %s\n", ge->host);
834 free(ge->host);
835 ge->host = NULL;
836 return 1;
837}
838
839static int do_file_open_with_tab(struct gui *ui, const gchar *uri)
840{
841 struct gui_entry *ge;
842 gint cur_page;
843 int ret, ge_is_new = 0;
844
845 /*
846 * Creates new tab if current tab is the main window, or the
847 * current tab already has a client.
848 */
849 cur_page = gtk_notebook_get_current_page(GTK_NOTEBOOK(ui->notebook));
850 ge = get_ge_from_page(ui, cur_page, &ge_is_new);
851 if (ge->client) {
852 ge = get_new_ge_with_tab(ui, "Untitled");
853 ge_is_new = 1;
854 }
855
856 gtk_notebook_set_current_page(GTK_NOTEBOOK(ui->notebook), ge->page_num);
857
858 if (get_connection_details(ge)) {
859 if (ge_is_new)
860 gtk_widget_destroy(ge->vbox);
861
862 return 1;
863 }
864
865 ret = do_file_open(ge, uri);
866
867 if (!ret) {
868 if (ge->server_start)
869 gfio_start_server(ui);
870 } else {
871 if (ge_is_new)
872 gtk_widget_destroy(ge->vbox);
873 }
874
875 return ret;
876}
877
878static void recent_open(GtkAction *action, gpointer data)
879{
880 struct gui *ui = (struct gui *) data;
881 GtkRecentInfo *info;
882 const gchar *uri;
883
884 info = g_object_get_data(G_OBJECT(action), "gtk-recent-info");
885 uri = gtk_recent_info_get_uri(info);
886
887 do_file_open_with_tab(ui, uri);
888}
889
890static void file_open(GtkWidget *w, gpointer data)
891{
892 struct gui *ui = data;
893 GtkWidget *dialog;
894 GtkFileFilter *filter;
895 gchar *filename;
896
897 dialog = gtk_file_chooser_dialog_new("Open File",
898 GTK_WINDOW(ui->window),
899 GTK_FILE_CHOOSER_ACTION_OPEN,
900 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
901 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
902 NULL);
903 gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), FALSE);
904
905 filter = gtk_file_filter_new();
906 gtk_file_filter_add_pattern(filter, "*.fio");
907 gtk_file_filter_add_pattern(filter, "*.job");
908 gtk_file_filter_add_pattern(filter, "*.ini");
909 gtk_file_filter_add_mime_type(filter, GFIO_MIME);
910 gtk_file_filter_set_name(filter, "Fio job file");
911 gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(dialog), filter);
912
913 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT) {
914 gtk_widget_destroy(dialog);
915 return;
916 }
917
918 filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
919
920 gtk_widget_destroy(dialog);
921
922 do_file_open_with_tab(ui, filename);
923 g_free(filename);
924}
925
926static void file_save(GtkWidget *w, gpointer data)
927{
928 struct gui *ui = data;
929 GtkWidget *dialog;
930
931 dialog = gtk_file_chooser_dialog_new("Save File",
932 GTK_WINDOW(ui->window),
933 GTK_FILE_CHOOSER_ACTION_SAVE,
934 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
935 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
936 NULL);
937
938 gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE);
939 gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), "Untitled document");
940
941 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
942 char *filename;
943
Jens Axboe0420ba62012-02-29 11:16:52 +0100944 filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
Jens Axboeb0500cc2012-03-21 11:59:18 +0100945 // save_job_file(filename);
Jens Axboe0420ba62012-02-29 11:16:52 +0100946 g_free(filename);
947 }
Jens Axboeb0500cc2012-03-21 11:59:18 +0100948 gtk_widget_destroy(dialog);
949}
Jens Axboe0420ba62012-02-29 11:16:52 +0100950
Jens Axboe9b260bd2012-03-06 11:02:52 +0100951static void view_log_destroy(GtkWidget *w, gpointer data)
952{
953 struct gui *ui = (struct gui *) data;
954
955 gtk_widget_ref(ui->log_tree);
956 gtk_container_remove(GTK_CONTAINER(w), ui->log_tree);
957 gtk_widget_destroy(w);
Jens Axboe4cbe7212012-03-06 13:36:17 +0100958 ui->log_view = NULL;
Jens Axboe9b260bd2012-03-06 11:02:52 +0100959}
960
Jens Axboe1252d8f2012-03-21 11:13:31 +0100961void gfio_view_log(struct gui *ui)
Jens Axboe9b260bd2012-03-06 11:02:52 +0100962{
Jens Axboe4cbe7212012-03-06 13:36:17 +0100963 GtkWidget *win, *scroll, *vbox, *box;
Jens Axboe9b260bd2012-03-06 11:02:52 +0100964
Jens Axboe4cbe7212012-03-06 13:36:17 +0100965 if (ui->log_view)
966 return;
967
968 ui->log_view = win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
Jens Axboe9b260bd2012-03-06 11:02:52 +0100969 gtk_window_set_title(GTK_WINDOW(win), "Log");
Jens Axboe4cbe7212012-03-06 13:36:17 +0100970 gtk_window_set_default_size(GTK_WINDOW(win), 700, 500);
Jens Axboe9b260bd2012-03-06 11:02:52 +0100971
Jens Axboe4cbe7212012-03-06 13:36:17 +0100972 scroll = gtk_scrolled_window_new(NULL, NULL);
Jens Axboe9b260bd2012-03-06 11:02:52 +0100973
Jens Axboe4cbe7212012-03-06 13:36:17 +0100974 gtk_container_set_border_width(GTK_CONTAINER(scroll), 5);
975
976 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
977
978 box = gtk_hbox_new(TRUE, 0);
979 gtk_box_pack_start_defaults(GTK_BOX(box), ui->log_tree);
980 g_signal_connect(box, "destroy", G_CALLBACK(view_log_destroy), ui);
981 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroll), box);
982
983 vbox = gtk_vbox_new(TRUE, 5);
984 gtk_box_pack_start_defaults(GTK_BOX(vbox), scroll);
985
986 gtk_container_add(GTK_CONTAINER(win), vbox);
Jens Axboe9b260bd2012-03-06 11:02:52 +0100987 gtk_widget_show_all(win);
988}
989
Jens Axboe1252d8f2012-03-21 11:13:31 +0100990static void view_log(GtkWidget *w, gpointer data)
991{
992 struct gui *ui = (struct gui *) data;
993
994 gfio_view_log(ui);
995}
996
Jens Axboe85dd01e2012-03-12 14:33:16 +0100997static void connect_job_entry(GtkWidget *w, gpointer data)
Jens Axboe16ce5ad2012-03-12 11:56:09 +0100998{
Jens Axboe85dd01e2012-03-12 14:33:16 +0100999 struct gui *ui = (struct gui *) data;
1000 struct gui_entry *ge;
1001
1002 ge = get_ge_from_cur_tab(ui);
1003 if (ge)
1004 connect_clicked(w, ge);
1005}
1006
1007static void send_job_entry(GtkWidget *w, gpointer data)
1008{
1009 struct gui *ui = (struct gui *) data;
1010 struct gui_entry *ge;
1011
1012 ge = get_ge_from_cur_tab(ui);
1013 if (ge)
1014 send_clicked(w, ge);
Jens Axboe85dd01e2012-03-12 14:33:16 +01001015}
1016
1017static void edit_job_entry(GtkWidget *w, gpointer data)
1018{
Jens Axboe9af4a242012-03-16 10:13:49 +01001019 struct gui *ui = (struct gui *) data;
Jens Axboe789f4cc2012-03-16 14:56:44 +01001020 struct gui_entry *ge;
Jens Axboe9af4a242012-03-16 10:13:49 +01001021
Jens Axboe789f4cc2012-03-16 14:56:44 +01001022 ge = get_ge_from_cur_tab(ui);
1023 if (ge && ge->client)
1024 gopt_get_options_window(ui->window, &ge->client->o);
Jens Axboe85dd01e2012-03-12 14:33:16 +01001025}
1026
1027static void start_job_entry(GtkWidget *w, gpointer data)
1028{
1029 struct gui *ui = (struct gui *) data;
1030 struct gui_entry *ge;
1031
1032 ge = get_ge_from_cur_tab(ui);
1033 if (ge)
1034 start_job_clicked(w, ge);
Jens Axboe16ce5ad2012-03-12 11:56:09 +01001035}
1036
Jens Axboe781ccba2012-03-15 09:44:42 +01001037static void view_results(GtkWidget *w, gpointer data)
1038{
1039 struct gui *ui = (struct gui *) data;
1040 struct gfio_client *gc;
1041 struct gui_entry *ge;
1042
1043 ge = get_ge_from_cur_tab(ui);
1044 if (!ge)
1045 return;
1046
1047 if (ge->results_window)
1048 return;
1049
1050 gc = ge->client;
1051 if (gc && gc->nr_results)
1052 gfio_display_end_results(gc);
1053}
1054
Jens Axboe8577f4f2012-03-09 19:28:27 +01001055static void __update_graph_limits(struct gfio_graphs *g)
1056{
1057 line_graph_set_data_count_limit(g->iops_graph, gfio_graph_limit);
1058 line_graph_set_data_count_limit(g->bandwidth_graph, gfio_graph_limit);
1059}
1060
1061static void update_graph_limits(void)
1062{
1063 struct flist_head *entry;
1064 struct gui_entry *ge;
1065
1066 __update_graph_limits(&main_ui.graphs);
1067
1068 flist_for_each(entry, &main_ui.list) {
1069 ge = flist_entry(entry, struct gui_entry, list);
1070 __update_graph_limits(&ge->graphs);
1071 }
1072}
1073
Jens Axboe46974a72012-03-02 19:34:13 +01001074static void preferences(GtkWidget *w, gpointer data)
1075{
Jens Axboef3e84402012-03-07 13:14:32 +01001076 GtkWidget *dialog, *frame, *box, **buttons, *vbox, *font;
Jens Axboe1cf6bca2012-03-09 20:20:17 +01001077 GtkWidget *hbox, *spin, *entry, *spin_int;
Jens Axboe6e02ad62012-03-20 12:25:36 +01001078 struct gui *ui = (struct gui *) data;
Jens Axboe46974a72012-03-02 19:34:13 +01001079 int i;
1080
1081 dialog = gtk_dialog_new_with_buttons("Preferences",
Jens Axboe6e02ad62012-03-20 12:25:36 +01001082 GTK_WINDOW(ui->window),
Jens Axboe46974a72012-03-02 19:34:13 +01001083 GTK_DIALOG_DESTROY_WITH_PARENT,
1084 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
1085 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
1086 NULL);
1087
Jens Axboe8577f4f2012-03-09 19:28:27 +01001088 frame = gtk_frame_new("Graphing");
Jens Axboef3e84402012-03-07 13:14:32 +01001089 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), frame, FALSE, FALSE, 5);
1090 vbox = gtk_vbox_new(FALSE, 6);
1091 gtk_container_add(GTK_CONTAINER(frame), vbox);
1092
Jens Axboe1cf6bca2012-03-09 20:20:17 +01001093 hbox = gtk_hbox_new(FALSE, 5);
1094 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 5);
1095 entry = gtk_label_new("Font face to use for graph labels");
1096 gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 5);
1097
Jens Axboef3e84402012-03-07 13:14:32 +01001098 font = gtk_font_button_new();
Jens Axboe1cf6bca2012-03-09 20:20:17 +01001099 gtk_box_pack_start(GTK_BOX(hbox), font, FALSE, FALSE, 5);
Jens Axboef3e84402012-03-07 13:14:32 +01001100
Jens Axboe8577f4f2012-03-09 19:28:27 +01001101 box = gtk_vbox_new(FALSE, 6);
1102 gtk_box_pack_start(GTK_BOX(vbox), box, FALSE, FALSE, 5);
1103
1104 hbox = gtk_hbox_new(FALSE, 5);
Jens Axboe1cf6bca2012-03-09 20:20:17 +01001105 gtk_box_pack_start(GTK_BOX(box), hbox, TRUE, TRUE, 5);
Jens Axboe8577f4f2012-03-09 19:28:27 +01001106 entry = gtk_label_new("Maximum number of data points in graph (seconds)");
1107 gtk_box_pack_start(GTK_BOX(hbox), entry, FALSE, FALSE, 5);
1108
Jens Axboec05d9052012-03-11 13:05:35 +01001109 spin = create_spinbutton(hbox, 10, 1000000, gfio_graph_limit);
Jens Axboe8577f4f2012-03-09 19:28:27 +01001110
Jens Axboe1cf6bca2012-03-09 20:20:17 +01001111 box = gtk_vbox_new(FALSE, 6);
1112 gtk_box_pack_start(GTK_BOX(vbox), box, FALSE, FALSE, 5);
1113
1114 hbox = gtk_hbox_new(FALSE, 5);
1115 gtk_box_pack_start(GTK_BOX(box), hbox, TRUE, TRUE, 5);
1116 entry = gtk_label_new("Client ETA request interval (msec)");
1117 gtk_box_pack_start(GTK_BOX(hbox), entry, FALSE, FALSE, 5);
1118
1119 spin_int = create_spinbutton(hbox, 100, 100000, gfio_client_ops.eta_msec);
Jens Axboea31d9fa2012-03-09 20:23:05 +01001120 frame = gtk_frame_new("Debug logging");
1121 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), frame, FALSE, FALSE, 5);
1122 vbox = gtk_vbox_new(FALSE, 6);
1123 gtk_container_add(GTK_CONTAINER(frame), vbox);
1124
1125 box = gtk_hbox_new(FALSE, 6);
1126 gtk_container_add(GTK_CONTAINER(vbox), box);
1127
1128 buttons = malloc(sizeof(GtkWidget *) * FD_DEBUG_MAX);
1129
1130 for (i = 0; i < FD_DEBUG_MAX; i++) {
1131 if (i == 7) {
1132 box = gtk_hbox_new(FALSE, 6);
1133 gtk_container_add(GTK_CONTAINER(vbox), box);
1134 }
1135
1136
1137 buttons[i] = gtk_check_button_new_with_label(debug_levels[i].name);
1138 gtk_widget_set_tooltip_text(buttons[i], debug_levels[i].help);
1139 gtk_box_pack_start(GTK_BOX(box), buttons[i], FALSE, FALSE, 6);
1140 }
1141
Jens Axboe46974a72012-03-02 19:34:13 +01001142 gtk_widget_show_all(dialog);
1143
1144 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT) {
1145 gtk_widget_destroy(dialog);
1146 return;
1147 }
1148
1149 for (i = 0; i < FD_DEBUG_MAX; i++) {
1150 int set;
1151
1152 set = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(buttons[i]));
1153 if (set)
1154 fio_debug |= (1UL << i);
1155 }
1156
Jens Axboef3e84402012-03-07 13:14:32 +01001157 gfio_graph_font = strdup(gtk_font_button_get_font_name(GTK_FONT_BUTTON(font)));
Jens Axboe8577f4f2012-03-09 19:28:27 +01001158 gfio_graph_limit = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spin));
1159 update_graph_limits();
Jens Axboe1cf6bca2012-03-09 20:20:17 +01001160 gfio_client_ops.eta_msec = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spin_int));
Jens Axboe8577f4f2012-03-09 19:28:27 +01001161
Jens Axboe46974a72012-03-02 19:34:13 +01001162 gtk_widget_destroy(dialog);
1163}
1164
Jens Axboe0420ba62012-02-29 11:16:52 +01001165static void about_dialog(GtkWidget *w, gpointer data)
1166{
Jens Axboe81e4ea62012-03-07 14:18:28 +01001167 const char *authors[] = {
1168 "Jens Axboe <axboe@kernel.dk>",
1169 "Stephen Carmeron <stephenmcameron@gmail.com>",
1170 NULL
1171 };
Jens Axboe84a72ed2012-03-07 14:24:57 +01001172 const char *license[] = {
1173 "Fio is free software; you can redistribute it and/or modify "
1174 "it under the terms of the GNU General Public License as published by "
1175 "the Free Software Foundation; either version 2 of the License, or "
1176 "(at your option) any later version.\n",
1177 "Fio is distributed in the hope that it will be useful, "
1178 "but WITHOUT ANY WARRANTY; without even the implied warranty of "
1179 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the "
1180 "GNU General Public License for more details.\n",
1181 "You should have received a copy of the GNU General Public License "
1182 "along with Fio; if not, write to the Free Software Foundation, Inc., "
1183 "51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n"
1184 };
1185 char *license_trans;
1186
1187 license_trans = g_strconcat(license[0], "\n", license[1], "\n",
1188 license[2], "\n", NULL);
Jens Axboe81e4ea62012-03-07 14:18:28 +01001189
Jens Axboe0420ba62012-02-29 11:16:52 +01001190 gtk_show_about_dialog(NULL,
1191 "program-name", "gfio",
1192 "comments", "Gtk2 UI for fio",
Jens Axboe84a72ed2012-03-07 14:24:57 +01001193 "license", license_trans,
Jens Axboe81e4ea62012-03-07 14:18:28 +01001194 "website", "http://git.kernel.dk/?p=fio.git;a=summary",
1195 "authors", authors,
Jens Axboe0420ba62012-02-29 11:16:52 +01001196 "version", fio_version_string,
Jens Axboe81e4ea62012-03-07 14:18:28 +01001197 "copyright", "© 2012 Jens Axboe <axboe@kernel.dk>",
Jens Axboe0420ba62012-02-29 11:16:52 +01001198 "logo-icon-name", "fio",
1199 /* Must be last: */
Jens Axboe81e4ea62012-03-07 14:18:28 +01001200 "wrap-license", TRUE,
Jens Axboe0420ba62012-02-29 11:16:52 +01001201 NULL);
Jens Axboe84a72ed2012-03-07 14:24:57 +01001202
Jens Axboe2f99deb2012-03-09 14:37:29 +01001203 g_free(license_trans);
Jens Axboe0420ba62012-02-29 11:16:52 +01001204}
1205
1206static GtkActionEntry menu_items[] = {
Jens Axboe46974a72012-03-02 19:34:13 +01001207 { "FileMenuAction", GTK_STOCK_FILE, "File", NULL, NULL, NULL},
Jens Axboe9b260bd2012-03-06 11:02:52 +01001208 { "ViewMenuAction", GTK_STOCK_FILE, "View", NULL, NULL, NULL},
Jens Axboe16ce5ad2012-03-12 11:56:09 +01001209 { "JobMenuAction", GTK_STOCK_FILE, "Job", NULL, NULL, NULL},
Jens Axboe46974a72012-03-02 19:34:13 +01001210 { "HelpMenuAction", GTK_STOCK_HELP, "Help", NULL, NULL, NULL},
Jens Axboe2f99deb2012-03-09 14:37:29 +01001211 { "NewFile", GTK_STOCK_NEW, "New", "<Control>N", NULL, G_CALLBACK(file_new) },
Jens Axboe16ce5ad2012-03-12 11:56:09 +01001212 { "CloseFile", GTK_STOCK_CLOSE, "Close", "<Control>W", NULL, G_CALLBACK(file_close) },
Jens Axboe46974a72012-03-02 19:34:13 +01001213 { "OpenFile", GTK_STOCK_OPEN, NULL, "<Control>O", NULL, G_CALLBACK(file_open) },
1214 { "SaveFile", GTK_STOCK_SAVE, NULL, "<Control>S", NULL, G_CALLBACK(file_save) },
1215 { "Preferences", GTK_STOCK_PREFERENCES, NULL, "<Control>p", NULL, G_CALLBACK(preferences) },
Jens Axboe9b260bd2012-03-06 11:02:52 +01001216 { "ViewLog", NULL, "Log", "<Control>l", NULL, G_CALLBACK(view_log) },
Jens Axboe781ccba2012-03-15 09:44:42 +01001217 { "ViewResults", NULL, "Results", "<Control>R", NULL, G_CALLBACK(view_results) },
Jens Axboebc271d82012-03-15 21:57:40 +01001218 { "ConnectJob", NULL, "Connect", "<Control>D", NULL, G_CALLBACK(connect_job_entry) },
Jens Axboe85dd01e2012-03-12 14:33:16 +01001219 { "EditJob", NULL, "Edit job", "<Control>E", NULL, G_CALLBACK(edit_job_entry) },
1220 { "SendJob", NULL, "Send job", "<Control>X", NULL, G_CALLBACK(send_job_entry) },
1221 { "StartJob", NULL, "Start job", "<Control>L", NULL, G_CALLBACK(start_job_entry) },
Jens Axboe46974a72012-03-02 19:34:13 +01001222 { "Quit", GTK_STOCK_QUIT, NULL, "<Control>Q", NULL, G_CALLBACK(quit_clicked) },
1223 { "About", GTK_STOCK_ABOUT, NULL, NULL, NULL, G_CALLBACK(about_dialog) },
Jens Axboe0420ba62012-02-29 11:16:52 +01001224};
Jens Axboe3e47bd22012-02-29 13:45:02 +01001225static gint nmenu_items = sizeof(menu_items) / sizeof(menu_items[0]);
Jens Axboe0420ba62012-02-29 11:16:52 +01001226
1227static const gchar *ui_string = " \
1228 <ui> \
1229 <menubar name=\"MainMenu\"> \
1230 <menu name=\"FileMenu\" action=\"FileMenuAction\"> \
Jens Axboe2f99deb2012-03-09 14:37:29 +01001231 <menuitem name=\"New\" action=\"NewFile\" /> \
Jens Axboebf641382012-03-15 13:46:16 +01001232 <menuitem name=\"Open\" action=\"OpenFile\" /> \
Jens Axboe16ce5ad2012-03-12 11:56:09 +01001233 <menuitem name=\"Close\" action=\"CloseFile\" /> \
Jens Axboe2f99deb2012-03-09 14:37:29 +01001234 <separator name=\"Separator1\"/> \
Jens Axboe0420ba62012-02-29 11:16:52 +01001235 <menuitem name=\"Save\" action=\"SaveFile\" /> \
Jens Axboe46974a72012-03-02 19:34:13 +01001236 <separator name=\"Separator2\"/> \
Jens Axboe2f99deb2012-03-09 14:37:29 +01001237 <menuitem name=\"Preferences\" action=\"Preferences\" /> \
1238 <separator name=\"Separator3\"/> \
Jens Axboe261f21d2012-03-12 14:58:22 +01001239 <placeholder name=\"FileRecentFiles\"/> \
1240 <separator name=\"Separator4\"/> \
Jens Axboe0420ba62012-02-29 11:16:52 +01001241 <menuitem name=\"Quit\" action=\"Quit\" /> \
1242 </menu> \
Jens Axboe16ce5ad2012-03-12 11:56:09 +01001243 <menu name=\"JobMenu\" action=\"JobMenuAction\"> \
Jens Axboe85dd01e2012-03-12 14:33:16 +01001244 <menuitem name=\"Connect\" action=\"ConnectJob\" /> \
Jens Axboe261f21d2012-03-12 14:58:22 +01001245 <separator name=\"Separator5\"/> \
Jens Axboe85dd01e2012-03-12 14:33:16 +01001246 <menuitem name=\"Edit job\" action=\"EditJob\" /> \
1247 <menuitem name=\"Send job\" action=\"SendJob\" /> \
Jens Axboe261f21d2012-03-12 14:58:22 +01001248 <separator name=\"Separator6\"/> \
Jens Axboe85dd01e2012-03-12 14:33:16 +01001249 <menuitem name=\"Start job\" action=\"StartJob\" /> \
Jens Axboe16ce5ad2012-03-12 11:56:09 +01001250 </menu>\
Jens Axboe9b260bd2012-03-06 11:02:52 +01001251 <menu name=\"ViewMenu\" action=\"ViewMenuAction\"> \
Jens Axboe781ccba2012-03-15 09:44:42 +01001252 <menuitem name=\"Results\" action=\"ViewResults\" /> \
1253 <separator name=\"Separator7\"/> \
Jens Axboe9b260bd2012-03-06 11:02:52 +01001254 <menuitem name=\"Log\" action=\"ViewLog\" /> \
1255 </menu>\
Jens Axboe0420ba62012-02-29 11:16:52 +01001256 <menu name=\"Help\" action=\"HelpMenuAction\"> \
1257 <menuitem name=\"About\" action=\"About\" /> \
1258 </menu> \
1259 </menubar> \
1260 </ui> \
1261";
1262
Jens Axboe4cbe7212012-03-06 13:36:17 +01001263static GtkWidget *get_menubar_menu(GtkWidget *window, GtkUIManager *ui_manager,
1264 struct gui *ui)
Jens Axboe0420ba62012-02-29 11:16:52 +01001265{
Jens Axboeca664f42012-03-14 19:49:40 +01001266 GtkActionGroup *action_group;
Jens Axboe0420ba62012-02-29 11:16:52 +01001267 GError *error = 0;
1268
1269 action_group = gtk_action_group_new("Menu");
Jens Axboe4cbe7212012-03-06 13:36:17 +01001270 gtk_action_group_add_actions(action_group, menu_items, nmenu_items, ui);
Jens Axboe0420ba62012-02-29 11:16:52 +01001271
1272 gtk_ui_manager_insert_action_group(ui_manager, action_group, 0);
1273 gtk_ui_manager_add_ui_from_string(GTK_UI_MANAGER(ui_manager), ui_string, -1, &error);
1274
1275 gtk_window_add_accel_group(GTK_WINDOW(window), gtk_ui_manager_get_accel_group(ui_manager));
Jens Axboe02421e62012-03-12 12:05:50 +01001276
Jens Axboe0420ba62012-02-29 11:16:52 +01001277 return gtk_ui_manager_get_widget(ui_manager, "/MainMenu");
1278}
1279
1280void gfio_ui_setup(GtkSettings *settings, GtkWidget *menubar,
Jens Axboe1252d8f2012-03-21 11:13:31 +01001281 GtkWidget *vbox, GtkUIManager *ui_manager)
Jens Axboe0420ba62012-02-29 11:16:52 +01001282{
Jens Axboe1252d8f2012-03-21 11:13:31 +01001283 gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 0);
Jens Axboe0420ba62012-02-29 11:16:52 +01001284}
1285
Jens Axboec80b74b2012-03-12 10:23:28 +01001286static void combo_entry_changed(GtkComboBox *box, gpointer data)
1287{
1288 struct gui_entry *ge = (struct gui_entry *) data;
1289 gint index;
1290
1291 index = gtk_combo_box_get_active(box);
1292
1293 multitext_set_entry(&ge->eta.iotype, index);
Jens Axboe99d633a2012-03-15 15:55:04 +01001294 multitext_set_entry(&ge->eta.bs, index);
Jens Axboec80b74b2012-03-12 10:23:28 +01001295 multitext_set_entry(&ge->eta.ioengine, index);
1296 multitext_set_entry(&ge->eta.iodepth, index);
1297}
1298
1299static void combo_entry_destroy(GtkWidget *widget, gpointer data)
1300{
1301 struct gui_entry *ge = (struct gui_entry *) data;
1302
1303 multitext_free(&ge->eta.iotype);
Jens Axboe99d633a2012-03-15 15:55:04 +01001304 multitext_free(&ge->eta.bs);
Jens Axboec80b74b2012-03-12 10:23:28 +01001305 multitext_free(&ge->eta.ioengine);
1306 multitext_free(&ge->eta.iodepth);
1307}
1308
Jens Axboe2f99deb2012-03-09 14:37:29 +01001309static GtkWidget *new_client_page(struct gui_entry *ge)
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001310{
Jens Axboe2f99deb2012-03-09 14:37:29 +01001311 GtkWidget *main_vbox, *probe, *probe_frame, *probe_box;
Jens Axboe65476332012-03-13 10:37:04 +01001312 GtkWidget *scrolled_window, *bottom_align, *top_align, *top_vbox;
Jens Axboe0420ba62012-02-29 11:16:52 +01001313
Jens Axboe2f99deb2012-03-09 14:37:29 +01001314 main_vbox = gtk_vbox_new(FALSE, 3);
Stephen M. Cameron45032dd2012-02-24 08:17:31 +01001315
Jens Axboe65476332012-03-13 10:37:04 +01001316 top_align = gtk_alignment_new(0, 0, 1, 0);
1317 top_vbox = gtk_vbox_new(FALSE, 3);
1318 gtk_container_add(GTK_CONTAINER(top_align), top_vbox);
1319 gtk_box_pack_start(GTK_BOX(main_vbox), top_align, FALSE, FALSE, 0);
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +01001320
Jens Axboe3e47bd22012-02-29 13:45:02 +01001321 probe = gtk_frame_new("Job");
Jens Axboe2f99deb2012-03-09 14:37:29 +01001322 gtk_box_pack_start(GTK_BOX(main_vbox), probe, FALSE, FALSE, 3);
Jens Axboe843ad232012-02-29 11:44:53 +01001323 probe_frame = gtk_vbox_new(FALSE, 3);
1324 gtk_container_add(GTK_CONTAINER(probe), probe_frame);
1325
1326 probe_box = gtk_hbox_new(FALSE, 3);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001327 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, FALSE, FALSE, 3);
1328 ge->probe.hostname = new_info_label_in_frame(probe_box, "Host");
1329 ge->probe.os = new_info_label_in_frame(probe_box, "OS");
1330 ge->probe.arch = new_info_label_in_frame(probe_box, "Architecture");
1331 ge->probe.fio_ver = new_info_label_in_frame(probe_box, "Fio version");
Jens Axboe843ad232012-02-29 11:44:53 +01001332
Jens Axboe3e47bd22012-02-29 13:45:02 +01001333 probe_box = gtk_hbox_new(FALSE, 3);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001334 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, FALSE, FALSE, 3);
1335
Jens Axboe3863d1a2012-03-09 17:39:05 +01001336 ge->eta.names = new_combo_entry_in_frame(probe_box, "Jobs");
Jens Axboec80b74b2012-03-12 10:23:28 +01001337 g_signal_connect(ge->eta.names, "changed", G_CALLBACK(combo_entry_changed), ge);
1338 g_signal_connect(ge->eta.names, "destroy", G_CALLBACK(combo_entry_destroy), ge);
1339 ge->eta.iotype.entry = new_info_entry_in_frame(probe_box, "IO");
Jens Axboe99d633a2012-03-15 15:55:04 +01001340 ge->eta.bs.entry = new_info_entry_in_frame(probe_box, "Blocksize (Read/Write)");
Jens Axboec80b74b2012-03-12 10:23:28 +01001341 ge->eta.ioengine.entry = new_info_entry_in_frame(probe_box, "IO Engine");
1342 ge->eta.iodepth.entry = new_info_entry_in_frame(probe_box, "IO Depth");
Jens Axboe2f99deb2012-03-09 14:37:29 +01001343 ge->eta.jobs = new_info_entry_in_frame(probe_box, "Jobs");
1344 ge->eta.files = new_info_entry_in_frame(probe_box, "Open files");
1345
1346 probe_box = gtk_hbox_new(FALSE, 3);
1347 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, FALSE, FALSE, 3);
1348 ge->eta.read_bw = new_info_entry_in_frame(probe_box, "Read BW");
1349 ge->eta.read_iops = new_info_entry_in_frame(probe_box, "IOPS");
1350 ge->eta.write_bw = new_info_entry_in_frame(probe_box, "Write BW");
1351 ge->eta.write_iops = new_info_entry_in_frame(probe_box, "IOPS");
1352
1353 /*
1354 * Only add this if we have a commit rate
1355 */
1356#if 0
1357 probe_box = gtk_hbox_new(FALSE, 3);
Jens Axboe3e47bd22012-02-29 13:45:02 +01001358 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, TRUE, FALSE, 3);
Jens Axboe807f9972012-03-02 10:25:24 +01001359
Jens Axboe2f99deb2012-03-09 14:37:29 +01001360 ge->eta.cr_bw = new_info_label_in_frame(probe_box, "Commit BW");
1361 ge->eta.cr_iops = new_info_label_in_frame(probe_box, "Commit IOPS");
1362
1363 ge->eta.cw_bw = new_info_label_in_frame(probe_box, "Commit BW");
1364 ge->eta.cw_iops = new_info_label_in_frame(probe_box, "Commit IOPS");
1365#endif
1366
1367 /*
1368 * Set up a drawing area and IOPS and bandwidth graphs
1369 */
Jens Axboe2f99deb2012-03-09 14:37:29 +01001370 ge->graphs.drawing_area = gtk_drawing_area_new();
Jens Axboe2f99deb2012-03-09 14:37:29 +01001371 gtk_widget_set_size_request(GTK_WIDGET(ge->graphs.drawing_area),
Stephen M. Cameron57f9d282012-03-11 11:36:51 +01001372 DRAWING_AREA_XDIM, DRAWING_AREA_YDIM);
Jens Axboe1252d8f2012-03-21 11:13:31 +01001373 gtk_widget_modify_bg(ge->graphs.drawing_area, GTK_STATE_NORMAL, &gfio_color_white);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001374 g_signal_connect(G_OBJECT(ge->graphs.drawing_area), "expose_event",
1375 G_CALLBACK(on_expose_drawing_area), &ge->graphs);
1376 g_signal_connect(G_OBJECT(ge->graphs.drawing_area), "configure_event",
1377 G_CALLBACK(on_config_drawing_area), &ge->graphs);
Jens Axboe65476332012-03-13 10:37:04 +01001378 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
1379 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
Jens Axboe2f99deb2012-03-09 14:37:29 +01001380 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
Jens Axboe65476332012-03-13 10:37:04 +01001381 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled_window),
Jens Axboe2f99deb2012-03-09 14:37:29 +01001382 ge->graphs.drawing_area);
Jens Axboe65476332012-03-13 10:37:04 +01001383 gtk_box_pack_start(GTK_BOX(main_vbox), scrolled_window, TRUE, TRUE, 0);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001384
1385 setup_graphs(&ge->graphs);
1386
1387 /*
1388 * Set up alignments for widgets at the bottom of ui,
1389 * align bottom left, expand horizontally but not vertically
1390 */
Jens Axboe65476332012-03-13 10:37:04 +01001391 bottom_align = gtk_alignment_new(0, 1, 1, 0);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001392 ge->buttonbox = gtk_hbox_new(FALSE, 0);
Jens Axboe65476332012-03-13 10:37:04 +01001393 gtk_container_add(GTK_CONTAINER(bottom_align), ge->buttonbox);
1394 gtk_box_pack_start(GTK_BOX(main_vbox), bottom_align, FALSE, FALSE, 0);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001395
1396 add_buttons(ge, buttonspeclist, ARRAYSIZE(buttonspeclist));
1397
1398 /*
1399 * Set up thread status progress bar
1400 */
1401 ge->thread_status_pb = gtk_progress_bar_new();
1402 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(ge->thread_status_pb), 0.0);
1403 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(ge->thread_status_pb), "No connections");
1404 gtk_container_add(GTK_CONTAINER(ge->buttonbox), ge->thread_status_pb);
1405
1406
1407 return main_vbox;
1408}
1409
1410static GtkWidget *new_main_page(struct gui *ui)
1411{
1412 GtkWidget *main_vbox, *probe, *probe_frame, *probe_box;
Jens Axboe65476332012-03-13 10:37:04 +01001413 GtkWidget *scrolled_window, *bottom_align, *top_align, *top_vbox;
Jens Axboe2f99deb2012-03-09 14:37:29 +01001414
1415 main_vbox = gtk_vbox_new(FALSE, 3);
1416
1417 /*
1418 * Set up alignments for widgets at the top of ui,
1419 * align top left, expand horizontally but not vertically
1420 */
Jens Axboe65476332012-03-13 10:37:04 +01001421 top_align = gtk_alignment_new(0, 0, 1, 0);
1422 top_vbox = gtk_vbox_new(FALSE, 0);
1423 gtk_container_add(GTK_CONTAINER(top_align), top_vbox);
1424 gtk_box_pack_start(GTK_BOX(main_vbox), top_align, FALSE, FALSE, 0);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001425
1426 probe = gtk_frame_new("Run statistics");
1427 gtk_box_pack_start(GTK_BOX(main_vbox), probe, FALSE, FALSE, 3);
1428 probe_frame = gtk_vbox_new(FALSE, 3);
1429 gtk_container_add(GTK_CONTAINER(probe), probe_frame);
Jens Axboe3e47bd22012-02-29 13:45:02 +01001430
1431 probe_box = gtk_hbox_new(FALSE, 3);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001432 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, FALSE, FALSE, 3);
Jens Axboe3863d1a2012-03-09 17:39:05 +01001433 ui->eta.jobs = new_info_entry_in_frame(probe_box, "Running");
Jens Axboeca850992012-03-05 20:04:43 +01001434 ui->eta.read_bw = new_info_entry_in_frame(probe_box, "Read BW");
1435 ui->eta.read_iops = new_info_entry_in_frame(probe_box, "IOPS");
1436 ui->eta.write_bw = new_info_entry_in_frame(probe_box, "Write BW");
1437 ui->eta.write_iops = new_info_entry_in_frame(probe_box, "IOPS");
Jens Axboe807f9972012-03-02 10:25:24 +01001438
1439 /*
1440 * Only add this if we have a commit rate
1441 */
1442#if 0
1443 probe_box = gtk_hbox_new(FALSE, 3);
1444 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, TRUE, FALSE, 3);
1445
Jens Axboe3e47bd22012-02-29 13:45:02 +01001446 ui->eta.cr_bw = new_info_label_in_frame(probe_box, "Commit BW");
1447 ui->eta.cr_iops = new_info_label_in_frame(probe_box, "Commit IOPS");
1448
Jens Axboe3e47bd22012-02-29 13:45:02 +01001449 ui->eta.cw_bw = new_info_label_in_frame(probe_box, "Commit BW");
1450 ui->eta.cw_iops = new_info_label_in_frame(probe_box, "Commit IOPS");
Jens Axboe807f9972012-03-02 10:25:24 +01001451#endif
Jens Axboe3e47bd22012-02-29 13:45:02 +01001452
Stephen M. Cameron45032dd2012-02-24 08:17:31 +01001453 /*
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001454 * Set up a drawing area and IOPS and bandwidth graphs
Stephen M. Cameron736f2df2012-02-24 08:17:32 +01001455 */
Jens Axboe2f99deb2012-03-09 14:37:29 +01001456 ui->graphs.drawing_area = gtk_drawing_area_new();
Jens Axboe2f99deb2012-03-09 14:37:29 +01001457 gtk_widget_set_size_request(GTK_WIDGET(ui->graphs.drawing_area),
Stephen M. Cameron57f9d282012-03-11 11:36:51 +01001458 DRAWING_AREA_XDIM, DRAWING_AREA_YDIM);
Jens Axboe1252d8f2012-03-21 11:13:31 +01001459 gtk_widget_modify_bg(ui->graphs.drawing_area, GTK_STATE_NORMAL, &gfio_color_white);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001460 g_signal_connect(G_OBJECT(ui->graphs.drawing_area), "expose_event",
1461 G_CALLBACK(on_expose_drawing_area), &ui->graphs);
1462 g_signal_connect(G_OBJECT(ui->graphs.drawing_area), "configure_event",
1463 G_CALLBACK(on_config_drawing_area), &ui->graphs);
Jens Axboe65476332012-03-13 10:37:04 +01001464 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
1465 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
Stephen M. Cameron736f2df2012-02-24 08:17:32 +01001466 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
Jens Axboe65476332012-03-13 10:37:04 +01001467 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled_window),
Jens Axboe2f99deb2012-03-09 14:37:29 +01001468 ui->graphs.drawing_area);
Jens Axboe65476332012-03-13 10:37:04 +01001469 gtk_box_pack_start(GTK_BOX(main_vbox), scrolled_window,
Stephen M. Camerone1645342012-02-24 08:17:32 +01001470 TRUE, TRUE, 0);
Stephen M. Cameron736f2df2012-02-24 08:17:32 +01001471
Jens Axboe2f99deb2012-03-09 14:37:29 +01001472 setup_graphs(&ui->graphs);
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001473
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +01001474 /*
1475 * Set up alignments for widgets at the bottom of ui,
1476 * align bottom left, expand horizontally but not vertically
1477 */
Jens Axboe65476332012-03-13 10:37:04 +01001478 bottom_align = gtk_alignment_new(0, 1, 1, 0);
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +01001479 ui->buttonbox = gtk_hbox_new(FALSE, 0);
Jens Axboe65476332012-03-13 10:37:04 +01001480 gtk_container_add(GTK_CONTAINER(bottom_align), ui->buttonbox);
1481 gtk_box_pack_start(GTK_BOX(main_vbox), bottom_align, FALSE, FALSE, 0);
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +01001482
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001483 /*
1484 * Set up thread status progress bar
1485 */
1486 ui->thread_status_pb = gtk_progress_bar_new();
1487 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(ui->thread_status_pb), 0.0);
Jens Axboe8663ea62012-03-02 14:04:30 +01001488 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(ui->thread_status_pb), "No connections");
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001489 gtk_container_add(GTK_CONTAINER(ui->buttonbox), ui->thread_status_pb);
1490
Jens Axboe2f99deb2012-03-09 14:37:29 +01001491 return main_vbox;
1492}
1493
1494static gboolean notebook_switch_page(GtkNotebook *notebook, GtkWidget *widget,
1495 guint page, gpointer data)
1496
1497{
Jens Axboe02421e62012-03-12 12:05:50 +01001498 struct gui *ui = (struct gui *) data;
Jens Axboe85dd01e2012-03-12 14:33:16 +01001499 struct gui_entry *ge;
Jens Axboe02421e62012-03-12 12:05:50 +01001500
Jens Axboe85dd01e2012-03-12 14:33:16 +01001501 if (!page) {
1502 set_job_menu_visible(ui, 0);
Jens Axboe781ccba2012-03-15 09:44:42 +01001503 set_view_results_visible(ui, 0);
Jens Axboe85dd01e2012-03-12 14:33:16 +01001504 return TRUE;
1505 }
1506
1507 set_job_menu_visible(ui, 1);
Jens Axboe6e02ad62012-03-20 12:25:36 +01001508 ge = get_ge_from_page(ui, page, NULL);
Jens Axboe85dd01e2012-03-12 14:33:16 +01001509 if (ge)
1510 update_button_states(ui, ge);
1511
Jens Axboe2f99deb2012-03-09 14:37:29 +01001512 return TRUE;
1513}
1514
Jens Axboe38634cb2012-03-13 12:26:41 +01001515static gint compare_recent_items(GtkRecentInfo *a, GtkRecentInfo *b)
1516{
1517 time_t time_a = gtk_recent_info_get_visited(a);
1518 time_t time_b = gtk_recent_info_get_visited(b);
1519
1520 return time_b - time_a;
1521}
1522
1523static void add_recent_file_items(struct gui *ui)
1524{
1525 const gchar *gfio = g_get_application_name();
1526 GList *items, *item;
1527 int i = 0;
1528
1529 if (ui->recent_ui_id) {
1530 gtk_ui_manager_remove_ui(ui->uimanager, ui->recent_ui_id);
1531 gtk_ui_manager_ensure_update(ui->uimanager);
1532 }
1533 ui->recent_ui_id = gtk_ui_manager_new_merge_id(ui->uimanager);
1534
1535 if (ui->actiongroup) {
1536 gtk_ui_manager_remove_action_group(ui->uimanager, ui->actiongroup);
1537 g_object_unref(ui->actiongroup);
1538 }
1539 ui->actiongroup = gtk_action_group_new("RecentFileActions");
1540
1541 gtk_ui_manager_insert_action_group(ui->uimanager, ui->actiongroup, -1);
1542
1543 items = gtk_recent_manager_get_items(ui->recentmanager);
1544 items = g_list_sort(items, (GCompareFunc) compare_recent_items);
1545
1546 for (item = items; item && item->data; item = g_list_next(item)) {
1547 GtkRecentInfo *info = (GtkRecentInfo *) item->data;
1548 gchar *action_name;
1549 const gchar *label;
1550 GtkAction *action;
1551
1552 if (!gtk_recent_info_has_application(info, gfio))
1553 continue;
1554
1555 /*
1556 * We only support local files for now
1557 */
1558 if (!gtk_recent_info_is_local(info) || !gtk_recent_info_exists(info))
1559 continue;
1560
1561 action_name = g_strdup_printf("RecentFile%u", i++);
1562 label = gtk_recent_info_get_display_name(info);
1563
1564 action = g_object_new(GTK_TYPE_ACTION,
1565 "name", action_name,
1566 "label", label, NULL);
1567
1568 g_object_set_data_full(G_OBJECT(action), "gtk-recent-info",
1569 gtk_recent_info_ref(info),
1570 (GDestroyNotify) gtk_recent_info_unref);
1571
1572
1573 g_signal_connect(action, "activate", G_CALLBACK(recent_open), ui);
1574
1575 gtk_action_group_add_action(ui->actiongroup, action);
1576 g_object_unref(action);
1577
1578 gtk_ui_manager_add_ui(ui->uimanager, ui->recent_ui_id,
1579 "/MainMenu/FileMenu/FileRecentFiles",
1580 label, action_name,
1581 GTK_UI_MANAGER_MENUITEM, FALSE);
1582
1583 g_free(action_name);
1584
1585 if (i == 8)
1586 break;
1587 }
1588
1589 g_list_foreach(items, (GFunc) gtk_recent_info_unref, NULL);
1590 g_list_free(items);
1591}
1592
Jens Axboea6790902012-03-13 15:16:11 +01001593static void drag_and_drop_received(GtkWidget *widget, GdkDragContext *ctx,
Jens Axboe6e02ad62012-03-20 12:25:36 +01001594 gint x, gint y, GtkSelectionData *seldata,
1595 guint info, guint time, gpointer *data)
Jens Axboea6790902012-03-13 15:16:11 +01001596{
Jens Axboe6e02ad62012-03-20 12:25:36 +01001597 struct gui *ui = (struct gui *) data;
Jens Axboea6790902012-03-13 15:16:11 +01001598 gchar **uris;
1599 GtkWidget *source;
Jens Axboea6790902012-03-13 15:16:11 +01001600
1601 source = gtk_drag_get_source_widget(ctx);
1602 if (source && widget == gtk_widget_get_toplevel(source)) {
1603 gtk_drag_finish(ctx, FALSE, FALSE, time);
1604 return;
1605 }
1606
Jens Axboe6e02ad62012-03-20 12:25:36 +01001607 uris = gtk_selection_data_get_uris(seldata);
Jens Axboea6790902012-03-13 15:16:11 +01001608 if (!uris) {
1609 gtk_drag_finish(ctx, FALSE, FALSE, time);
1610 return;
1611 }
1612
Jens Axboe0cf3ece2012-03-21 10:15:20 +01001613 if (uris[0])
1614 do_file_open_with_tab(ui, uris[0]);
Jens Axboea6790902012-03-13 15:16:11 +01001615
1616 gtk_drag_finish(ctx, TRUE, FALSE, time);
1617 g_strfreev(uris);
1618}
1619
Jens Axboe2f99deb2012-03-09 14:37:29 +01001620static void init_ui(int *argc, char **argv[], struct gui *ui)
1621{
1622 GtkSettings *settings;
Jens Axboe02421e62012-03-12 12:05:50 +01001623 GtkWidget *vbox;
Jens Axboe2f99deb2012-03-09 14:37:29 +01001624
1625 /* Magical g*thread incantation, you just need this thread stuff.
1626 * Without it, the update that happens in gfio_update_thread_status
1627 * doesn't really happen in a timely fashion, you need expose events
1628 */
1629 if (!g_thread_supported())
1630 g_thread_init(NULL);
1631 gdk_threads_init();
1632
1633 gtk_init(argc, argv);
1634 settings = gtk_settings_get_default();
1635 gtk_settings_set_long_property(settings, "gtk_tooltip_timeout", 10, "gfio setting");
1636 g_type_init();
Jens Axboe1252d8f2012-03-21 11:13:31 +01001637 gdk_color_parse("white", &gfio_color_white);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001638
1639 ui->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
Stephen M. Cameron814479d2012-03-15 07:58:14 +01001640 gtk_window_set_title(GTK_WINDOW(ui->window), "fio");
Jens Axboe2f99deb2012-03-09 14:37:29 +01001641 gtk_window_set_default_size(GTK_WINDOW(ui->window), 1024, 768);
1642
Jens Axboe6e02ad62012-03-20 12:25:36 +01001643 g_signal_connect(ui->window, "delete-event", G_CALLBACK(quit_clicked), ui);
1644 g_signal_connect(ui->window, "destroy", G_CALLBACK(quit_clicked), ui);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001645
1646 ui->vbox = gtk_vbox_new(FALSE, 0);
1647 gtk_container_add(GTK_CONTAINER(ui->window), ui->vbox);
1648
Jens Axboe02421e62012-03-12 12:05:50 +01001649 ui->uimanager = gtk_ui_manager_new();
1650 ui->menu = get_menubar_menu(ui->window, ui->uimanager, ui);
1651 gfio_ui_setup(settings, ui->menu, ui->vbox, ui->uimanager);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001652
Jens Axboe38634cb2012-03-13 12:26:41 +01001653 ui->recentmanager = gtk_recent_manager_get_default();
1654 add_recent_file_items(ui);
1655
Jens Axboe2f99deb2012-03-09 14:37:29 +01001656 ui->notebook = gtk_notebook_new();
1657 g_signal_connect(ui->notebook, "switch-page", G_CALLBACK(notebook_switch_page), ui);
Jens Axboeb870c312012-03-09 17:22:01 +01001658 gtk_notebook_set_scrollable(GTK_NOTEBOOK(ui->notebook), 1);
Jens Axboe0aa928c2012-03-09 17:24:07 +01001659 gtk_notebook_popup_enable(GTK_NOTEBOOK(ui->notebook));
Jens Axboe2f99deb2012-03-09 14:37:29 +01001660 gtk_container_add(GTK_CONTAINER(ui->vbox), ui->notebook);
1661
1662 vbox = new_main_page(ui);
Jens Axboe0cf3ece2012-03-21 10:15:20 +01001663 gtk_drag_dest_set(GTK_WIDGET(ui->window), GTK_DEST_DEFAULT_ALL, NULL, 1, GDK_ACTION_COPY);
Jens Axboea6790902012-03-13 15:16:11 +01001664 gtk_drag_dest_add_uri_targets(GTK_WIDGET(ui->window));
1665 g_signal_connect(ui->window, "drag-data-received", G_CALLBACK(drag_and_drop_received), ui);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001666
1667 gtk_notebook_append_page(GTK_NOTEBOOK(ui->notebook), vbox, gtk_label_new("Main"));
1668
Jens Axboe9b260bd2012-03-06 11:02:52 +01001669 gfio_ui_setup_log(ui);
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001670
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001671 gtk_widget_show_all(ui->window);
1672}
1673
Stephen M. Cameron8232e282012-02-24 08:17:31 +01001674int main(int argc, char *argv[], char *envp[])
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001675{
Stephen M. Cameron8232e282012-02-24 08:17:31 +01001676 if (initialize_fio(envp))
1677 return 1;
Jens Axboe0420ba62012-02-29 11:16:52 +01001678 if (fio_init_options())
1679 return 1;
Stephen M. Camerona1820202012-02-24 08:17:31 +01001680
Jens Axboe2f99deb2012-03-09 14:37:29 +01001681 memset(&main_ui, 0, sizeof(main_ui));
1682 INIT_FLIST_HEAD(&main_ui.list);
1683
1684 init_ui(&argc, &argv, &main_ui);
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +01001685
Stephen M. Cameron2839f0c2012-02-24 08:17:31 +01001686 gdk_threads_enter();
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001687 gtk_main();
Stephen M. Cameron2839f0c2012-02-24 08:17:31 +01001688 gdk_threads_leave();
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001689 return 0;
1690}