blob: 274dea8f59998045bf6965936091351e1bfb1fe3 [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 Axboeb98ab712012-03-21 12:48:32 +0100389 g_hash_table_remove(ge->ui->ge_hash, &ge->page_num);
390
Jens Axboe0cf3ece2012-03-21 10:15:20 +0100391 free(ge->job_file);
392 free(ge->host);
Jens Axboe0fd18982012-03-14 10:34:48 +0100393 free(ge);
394}
395
396static void ge_widget_destroy(GtkWidget *w, gpointer data)
397{
Jens Axboe2eb98bf2012-03-20 08:20:48 +0100398 struct gui_entry *ge = (struct gui_entry *) data;
399
400 ge_destroy(ge);
Jens Axboe0fd18982012-03-14 10:34:48 +0100401}
402
403static void gfio_quit(struct gui *ui)
404{
Jens Axboe0fd18982012-03-14 10:34:48 +0100405 gtk_main_quit();
406}
407
Stephen M. Cameronff1f3282012-02-24 08:17:30 +0100408static void quit_clicked(__attribute__((unused)) GtkWidget *widget,
409 __attribute__((unused)) gpointer data)
410{
Jens Axboe6e02ad62012-03-20 12:25:36 +0100411 struct gui *ui = (struct gui *) data;
412
413 gfio_quit(ui);
Stephen M. Cameronff1f3282012-02-24 08:17:30 +0100414}
415
Stephen M. Cameron25927252012-02-24 08:17:31 +0100416static void *job_thread(void *arg)
Stephen M. Cameronf3074002012-02-24 08:17:30 +0100417{
Jens Axboea9eccde2012-03-09 14:59:42 +0100418 struct gui *ui = arg;
419
420 ui->handler_running = 1;
Stephen M. Cameron25927252012-02-24 08:17:31 +0100421 fio_handle_clients(&gfio_client_ops);
Jens Axboea9eccde2012-03-09 14:59:42 +0100422 ui->handler_running = 0;
Stephen M. Cameron25927252012-02-24 08:17:31 +0100423 return NULL;
424}
425
Jens Axboe0cf3ece2012-03-21 10:15:20 +0100426static int send_job_file(struct gui_entry *ge)
Stephen M. Cameron60f6b332012-02-24 08:17:32 +0100427{
Jens Axboe9988ca72012-03-09 15:14:06 +0100428 struct gfio_client *gc = ge->client;
Jens Axboe0cf3ece2012-03-21 10:15:20 +0100429 int ret = 0;
Stephen M. Cameron60f6b332012-02-24 08:17:32 +0100430
Jens Axboe0cf3ece2012-03-21 10:15:20 +0100431 ret = fio_client_send_ini(gc->client, ge->job_file);
432 if (!ret)
433 return 0;
Jens Axboec7249262012-03-09 17:11:04 +0100434
Jens Axboe41666582012-03-21 10:25:29 +0100435 gfio_report_error(ge, "Failed to send file %s: %s\n", ge->job_file, strerror(-ret));
Jens Axboe0cf3ece2012-03-21 10:15:20 +0100436 return 1;
Stephen M. Cameron60f6b332012-02-24 08:17:32 +0100437}
438
Jens Axboe63a130b2012-03-06 20:08:59 +0100439static void *server_thread(void *arg)
440{
441 is_backend = 1;
442 gfio_server_running = 1;
443 fio_start_server(NULL);
444 gfio_server_running = 0;
445 return NULL;
446}
447
Jens Axboe6e02ad62012-03-20 12:25:36 +0100448static void gfio_start_server(struct gui *ui)
Jens Axboe63a130b2012-03-06 20:08:59 +0100449{
450 if (!gfio_server_running) {
451 gfio_server_running = 1;
452 pthread_create(&ui->server_t, NULL, server_thread, NULL);
Jens Axboee34f6ad2012-03-06 20:47:15 +0100453 pthread_detach(ui->server_t);
Jens Axboe63a130b2012-03-06 20:08:59 +0100454 }
455}
456
Stephen M. Cameron25927252012-02-24 08:17:31 +0100457static void start_job_clicked(__attribute__((unused)) GtkWidget *widget,
458 gpointer data)
459{
Jens Axboe2f99deb2012-03-09 14:37:29 +0100460 struct gui_entry *ge = data;
461 struct gfio_client *gc = ge->client;
Stephen M. Cameron25927252012-02-24 08:17:31 +0100462
Jens Axboe78cb2fe2012-03-12 23:05:29 +0100463 if (gc)
464 fio_start_client(gc->client);
Stephen M. Cameronf3074002012-02-24 08:17:30 +0100465}
466
Jens Axboedf06f222012-03-02 13:32:04 +0100467static void file_open(GtkWidget *w, gpointer data);
468
Jens Axboe62bc9372012-03-07 11:45:07 +0100469struct connection_widgets
470{
471 GtkWidget *hentry;
472 GtkWidget *combo;
473 GtkWidget *button;
474};
475
476static void hostname_cb(GtkEntry *entry, gpointer data)
477{
478 struct connection_widgets *cw = data;
479 int uses_net = 0, is_localhost = 0;
480 const gchar *text;
481 gchar *ctext;
482
483 /*
484 * Check whether to display the 'auto start backend' box
485 * or not. Show it if we are a localhost and using network,
486 * or using a socket.
487 */
488 ctext = gtk_combo_box_get_active_text(GTK_COMBO_BOX(cw->combo));
489 if (!ctext || !strncmp(ctext, "IPv4", 4) || !strncmp(ctext, "IPv6", 4))
490 uses_net = 1;
491 g_free(ctext);
492
493 if (uses_net) {
494 text = gtk_entry_get_text(GTK_ENTRY(cw->hentry));
495 if (!strcmp(text, "127.0.0.1") || !strcmp(text, "localhost") ||
496 !strcmp(text, "::1") || !strcmp(text, "ip6-localhost") ||
497 !strcmp(text, "ip6-loopback"))
498 is_localhost = 1;
499 }
500
501 if (!uses_net || is_localhost) {
502 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cw->button), 1);
503 gtk_widget_set_sensitive(cw->button, 1);
504 } else {
505 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cw->button), 0);
506 gtk_widget_set_sensitive(cw->button, 0);
507 }
Jens Axboeb0500cc2012-03-21 11:59:18 +0100508}
Jens Axboea7a42ce2012-03-02 13:12:04 +0100509
Jens Axboeb0500cc2012-03-21 11:59:18 +0100510static int get_connection_details(struct gui_entry *ge)
511{
512 GtkWidget *dialog, *box, *vbox, *hbox, *frame, *pentry;
513 struct connection_widgets cw;
514 struct gui *ui = ge->ui;
515 char *typeentry;
Jens Axboea7a42ce2012-03-02 13:12:04 +0100516
Jens Axboeb0500cc2012-03-21 11:59:18 +0100517 if (ge->host)
Jens Axboe1252d8f2012-03-21 11:13:31 +0100518 return 0;
Jens Axboe1252d8f2012-03-21 11:13:31 +0100519
Jens Axboeb0500cc2012-03-21 11:59:18 +0100520 dialog = gtk_dialog_new_with_buttons("Connection details",
521 GTK_WINDOW(ui->window),
522 GTK_DIALOG_DESTROY_WITH_PARENT,
523 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
524 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, NULL);
Jens Axboe1252d8f2012-03-21 11:13:31 +0100525
Jens Axboeb0500cc2012-03-21 11:59:18 +0100526 frame = gtk_frame_new("Hostname / socket name");
527 /* gtk_dialog_get_content_area() is 2.14 and newer */
528 vbox = GTK_DIALOG(dialog)->vbox;
529 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
Jens Axboe1252d8f2012-03-21 11:13:31 +0100530
Jens Axboeb0500cc2012-03-21 11:59:18 +0100531 box = gtk_vbox_new(FALSE, 6);
532 gtk_container_add(GTK_CONTAINER(frame), box);
Jens Axboe1252d8f2012-03-21 11:13:31 +0100533
Jens Axboeb0500cc2012-03-21 11:59:18 +0100534 hbox = gtk_hbox_new(TRUE, 10);
535 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
536 cw.hentry = gtk_entry_new();
537 gtk_entry_set_text(GTK_ENTRY(cw.hentry), "localhost");
538 gtk_box_pack_start(GTK_BOX(hbox), cw.hentry, TRUE, TRUE, 0);
Jens Axboe1252d8f2012-03-21 11:13:31 +0100539
Jens Axboeb0500cc2012-03-21 11:59:18 +0100540 frame = gtk_frame_new("Port");
541 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
542 box = gtk_vbox_new(FALSE, 10);
543 gtk_container_add(GTK_CONTAINER(frame), box);
Jens Axboe1252d8f2012-03-21 11:13:31 +0100544
Jens Axboeb0500cc2012-03-21 11:59:18 +0100545 hbox = gtk_hbox_new(TRUE, 4);
546 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
547 pentry = create_spinbutton(hbox, 1, 65535, FIO_NET_PORT);
Jens Axboe1252d8f2012-03-21 11:13:31 +0100548
Jens Axboeb0500cc2012-03-21 11:59:18 +0100549 frame = gtk_frame_new("Type");
550 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
551 box = gtk_vbox_new(FALSE, 10);
552 gtk_container_add(GTK_CONTAINER(frame), box);
Jens Axboe1252d8f2012-03-21 11:13:31 +0100553
Jens Axboeb0500cc2012-03-21 11:59:18 +0100554 hbox = gtk_hbox_new(TRUE, 4);
555 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
Jens Axboe1252d8f2012-03-21 11:13:31 +0100556
Jens Axboeb0500cc2012-03-21 11:59:18 +0100557 cw.combo = gtk_combo_box_new_text();
558 gtk_combo_box_append_text(GTK_COMBO_BOX(cw.combo), "IPv4");
559 gtk_combo_box_append_text(GTK_COMBO_BOX(cw.combo), "IPv6");
560 gtk_combo_box_append_text(GTK_COMBO_BOX(cw.combo), "local socket");
561 gtk_combo_box_set_active(GTK_COMBO_BOX(cw.combo), 0);
Jens Axboe1252d8f2012-03-21 11:13:31 +0100562
Jens Axboeb0500cc2012-03-21 11:59:18 +0100563 gtk_container_add(GTK_CONTAINER(hbox), cw.combo);
Jens Axboe1252d8f2012-03-21 11:13:31 +0100564
Jens Axboeb0500cc2012-03-21 11:59:18 +0100565 frame = gtk_frame_new("Options");
566 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
567 box = gtk_vbox_new(FALSE, 10);
568 gtk_container_add(GTK_CONTAINER(frame), box);
Jens Axboe38634cb2012-03-13 12:26:41 +0100569
Jens Axboeb0500cc2012-03-21 11:59:18 +0100570 hbox = gtk_hbox_new(TRUE, 4);
571 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
Jens Axboe2f99deb2012-03-09 14:37:29 +0100572
Jens Axboeb0500cc2012-03-21 11:59:18 +0100573 cw.button = gtk_check_button_new_with_label("Auto-spawn fio backend");
574 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cw.button), 1);
575 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.");
576 gtk_box_pack_start(GTK_BOX(hbox), cw.button, FALSE, FALSE, 6);
Jens Axboe2f99deb2012-03-09 14:37:29 +0100577
Jens Axboe1252d8f2012-03-21 11:13:31 +0100578 /*
Jens Axboeb0500cc2012-03-21 11:59:18 +0100579 * Connect edit signal, so we can show/not-show the auto start button
Jens Axboe1252d8f2012-03-21 11:13:31 +0100580 */
Jens Axboeb0500cc2012-03-21 11:59:18 +0100581 g_signal_connect(GTK_OBJECT(cw.hentry), "changed", G_CALLBACK(hostname_cb), &cw);
582 g_signal_connect(GTK_OBJECT(cw.combo), "changed", G_CALLBACK(hostname_cb), &cw);
Jens Axboe0420ba62012-02-29 11:16:52 +0100583
Jens Axboeb0500cc2012-03-21 11:59:18 +0100584 gtk_widget_show_all(dialog);
Jens Axboe1252d8f2012-03-21 11:13:31 +0100585
Jens Axboeb0500cc2012-03-21 11:59:18 +0100586 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT) {
587 gtk_widget_destroy(dialog);
Jens Axboea6790902012-03-13 15:16:11 +0100588 return 1;
589 }
590
Jens Axboeb0500cc2012-03-21 11:59:18 +0100591 ge->host = strdup(gtk_entry_get_text(GTK_ENTRY(cw.hentry)));
592 ge->port = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(pentry));
Jens Axboea6790902012-03-13 15:16:11 +0100593
Jens Axboeb0500cc2012-03-21 11:59:18 +0100594 typeentry = gtk_combo_box_get_active_text(GTK_COMBO_BOX(cw.combo));
595 if (!typeentry || !strncmp(typeentry, "IPv4", 4))
596 ge->type = Fio_client_ipv4;
597 else if (!strncmp(typeentry, "IPv6", 4))
598 ge->type = Fio_client_ipv6;
599 else
600 ge->type = Fio_client_socket;
601 g_free(typeentry);
Jens Axboe1252d8f2012-03-21 11:13:31 +0100602
Jens Axboeb0500cc2012-03-21 11:59:18 +0100603 ge->server_start = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cw.button));
Jens Axboe1252d8f2012-03-21 11:13:31 +0100604
Jens Axboeb0500cc2012-03-21 11:59:18 +0100605 gtk_widget_destroy(dialog);
606 return 0;
607}
Jens Axboe1252d8f2012-03-21 11:13:31 +0100608
Jens Axboeb0500cc2012-03-21 11:59:18 +0100609static void gfio_set_client(struct gfio_client *gc, struct fio_client *client)
610{
611 gc->client = fio_get_client(client);
612 client->client_data = gc;
613}
Jens Axboe1252d8f2012-03-21 11:13:31 +0100614
Jens Axboeb0500cc2012-03-21 11:59:18 +0100615static void gfio_client_added(struct gui_entry *ge, struct fio_client *client)
616{
617 struct gfio_client *gc;
Jens Axboe1252d8f2012-03-21 11:13:31 +0100618
Jens Axboeb0500cc2012-03-21 11:59:18 +0100619 gc = malloc(sizeof(*gc));
620 memset(gc, 0, sizeof(*gc));
621 options_default_fill(&gc->o);
622 gc->ge = ge;
623 ge->client = gc;
624 gfio_set_client(gc, client);
625}
Jens Axboea6790902012-03-13 15:16:11 +0100626
Jens Axboeb0500cc2012-03-21 11:59:18 +0100627static void connect_clicked(GtkWidget *widget, gpointer data)
628{
629 struct gui_entry *ge = data;
630 struct gfio_client *gc = ge->client;
Jens Axboea6790902012-03-13 15:16:11 +0100631
Jens Axboeb0500cc2012-03-21 11:59:18 +0100632 if (ge->state == GE_STATE_NEW) {
633 int ret;
Jens Axboea6790902012-03-13 15:16:11 +0100634
Jens Axboeb0500cc2012-03-21 11:59:18 +0100635 if (!ge->job_file)
636 file_open(widget, ge->ui);
637 if (!ge->job_file)
Jens Axboe1252d8f2012-03-21 11:13:31 +0100638 return;
Jens Axboeb0500cc2012-03-21 11:59:18 +0100639
640 gc = ge->client;
641
642 if (!gc->client) {
643 struct fio_client *client;
644
645 if (get_connection_details(ge)) {
646 gfio_report_error(ge, "Failed to get connection details\n");
647 return;
648 }
649
650 client = fio_client_add_explicit(&gfio_client_ops, ge->host, ge->type, ge->port);
651 if (!client) {
652 gfio_report_error(ge, "Failed to add client %s\n", ge->host);
653 free(ge->host);
654 ge->host = NULL;
655 return;
656 }
657 gfio_set_client(gc, client);
Jens Axboe1252d8f2012-03-21 11:13:31 +0100658 }
Jens Axboe0420ba62012-02-29 11:16:52 +0100659
Jens Axboeb0500cc2012-03-21 11:59:18 +0100660 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(ge->thread_status_pb), "No jobs running");
661 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(ge->thread_status_pb), 0.0);
662 ret = fio_client_connect(gc->client);
663 if (!ret) {
664 if (!ge->ui->handler_running)
665 pthread_create(&ge->ui->t, NULL, job_thread, ge->ui);
666 gfio_set_state(ge, GE_STATE_CONNECTED);
667 } else {
668 gfio_report_error(ge, "Failed to connect to %s: %s\n", ge->client->client->hostname, strerror(-ret));
669 }
670 } else {
671 fio_client_terminate(gc->client);
672 gfio_set_state(ge, GE_STATE_NEW);
673 clear_ge_ui_info(ge);
674 }
675}
676
677static void send_clicked(GtkWidget *widget, gpointer data)
678{
679 struct gui_entry *ge = data;
680
681 if (send_job_file(ge))
682 gtk_widget_set_sensitive(ge->button[GFIO_BUTTON_START], 1);
683}
684
685static GtkWidget *new_client_page(struct gui_entry *ge);
686
687static struct gui_entry *alloc_new_gui_entry(struct gui *ui)
688{
689 struct gui_entry *ge;
690
691 ge = malloc(sizeof(*ge));
692 memset(ge, 0, sizeof(*ge));
693 ge->state = GE_STATE_NEW;
Jens Axboeb0500cc2012-03-21 11:59:18 +0100694 ge->ui = ui;
695 return ge;
696}
697
698static struct gui_entry *get_new_ge_with_tab(struct gui *ui, const char *name)
699{
700 struct gui_entry *ge;
701
702 ge = alloc_new_gui_entry(ui);
703
704 ge->vbox = new_client_page(ge);
705 g_signal_connect(ge->vbox, "destroy", G_CALLBACK(ge_widget_destroy), ge);
706
707 ge->page_label = gtk_label_new(name);
708 ge->page_num = gtk_notebook_append_page(GTK_NOTEBOOK(ui->notebook), ge->vbox, ge->page_label);
709
Jens Axboeb98ab712012-03-21 12:48:32 +0100710 g_hash_table_insert(ui->ge_hash, &ge->page_num, ge);
711
Jens Axboeb0500cc2012-03-21 11:59:18 +0100712 gtk_widget_show_all(ui->window);
713 return ge;
714}
715
716static void file_new(GtkWidget *w, gpointer data)
717{
718 struct gui *ui = (struct gui *) data;
719 struct gui_entry *ge;
720
721 ge = get_new_ge_with_tab(ui, "Untitled");
722 gtk_notebook_set_current_page(GTK_NOTEBOOK(ui->notebook), ge->page_num);
723}
724
725/*
726 * Return the 'ge' corresponding to the tab. If the active tab is the
727 * main tab, open a new tab.
728 */
729static struct gui_entry *get_ge_from_page(struct gui *ui, gint cur_page,
730 int *created)
731{
Jens Axboeb0500cc2012-03-21 11:59:18 +0100732 if (!cur_page) {
733 if (created)
734 *created = 1;
735 return get_new_ge_with_tab(ui, "Untitled");
736 }
737
738 if (created)
739 *created = 0;
740
Jens Axboeb98ab712012-03-21 12:48:32 +0100741 return g_hash_table_lookup(ui->ge_hash, &cur_page);
Jens Axboeb0500cc2012-03-21 11:59:18 +0100742}
743
744static struct gui_entry *get_ge_from_cur_tab(struct gui *ui)
745{
746 gint cur_page;
747
748 /*
749 * Main tab is tab 0, so any current page other than 0 holds
750 * a ge entry.
751 */
752 cur_page = gtk_notebook_get_current_page(GTK_NOTEBOOK(ui->notebook));
753 if (cur_page)
754 return get_ge_from_page(ui, cur_page, NULL);
755
756 return NULL;
757}
758
759static void file_close(GtkWidget *w, gpointer data)
760{
761 struct gui *ui = (struct gui *) data;
762 struct gui_entry *ge;
763
764 /*
765 * Can't close the main tab
766 */
767 ge = get_ge_from_cur_tab(ui);
768 if (ge) {
769 gtk_widget_destroy(ge->vbox);
770 return;
771 }
772
Jens Axboeb98ab712012-03-21 12:48:32 +0100773 if (g_hash_table_size(ui->ge_hash)) {
Jens Axboeb0500cc2012-03-21 11:59:18 +0100774 gfio_report_info(ui, "Error", "The main page view cannot be closed\n");
775 return;
776 }
777
778 gfio_quit(ui);
779}
780
781static void file_add_recent(struct gui *ui, const gchar *uri)
782{
783 GtkRecentData grd;
784
785 memset(&grd, 0, sizeof(grd));
786 grd.display_name = strdup("gfio");
787 grd.description = strdup("Fio job file");
788 grd.mime_type = strdup(GFIO_MIME);
789 grd.app_name = strdup(g_get_application_name());
790 grd.app_exec = strdup("gfio %f/%u");
791
792 gtk_recent_manager_add_full(ui->recentmanager, uri, &grd);
793}
794
795static gchar *get_filename_from_uri(const gchar *uri)
796{
797 if (strncmp(uri, "file://", 7))
798 return strdup(uri);
799
800 return strdup(uri + 7);
801}
802
803static int do_file_open(struct gui_entry *ge, const gchar *uri)
804{
805 struct fio_client *client;
806
807 assert(!ge->job_file);
808
809 ge->job_file = get_filename_from_uri(uri);
810
811 client = fio_client_add_explicit(&gfio_client_ops, ge->host, ge->type, ge->port);
812 if (client) {
Jens Axboe832fde72012-03-21 12:55:49 +0100813 char *label = strdup(uri);
814
815 basename(label);
816 gtk_label_set_text(GTK_LABEL(ge->page_label), basename(label));
817 free(label);
818
Jens Axboeb0500cc2012-03-21 11:59:18 +0100819 gfio_client_added(ge, client);
820 file_add_recent(ge->ui, uri);
821 return 0;
822 }
823
824 gfio_report_error(ge, "Failed to add client %s\n", ge->host);
825 free(ge->host);
826 ge->host = NULL;
Jens Axboeb98ab712012-03-21 12:48:32 +0100827 free(ge->job_file);
828 ge->job_file = NULL;
Jens Axboeb0500cc2012-03-21 11:59:18 +0100829 return 1;
830}
831
832static int do_file_open_with_tab(struct gui *ui, const gchar *uri)
833{
834 struct gui_entry *ge;
835 gint cur_page;
836 int ret, ge_is_new = 0;
837
838 /*
839 * Creates new tab if current tab is the main window, or the
840 * current tab already has a client.
841 */
842 cur_page = gtk_notebook_get_current_page(GTK_NOTEBOOK(ui->notebook));
843 ge = get_ge_from_page(ui, cur_page, &ge_is_new);
844 if (ge->client) {
845 ge = get_new_ge_with_tab(ui, "Untitled");
846 ge_is_new = 1;
847 }
848
849 gtk_notebook_set_current_page(GTK_NOTEBOOK(ui->notebook), ge->page_num);
850
851 if (get_connection_details(ge)) {
852 if (ge_is_new)
853 gtk_widget_destroy(ge->vbox);
854
855 return 1;
856 }
857
858 ret = do_file_open(ge, uri);
859
860 if (!ret) {
861 if (ge->server_start)
862 gfio_start_server(ui);
863 } else {
864 if (ge_is_new)
865 gtk_widget_destroy(ge->vbox);
866 }
867
868 return ret;
869}
870
871static void recent_open(GtkAction *action, gpointer data)
872{
873 struct gui *ui = (struct gui *) data;
874 GtkRecentInfo *info;
875 const gchar *uri;
876
877 info = g_object_get_data(G_OBJECT(action), "gtk-recent-info");
878 uri = gtk_recent_info_get_uri(info);
879
880 do_file_open_with_tab(ui, uri);
881}
882
883static void file_open(GtkWidget *w, gpointer data)
884{
885 struct gui *ui = data;
886 GtkWidget *dialog;
887 GtkFileFilter *filter;
888 gchar *filename;
889
890 dialog = gtk_file_chooser_dialog_new("Open File",
891 GTK_WINDOW(ui->window),
892 GTK_FILE_CHOOSER_ACTION_OPEN,
893 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
894 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
895 NULL);
896 gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), FALSE);
897
898 filter = gtk_file_filter_new();
899 gtk_file_filter_add_pattern(filter, "*.fio");
900 gtk_file_filter_add_pattern(filter, "*.job");
901 gtk_file_filter_add_pattern(filter, "*.ini");
902 gtk_file_filter_add_mime_type(filter, GFIO_MIME);
903 gtk_file_filter_set_name(filter, "Fio job file");
904 gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(dialog), filter);
905
906 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT) {
907 gtk_widget_destroy(dialog);
908 return;
909 }
910
911 filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
912
913 gtk_widget_destroy(dialog);
914
915 do_file_open_with_tab(ui, filename);
916 g_free(filename);
917}
918
919static void file_save(GtkWidget *w, gpointer data)
920{
921 struct gui *ui = data;
922 GtkWidget *dialog;
923
924 dialog = gtk_file_chooser_dialog_new("Save File",
925 GTK_WINDOW(ui->window),
926 GTK_FILE_CHOOSER_ACTION_SAVE,
927 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
928 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
929 NULL);
930
931 gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE);
932 gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), "Untitled document");
933
934 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
935 char *filename;
936
Jens Axboe0420ba62012-02-29 11:16:52 +0100937 filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
Jens Axboeb0500cc2012-03-21 11:59:18 +0100938 // save_job_file(filename);
Jens Axboe0420ba62012-02-29 11:16:52 +0100939 g_free(filename);
940 }
Jens Axboeb0500cc2012-03-21 11:59:18 +0100941 gtk_widget_destroy(dialog);
942}
Jens Axboe0420ba62012-02-29 11:16:52 +0100943
Jens Axboe9b260bd2012-03-06 11:02:52 +0100944static void view_log_destroy(GtkWidget *w, gpointer data)
945{
946 struct gui *ui = (struct gui *) data;
947
948 gtk_widget_ref(ui->log_tree);
949 gtk_container_remove(GTK_CONTAINER(w), ui->log_tree);
950 gtk_widget_destroy(w);
Jens Axboe4cbe7212012-03-06 13:36:17 +0100951 ui->log_view = NULL;
Jens Axboe9b260bd2012-03-06 11:02:52 +0100952}
953
Jens Axboe1252d8f2012-03-21 11:13:31 +0100954void gfio_view_log(struct gui *ui)
Jens Axboe9b260bd2012-03-06 11:02:52 +0100955{
Jens Axboe4cbe7212012-03-06 13:36:17 +0100956 GtkWidget *win, *scroll, *vbox, *box;
Jens Axboe9b260bd2012-03-06 11:02:52 +0100957
Jens Axboe4cbe7212012-03-06 13:36:17 +0100958 if (ui->log_view)
959 return;
960
961 ui->log_view = win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
Jens Axboe9b260bd2012-03-06 11:02:52 +0100962 gtk_window_set_title(GTK_WINDOW(win), "Log");
Jens Axboe4cbe7212012-03-06 13:36:17 +0100963 gtk_window_set_default_size(GTK_WINDOW(win), 700, 500);
Jens Axboe9b260bd2012-03-06 11:02:52 +0100964
Jens Axboe4cbe7212012-03-06 13:36:17 +0100965 scroll = gtk_scrolled_window_new(NULL, NULL);
Jens Axboe9b260bd2012-03-06 11:02:52 +0100966
Jens Axboe4cbe7212012-03-06 13:36:17 +0100967 gtk_container_set_border_width(GTK_CONTAINER(scroll), 5);
968
969 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
970
971 box = gtk_hbox_new(TRUE, 0);
972 gtk_box_pack_start_defaults(GTK_BOX(box), ui->log_tree);
973 g_signal_connect(box, "destroy", G_CALLBACK(view_log_destroy), ui);
974 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroll), box);
975
976 vbox = gtk_vbox_new(TRUE, 5);
977 gtk_box_pack_start_defaults(GTK_BOX(vbox), scroll);
978
979 gtk_container_add(GTK_CONTAINER(win), vbox);
Jens Axboe9b260bd2012-03-06 11:02:52 +0100980 gtk_widget_show_all(win);
981}
982
Jens Axboe1252d8f2012-03-21 11:13:31 +0100983static void view_log(GtkWidget *w, gpointer data)
984{
985 struct gui *ui = (struct gui *) data;
986
987 gfio_view_log(ui);
988}
989
Jens Axboe85dd01e2012-03-12 14:33:16 +0100990static void connect_job_entry(GtkWidget *w, gpointer data)
Jens Axboe16ce5ad2012-03-12 11:56:09 +0100991{
Jens Axboe85dd01e2012-03-12 14:33:16 +0100992 struct gui *ui = (struct gui *) data;
993 struct gui_entry *ge;
994
995 ge = get_ge_from_cur_tab(ui);
996 if (ge)
997 connect_clicked(w, ge);
998}
999
1000static void send_job_entry(GtkWidget *w, gpointer data)
1001{
1002 struct gui *ui = (struct gui *) data;
1003 struct gui_entry *ge;
1004
1005 ge = get_ge_from_cur_tab(ui);
1006 if (ge)
1007 send_clicked(w, ge);
Jens Axboe85dd01e2012-03-12 14:33:16 +01001008}
1009
1010static void edit_job_entry(GtkWidget *w, gpointer data)
1011{
Jens Axboe9af4a242012-03-16 10:13:49 +01001012 struct gui *ui = (struct gui *) data;
Jens Axboe789f4cc2012-03-16 14:56:44 +01001013 struct gui_entry *ge;
Jens Axboe9af4a242012-03-16 10:13:49 +01001014
Jens Axboe789f4cc2012-03-16 14:56:44 +01001015 ge = get_ge_from_cur_tab(ui);
1016 if (ge && ge->client)
1017 gopt_get_options_window(ui->window, &ge->client->o);
Jens Axboe85dd01e2012-03-12 14:33:16 +01001018}
1019
1020static void start_job_entry(GtkWidget *w, gpointer data)
1021{
1022 struct gui *ui = (struct gui *) data;
1023 struct gui_entry *ge;
1024
1025 ge = get_ge_from_cur_tab(ui);
1026 if (ge)
1027 start_job_clicked(w, ge);
Jens Axboe16ce5ad2012-03-12 11:56:09 +01001028}
1029
Jens Axboe781ccba2012-03-15 09:44:42 +01001030static void view_results(GtkWidget *w, gpointer data)
1031{
1032 struct gui *ui = (struct gui *) data;
1033 struct gfio_client *gc;
1034 struct gui_entry *ge;
1035
1036 ge = get_ge_from_cur_tab(ui);
1037 if (!ge)
1038 return;
1039
1040 if (ge->results_window)
1041 return;
1042
1043 gc = ge->client;
1044 if (gc && gc->nr_results)
1045 gfio_display_end_results(gc);
1046}
1047
Jens Axboe8577f4f2012-03-09 19:28:27 +01001048static void __update_graph_limits(struct gfio_graphs *g)
1049{
1050 line_graph_set_data_count_limit(g->iops_graph, gfio_graph_limit);
1051 line_graph_set_data_count_limit(g->bandwidth_graph, gfio_graph_limit);
1052}
1053
Jens Axboeb98ab712012-03-21 12:48:32 +01001054static void ge_update_lim_fn(gpointer key, gpointer value, gpointer data)
1055{
1056 struct gui_entry *ge = (struct gui_entry *) value;
1057
1058 __update_graph_limits(&ge->graphs);
1059}
1060
Jens Axboe8577f4f2012-03-09 19:28:27 +01001061static void update_graph_limits(void)
1062{
Jens Axboeb98ab712012-03-21 12:48:32 +01001063 struct gui *ui = &main_ui;
Jens Axboe8577f4f2012-03-09 19:28:27 +01001064
Jens Axboeb98ab712012-03-21 12:48:32 +01001065 __update_graph_limits(&ui->graphs);
Jens Axboe8577f4f2012-03-09 19:28:27 +01001066
Jens Axboeb98ab712012-03-21 12:48:32 +01001067 g_hash_table_foreach(ui->ge_hash, ge_update_lim_fn, NULL);
Jens Axboe8577f4f2012-03-09 19:28:27 +01001068}
1069
Jens Axboe46974a72012-03-02 19:34:13 +01001070static void preferences(GtkWidget *w, gpointer data)
1071{
Jens Axboef3e84402012-03-07 13:14:32 +01001072 GtkWidget *dialog, *frame, *box, **buttons, *vbox, *font;
Jens Axboe1cf6bca2012-03-09 20:20:17 +01001073 GtkWidget *hbox, *spin, *entry, *spin_int;
Jens Axboe6e02ad62012-03-20 12:25:36 +01001074 struct gui *ui = (struct gui *) data;
Jens Axboe46974a72012-03-02 19:34:13 +01001075 int i;
1076
1077 dialog = gtk_dialog_new_with_buttons("Preferences",
Jens Axboe6e02ad62012-03-20 12:25:36 +01001078 GTK_WINDOW(ui->window),
Jens Axboe46974a72012-03-02 19:34:13 +01001079 GTK_DIALOG_DESTROY_WITH_PARENT,
1080 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
1081 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
1082 NULL);
1083
Jens Axboe8577f4f2012-03-09 19:28:27 +01001084 frame = gtk_frame_new("Graphing");
Jens Axboef3e84402012-03-07 13:14:32 +01001085 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), frame, FALSE, FALSE, 5);
1086 vbox = gtk_vbox_new(FALSE, 6);
1087 gtk_container_add(GTK_CONTAINER(frame), vbox);
1088
Jens Axboe1cf6bca2012-03-09 20:20:17 +01001089 hbox = gtk_hbox_new(FALSE, 5);
1090 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 5);
1091 entry = gtk_label_new("Font face to use for graph labels");
1092 gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 5);
1093
Jens Axboef3e84402012-03-07 13:14:32 +01001094 font = gtk_font_button_new();
Jens Axboe1cf6bca2012-03-09 20:20:17 +01001095 gtk_box_pack_start(GTK_BOX(hbox), font, FALSE, FALSE, 5);
Jens Axboef3e84402012-03-07 13:14:32 +01001096
Jens Axboe8577f4f2012-03-09 19:28:27 +01001097 box = gtk_vbox_new(FALSE, 6);
1098 gtk_box_pack_start(GTK_BOX(vbox), box, FALSE, FALSE, 5);
1099
1100 hbox = gtk_hbox_new(FALSE, 5);
Jens Axboe1cf6bca2012-03-09 20:20:17 +01001101 gtk_box_pack_start(GTK_BOX(box), hbox, TRUE, TRUE, 5);
Jens Axboe8577f4f2012-03-09 19:28:27 +01001102 entry = gtk_label_new("Maximum number of data points in graph (seconds)");
1103 gtk_box_pack_start(GTK_BOX(hbox), entry, FALSE, FALSE, 5);
1104
Jens Axboec05d9052012-03-11 13:05:35 +01001105 spin = create_spinbutton(hbox, 10, 1000000, gfio_graph_limit);
Jens Axboe8577f4f2012-03-09 19:28:27 +01001106
Jens Axboe1cf6bca2012-03-09 20:20:17 +01001107 box = gtk_vbox_new(FALSE, 6);
1108 gtk_box_pack_start(GTK_BOX(vbox), box, FALSE, FALSE, 5);
1109
1110 hbox = gtk_hbox_new(FALSE, 5);
1111 gtk_box_pack_start(GTK_BOX(box), hbox, TRUE, TRUE, 5);
1112 entry = gtk_label_new("Client ETA request interval (msec)");
1113 gtk_box_pack_start(GTK_BOX(hbox), entry, FALSE, FALSE, 5);
1114
1115 spin_int = create_spinbutton(hbox, 100, 100000, gfio_client_ops.eta_msec);
Jens Axboea31d9fa2012-03-09 20:23:05 +01001116 frame = gtk_frame_new("Debug logging");
1117 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), frame, FALSE, FALSE, 5);
1118 vbox = gtk_vbox_new(FALSE, 6);
1119 gtk_container_add(GTK_CONTAINER(frame), vbox);
1120
1121 box = gtk_hbox_new(FALSE, 6);
1122 gtk_container_add(GTK_CONTAINER(vbox), box);
1123
1124 buttons = malloc(sizeof(GtkWidget *) * FD_DEBUG_MAX);
1125
1126 for (i = 0; i < FD_DEBUG_MAX; i++) {
1127 if (i == 7) {
1128 box = gtk_hbox_new(FALSE, 6);
1129 gtk_container_add(GTK_CONTAINER(vbox), box);
1130 }
1131
1132
1133 buttons[i] = gtk_check_button_new_with_label(debug_levels[i].name);
1134 gtk_widget_set_tooltip_text(buttons[i], debug_levels[i].help);
1135 gtk_box_pack_start(GTK_BOX(box), buttons[i], FALSE, FALSE, 6);
1136 }
1137
Jens Axboe46974a72012-03-02 19:34:13 +01001138 gtk_widget_show_all(dialog);
1139
1140 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT) {
1141 gtk_widget_destroy(dialog);
1142 return;
1143 }
1144
1145 for (i = 0; i < FD_DEBUG_MAX; i++) {
1146 int set;
1147
1148 set = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(buttons[i]));
1149 if (set)
1150 fio_debug |= (1UL << i);
1151 }
1152
Jens Axboef3e84402012-03-07 13:14:32 +01001153 gfio_graph_font = strdup(gtk_font_button_get_font_name(GTK_FONT_BUTTON(font)));
Jens Axboe8577f4f2012-03-09 19:28:27 +01001154 gfio_graph_limit = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spin));
1155 update_graph_limits();
Jens Axboe1cf6bca2012-03-09 20:20:17 +01001156 gfio_client_ops.eta_msec = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spin_int));
Jens Axboe8577f4f2012-03-09 19:28:27 +01001157
Jens Axboe46974a72012-03-02 19:34:13 +01001158 gtk_widget_destroy(dialog);
1159}
1160
Jens Axboe0420ba62012-02-29 11:16:52 +01001161static void about_dialog(GtkWidget *w, gpointer data)
1162{
Jens Axboe81e4ea62012-03-07 14:18:28 +01001163 const char *authors[] = {
1164 "Jens Axboe <axboe@kernel.dk>",
1165 "Stephen Carmeron <stephenmcameron@gmail.com>",
1166 NULL
1167 };
Jens Axboe84a72ed2012-03-07 14:24:57 +01001168 const char *license[] = {
1169 "Fio is free software; you can redistribute it and/or modify "
1170 "it under the terms of the GNU General Public License as published by "
1171 "the Free Software Foundation; either version 2 of the License, or "
1172 "(at your option) any later version.\n",
1173 "Fio is distributed in the hope that it will be useful, "
1174 "but WITHOUT ANY WARRANTY; without even the implied warranty of "
1175 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the "
1176 "GNU General Public License for more details.\n",
1177 "You should have received a copy of the GNU General Public License "
1178 "along with Fio; if not, write to the Free Software Foundation, Inc., "
1179 "51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n"
1180 };
1181 char *license_trans;
1182
1183 license_trans = g_strconcat(license[0], "\n", license[1], "\n",
1184 license[2], "\n", NULL);
Jens Axboe81e4ea62012-03-07 14:18:28 +01001185
Jens Axboe0420ba62012-02-29 11:16:52 +01001186 gtk_show_about_dialog(NULL,
1187 "program-name", "gfio",
1188 "comments", "Gtk2 UI for fio",
Jens Axboe84a72ed2012-03-07 14:24:57 +01001189 "license", license_trans,
Jens Axboe81e4ea62012-03-07 14:18:28 +01001190 "website", "http://git.kernel.dk/?p=fio.git;a=summary",
1191 "authors", authors,
Jens Axboe0420ba62012-02-29 11:16:52 +01001192 "version", fio_version_string,
Jens Axboe81e4ea62012-03-07 14:18:28 +01001193 "copyright", "© 2012 Jens Axboe <axboe@kernel.dk>",
Jens Axboe0420ba62012-02-29 11:16:52 +01001194 "logo-icon-name", "fio",
1195 /* Must be last: */
Jens Axboe81e4ea62012-03-07 14:18:28 +01001196 "wrap-license", TRUE,
Jens Axboe0420ba62012-02-29 11:16:52 +01001197 NULL);
Jens Axboe84a72ed2012-03-07 14:24:57 +01001198
Jens Axboe2f99deb2012-03-09 14:37:29 +01001199 g_free(license_trans);
Jens Axboe0420ba62012-02-29 11:16:52 +01001200}
1201
1202static GtkActionEntry menu_items[] = {
Jens Axboe46974a72012-03-02 19:34:13 +01001203 { "FileMenuAction", GTK_STOCK_FILE, "File", NULL, NULL, NULL},
Jens Axboe9b260bd2012-03-06 11:02:52 +01001204 { "ViewMenuAction", GTK_STOCK_FILE, "View", NULL, NULL, NULL},
Jens Axboe16ce5ad2012-03-12 11:56:09 +01001205 { "JobMenuAction", GTK_STOCK_FILE, "Job", NULL, NULL, NULL},
Jens Axboe46974a72012-03-02 19:34:13 +01001206 { "HelpMenuAction", GTK_STOCK_HELP, "Help", NULL, NULL, NULL},
Jens Axboe2f99deb2012-03-09 14:37:29 +01001207 { "NewFile", GTK_STOCK_NEW, "New", "<Control>N", NULL, G_CALLBACK(file_new) },
Jens Axboe16ce5ad2012-03-12 11:56:09 +01001208 { "CloseFile", GTK_STOCK_CLOSE, "Close", "<Control>W", NULL, G_CALLBACK(file_close) },
Jens Axboe46974a72012-03-02 19:34:13 +01001209 { "OpenFile", GTK_STOCK_OPEN, NULL, "<Control>O", NULL, G_CALLBACK(file_open) },
1210 { "SaveFile", GTK_STOCK_SAVE, NULL, "<Control>S", NULL, G_CALLBACK(file_save) },
1211 { "Preferences", GTK_STOCK_PREFERENCES, NULL, "<Control>p", NULL, G_CALLBACK(preferences) },
Jens Axboe9b260bd2012-03-06 11:02:52 +01001212 { "ViewLog", NULL, "Log", "<Control>l", NULL, G_CALLBACK(view_log) },
Jens Axboe781ccba2012-03-15 09:44:42 +01001213 { "ViewResults", NULL, "Results", "<Control>R", NULL, G_CALLBACK(view_results) },
Jens Axboebc271d82012-03-15 21:57:40 +01001214 { "ConnectJob", NULL, "Connect", "<Control>D", NULL, G_CALLBACK(connect_job_entry) },
Jens Axboe85dd01e2012-03-12 14:33:16 +01001215 { "EditJob", NULL, "Edit job", "<Control>E", NULL, G_CALLBACK(edit_job_entry) },
1216 { "SendJob", NULL, "Send job", "<Control>X", NULL, G_CALLBACK(send_job_entry) },
1217 { "StartJob", NULL, "Start job", "<Control>L", NULL, G_CALLBACK(start_job_entry) },
Jens Axboe46974a72012-03-02 19:34:13 +01001218 { "Quit", GTK_STOCK_QUIT, NULL, "<Control>Q", NULL, G_CALLBACK(quit_clicked) },
1219 { "About", GTK_STOCK_ABOUT, NULL, NULL, NULL, G_CALLBACK(about_dialog) },
Jens Axboe0420ba62012-02-29 11:16:52 +01001220};
Jens Axboe3e47bd22012-02-29 13:45:02 +01001221static gint nmenu_items = sizeof(menu_items) / sizeof(menu_items[0]);
Jens Axboe0420ba62012-02-29 11:16:52 +01001222
1223static const gchar *ui_string = " \
1224 <ui> \
1225 <menubar name=\"MainMenu\"> \
1226 <menu name=\"FileMenu\" action=\"FileMenuAction\"> \
Jens Axboe2f99deb2012-03-09 14:37:29 +01001227 <menuitem name=\"New\" action=\"NewFile\" /> \
Jens Axboebf641382012-03-15 13:46:16 +01001228 <menuitem name=\"Open\" action=\"OpenFile\" /> \
Jens Axboe16ce5ad2012-03-12 11:56:09 +01001229 <menuitem name=\"Close\" action=\"CloseFile\" /> \
Jens Axboe2f99deb2012-03-09 14:37:29 +01001230 <separator name=\"Separator1\"/> \
Jens Axboe0420ba62012-02-29 11:16:52 +01001231 <menuitem name=\"Save\" action=\"SaveFile\" /> \
Jens Axboe46974a72012-03-02 19:34:13 +01001232 <separator name=\"Separator2\"/> \
Jens Axboe2f99deb2012-03-09 14:37:29 +01001233 <menuitem name=\"Preferences\" action=\"Preferences\" /> \
1234 <separator name=\"Separator3\"/> \
Jens Axboe261f21d2012-03-12 14:58:22 +01001235 <placeholder name=\"FileRecentFiles\"/> \
1236 <separator name=\"Separator4\"/> \
Jens Axboe0420ba62012-02-29 11:16:52 +01001237 <menuitem name=\"Quit\" action=\"Quit\" /> \
1238 </menu> \
Jens Axboe16ce5ad2012-03-12 11:56:09 +01001239 <menu name=\"JobMenu\" action=\"JobMenuAction\"> \
Jens Axboe85dd01e2012-03-12 14:33:16 +01001240 <menuitem name=\"Connect\" action=\"ConnectJob\" /> \
Jens Axboe261f21d2012-03-12 14:58:22 +01001241 <separator name=\"Separator5\"/> \
Jens Axboe85dd01e2012-03-12 14:33:16 +01001242 <menuitem name=\"Edit job\" action=\"EditJob\" /> \
1243 <menuitem name=\"Send job\" action=\"SendJob\" /> \
Jens Axboe261f21d2012-03-12 14:58:22 +01001244 <separator name=\"Separator6\"/> \
Jens Axboe85dd01e2012-03-12 14:33:16 +01001245 <menuitem name=\"Start job\" action=\"StartJob\" /> \
Jens Axboe16ce5ad2012-03-12 11:56:09 +01001246 </menu>\
Jens Axboe9b260bd2012-03-06 11:02:52 +01001247 <menu name=\"ViewMenu\" action=\"ViewMenuAction\"> \
Jens Axboe781ccba2012-03-15 09:44:42 +01001248 <menuitem name=\"Results\" action=\"ViewResults\" /> \
1249 <separator name=\"Separator7\"/> \
Jens Axboe9b260bd2012-03-06 11:02:52 +01001250 <menuitem name=\"Log\" action=\"ViewLog\" /> \
1251 </menu>\
Jens Axboe0420ba62012-02-29 11:16:52 +01001252 <menu name=\"Help\" action=\"HelpMenuAction\"> \
1253 <menuitem name=\"About\" action=\"About\" /> \
1254 </menu> \
1255 </menubar> \
1256 </ui> \
1257";
1258
Jens Axboe4cbe7212012-03-06 13:36:17 +01001259static GtkWidget *get_menubar_menu(GtkWidget *window, GtkUIManager *ui_manager,
1260 struct gui *ui)
Jens Axboe0420ba62012-02-29 11:16:52 +01001261{
Jens Axboeca664f42012-03-14 19:49:40 +01001262 GtkActionGroup *action_group;
Jens Axboe0420ba62012-02-29 11:16:52 +01001263 GError *error = 0;
1264
1265 action_group = gtk_action_group_new("Menu");
Jens Axboe4cbe7212012-03-06 13:36:17 +01001266 gtk_action_group_add_actions(action_group, menu_items, nmenu_items, ui);
Jens Axboe0420ba62012-02-29 11:16:52 +01001267
1268 gtk_ui_manager_insert_action_group(ui_manager, action_group, 0);
1269 gtk_ui_manager_add_ui_from_string(GTK_UI_MANAGER(ui_manager), ui_string, -1, &error);
1270
1271 gtk_window_add_accel_group(GTK_WINDOW(window), gtk_ui_manager_get_accel_group(ui_manager));
Jens Axboe02421e62012-03-12 12:05:50 +01001272
Jens Axboe0420ba62012-02-29 11:16:52 +01001273 return gtk_ui_manager_get_widget(ui_manager, "/MainMenu");
1274}
1275
1276void gfio_ui_setup(GtkSettings *settings, GtkWidget *menubar,
Jens Axboe1252d8f2012-03-21 11:13:31 +01001277 GtkWidget *vbox, GtkUIManager *ui_manager)
Jens Axboe0420ba62012-02-29 11:16:52 +01001278{
Jens Axboe1252d8f2012-03-21 11:13:31 +01001279 gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 0);
Jens Axboe0420ba62012-02-29 11:16:52 +01001280}
1281
Jens Axboec80b74b2012-03-12 10:23:28 +01001282static void combo_entry_changed(GtkComboBox *box, gpointer data)
1283{
1284 struct gui_entry *ge = (struct gui_entry *) data;
1285 gint index;
1286
1287 index = gtk_combo_box_get_active(box);
1288
1289 multitext_set_entry(&ge->eta.iotype, index);
Jens Axboe99d633a2012-03-15 15:55:04 +01001290 multitext_set_entry(&ge->eta.bs, index);
Jens Axboec80b74b2012-03-12 10:23:28 +01001291 multitext_set_entry(&ge->eta.ioengine, index);
1292 multitext_set_entry(&ge->eta.iodepth, index);
1293}
1294
1295static void combo_entry_destroy(GtkWidget *widget, gpointer data)
1296{
1297 struct gui_entry *ge = (struct gui_entry *) data;
1298
1299 multitext_free(&ge->eta.iotype);
Jens Axboe99d633a2012-03-15 15:55:04 +01001300 multitext_free(&ge->eta.bs);
Jens Axboec80b74b2012-03-12 10:23:28 +01001301 multitext_free(&ge->eta.ioengine);
1302 multitext_free(&ge->eta.iodepth);
1303}
1304
Jens Axboe2f99deb2012-03-09 14:37:29 +01001305static GtkWidget *new_client_page(struct gui_entry *ge)
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001306{
Jens Axboe2f99deb2012-03-09 14:37:29 +01001307 GtkWidget *main_vbox, *probe, *probe_frame, *probe_box;
Jens Axboe65476332012-03-13 10:37:04 +01001308 GtkWidget *scrolled_window, *bottom_align, *top_align, *top_vbox;
Jens Axboe0420ba62012-02-29 11:16:52 +01001309
Jens Axboe2f99deb2012-03-09 14:37:29 +01001310 main_vbox = gtk_vbox_new(FALSE, 3);
Stephen M. Cameron45032dd2012-02-24 08:17:31 +01001311
Jens Axboe65476332012-03-13 10:37:04 +01001312 top_align = gtk_alignment_new(0, 0, 1, 0);
1313 top_vbox = gtk_vbox_new(FALSE, 3);
1314 gtk_container_add(GTK_CONTAINER(top_align), top_vbox);
1315 gtk_box_pack_start(GTK_BOX(main_vbox), top_align, FALSE, FALSE, 0);
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +01001316
Jens Axboe3e47bd22012-02-29 13:45:02 +01001317 probe = gtk_frame_new("Job");
Jens Axboe2f99deb2012-03-09 14:37:29 +01001318 gtk_box_pack_start(GTK_BOX(main_vbox), probe, FALSE, FALSE, 3);
Jens Axboe843ad232012-02-29 11:44:53 +01001319 probe_frame = gtk_vbox_new(FALSE, 3);
1320 gtk_container_add(GTK_CONTAINER(probe), probe_frame);
1321
1322 probe_box = gtk_hbox_new(FALSE, 3);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001323 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, FALSE, FALSE, 3);
1324 ge->probe.hostname = new_info_label_in_frame(probe_box, "Host");
1325 ge->probe.os = new_info_label_in_frame(probe_box, "OS");
1326 ge->probe.arch = new_info_label_in_frame(probe_box, "Architecture");
1327 ge->probe.fio_ver = new_info_label_in_frame(probe_box, "Fio version");
Jens Axboe843ad232012-02-29 11:44:53 +01001328
Jens Axboe3e47bd22012-02-29 13:45:02 +01001329 probe_box = gtk_hbox_new(FALSE, 3);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001330 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, FALSE, FALSE, 3);
1331
Jens Axboe3863d1a2012-03-09 17:39:05 +01001332 ge->eta.names = new_combo_entry_in_frame(probe_box, "Jobs");
Jens Axboec80b74b2012-03-12 10:23:28 +01001333 g_signal_connect(ge->eta.names, "changed", G_CALLBACK(combo_entry_changed), ge);
1334 g_signal_connect(ge->eta.names, "destroy", G_CALLBACK(combo_entry_destroy), ge);
1335 ge->eta.iotype.entry = new_info_entry_in_frame(probe_box, "IO");
Jens Axboe99d633a2012-03-15 15:55:04 +01001336 ge->eta.bs.entry = new_info_entry_in_frame(probe_box, "Blocksize (Read/Write)");
Jens Axboec80b74b2012-03-12 10:23:28 +01001337 ge->eta.ioengine.entry = new_info_entry_in_frame(probe_box, "IO Engine");
1338 ge->eta.iodepth.entry = new_info_entry_in_frame(probe_box, "IO Depth");
Jens Axboe2f99deb2012-03-09 14:37:29 +01001339 ge->eta.jobs = new_info_entry_in_frame(probe_box, "Jobs");
1340 ge->eta.files = new_info_entry_in_frame(probe_box, "Open files");
1341
1342 probe_box = gtk_hbox_new(FALSE, 3);
1343 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, FALSE, FALSE, 3);
1344 ge->eta.read_bw = new_info_entry_in_frame(probe_box, "Read BW");
1345 ge->eta.read_iops = new_info_entry_in_frame(probe_box, "IOPS");
1346 ge->eta.write_bw = new_info_entry_in_frame(probe_box, "Write BW");
1347 ge->eta.write_iops = new_info_entry_in_frame(probe_box, "IOPS");
1348
1349 /*
1350 * Only add this if we have a commit rate
1351 */
1352#if 0
1353 probe_box = gtk_hbox_new(FALSE, 3);
Jens Axboe3e47bd22012-02-29 13:45:02 +01001354 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, TRUE, FALSE, 3);
Jens Axboe807f9972012-03-02 10:25:24 +01001355
Jens Axboe2f99deb2012-03-09 14:37:29 +01001356 ge->eta.cr_bw = new_info_label_in_frame(probe_box, "Commit BW");
1357 ge->eta.cr_iops = new_info_label_in_frame(probe_box, "Commit IOPS");
1358
1359 ge->eta.cw_bw = new_info_label_in_frame(probe_box, "Commit BW");
1360 ge->eta.cw_iops = new_info_label_in_frame(probe_box, "Commit IOPS");
1361#endif
1362
1363 /*
1364 * Set up a drawing area and IOPS and bandwidth graphs
1365 */
Jens Axboe2f99deb2012-03-09 14:37:29 +01001366 ge->graphs.drawing_area = gtk_drawing_area_new();
Jens Axboe2f99deb2012-03-09 14:37:29 +01001367 gtk_widget_set_size_request(GTK_WIDGET(ge->graphs.drawing_area),
Stephen M. Cameron57f9d282012-03-11 11:36:51 +01001368 DRAWING_AREA_XDIM, DRAWING_AREA_YDIM);
Jens Axboe1252d8f2012-03-21 11:13:31 +01001369 gtk_widget_modify_bg(ge->graphs.drawing_area, GTK_STATE_NORMAL, &gfio_color_white);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001370 g_signal_connect(G_OBJECT(ge->graphs.drawing_area), "expose_event",
1371 G_CALLBACK(on_expose_drawing_area), &ge->graphs);
1372 g_signal_connect(G_OBJECT(ge->graphs.drawing_area), "configure_event",
1373 G_CALLBACK(on_config_drawing_area), &ge->graphs);
Jens Axboe65476332012-03-13 10:37:04 +01001374 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
1375 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
Jens Axboe2f99deb2012-03-09 14:37:29 +01001376 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
Jens Axboe65476332012-03-13 10:37:04 +01001377 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled_window),
Jens Axboe2f99deb2012-03-09 14:37:29 +01001378 ge->graphs.drawing_area);
Jens Axboe65476332012-03-13 10:37:04 +01001379 gtk_box_pack_start(GTK_BOX(main_vbox), scrolled_window, TRUE, TRUE, 0);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001380
1381 setup_graphs(&ge->graphs);
1382
1383 /*
1384 * Set up alignments for widgets at the bottom of ui,
1385 * align bottom left, expand horizontally but not vertically
1386 */
Jens Axboe65476332012-03-13 10:37:04 +01001387 bottom_align = gtk_alignment_new(0, 1, 1, 0);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001388 ge->buttonbox = gtk_hbox_new(FALSE, 0);
Jens Axboe65476332012-03-13 10:37:04 +01001389 gtk_container_add(GTK_CONTAINER(bottom_align), ge->buttonbox);
1390 gtk_box_pack_start(GTK_BOX(main_vbox), bottom_align, FALSE, FALSE, 0);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001391
Jens Axboe05775432012-03-21 14:07:11 +01001392 add_buttons(ge, buttonspeclist, ARRAY_SIZE(buttonspeclist));
Jens Axboe2f99deb2012-03-09 14:37:29 +01001393
1394 /*
1395 * Set up thread status progress bar
1396 */
1397 ge->thread_status_pb = gtk_progress_bar_new();
1398 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(ge->thread_status_pb), 0.0);
1399 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(ge->thread_status_pb), "No connections");
1400 gtk_container_add(GTK_CONTAINER(ge->buttonbox), ge->thread_status_pb);
1401
1402
1403 return main_vbox;
1404}
1405
1406static GtkWidget *new_main_page(struct gui *ui)
1407{
1408 GtkWidget *main_vbox, *probe, *probe_frame, *probe_box;
Jens Axboe65476332012-03-13 10:37:04 +01001409 GtkWidget *scrolled_window, *bottom_align, *top_align, *top_vbox;
Jens Axboe2f99deb2012-03-09 14:37:29 +01001410
1411 main_vbox = gtk_vbox_new(FALSE, 3);
1412
1413 /*
1414 * Set up alignments for widgets at the top of ui,
1415 * align top left, expand horizontally but not vertically
1416 */
Jens Axboe65476332012-03-13 10:37:04 +01001417 top_align = gtk_alignment_new(0, 0, 1, 0);
1418 top_vbox = gtk_vbox_new(FALSE, 0);
1419 gtk_container_add(GTK_CONTAINER(top_align), top_vbox);
1420 gtk_box_pack_start(GTK_BOX(main_vbox), top_align, FALSE, FALSE, 0);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001421
1422 probe = gtk_frame_new("Run statistics");
1423 gtk_box_pack_start(GTK_BOX(main_vbox), probe, FALSE, FALSE, 3);
1424 probe_frame = gtk_vbox_new(FALSE, 3);
1425 gtk_container_add(GTK_CONTAINER(probe), probe_frame);
Jens Axboe3e47bd22012-02-29 13:45:02 +01001426
1427 probe_box = gtk_hbox_new(FALSE, 3);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001428 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, FALSE, FALSE, 3);
Jens Axboe3863d1a2012-03-09 17:39:05 +01001429 ui->eta.jobs = new_info_entry_in_frame(probe_box, "Running");
Jens Axboeca850992012-03-05 20:04:43 +01001430 ui->eta.read_bw = new_info_entry_in_frame(probe_box, "Read BW");
1431 ui->eta.read_iops = new_info_entry_in_frame(probe_box, "IOPS");
1432 ui->eta.write_bw = new_info_entry_in_frame(probe_box, "Write BW");
1433 ui->eta.write_iops = new_info_entry_in_frame(probe_box, "IOPS");
Jens Axboe807f9972012-03-02 10:25:24 +01001434
1435 /*
1436 * Only add this if we have a commit rate
1437 */
1438#if 0
1439 probe_box = gtk_hbox_new(FALSE, 3);
1440 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, TRUE, FALSE, 3);
1441
Jens Axboe3e47bd22012-02-29 13:45:02 +01001442 ui->eta.cr_bw = new_info_label_in_frame(probe_box, "Commit BW");
1443 ui->eta.cr_iops = new_info_label_in_frame(probe_box, "Commit IOPS");
1444
Jens Axboe3e47bd22012-02-29 13:45:02 +01001445 ui->eta.cw_bw = new_info_label_in_frame(probe_box, "Commit BW");
1446 ui->eta.cw_iops = new_info_label_in_frame(probe_box, "Commit IOPS");
Jens Axboe807f9972012-03-02 10:25:24 +01001447#endif
Jens Axboe3e47bd22012-02-29 13:45:02 +01001448
Stephen M. Cameron45032dd2012-02-24 08:17:31 +01001449 /*
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001450 * Set up a drawing area and IOPS and bandwidth graphs
Stephen M. Cameron736f2df2012-02-24 08:17:32 +01001451 */
Jens Axboe2f99deb2012-03-09 14:37:29 +01001452 ui->graphs.drawing_area = gtk_drawing_area_new();
Jens Axboe2f99deb2012-03-09 14:37:29 +01001453 gtk_widget_set_size_request(GTK_WIDGET(ui->graphs.drawing_area),
Stephen M. Cameron57f9d282012-03-11 11:36:51 +01001454 DRAWING_AREA_XDIM, DRAWING_AREA_YDIM);
Jens Axboe1252d8f2012-03-21 11:13:31 +01001455 gtk_widget_modify_bg(ui->graphs.drawing_area, GTK_STATE_NORMAL, &gfio_color_white);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001456 g_signal_connect(G_OBJECT(ui->graphs.drawing_area), "expose_event",
1457 G_CALLBACK(on_expose_drawing_area), &ui->graphs);
1458 g_signal_connect(G_OBJECT(ui->graphs.drawing_area), "configure_event",
1459 G_CALLBACK(on_config_drawing_area), &ui->graphs);
Jens Axboe65476332012-03-13 10:37:04 +01001460 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
1461 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
Stephen M. Cameron736f2df2012-02-24 08:17:32 +01001462 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
Jens Axboe65476332012-03-13 10:37:04 +01001463 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled_window),
Jens Axboe2f99deb2012-03-09 14:37:29 +01001464 ui->graphs.drawing_area);
Jens Axboe65476332012-03-13 10:37:04 +01001465 gtk_box_pack_start(GTK_BOX(main_vbox), scrolled_window,
Stephen M. Camerone1645342012-02-24 08:17:32 +01001466 TRUE, TRUE, 0);
Stephen M. Cameron736f2df2012-02-24 08:17:32 +01001467
Jens Axboe2f99deb2012-03-09 14:37:29 +01001468 setup_graphs(&ui->graphs);
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001469
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +01001470 /*
1471 * Set up alignments for widgets at the bottom of ui,
1472 * align bottom left, expand horizontally but not vertically
1473 */
Jens Axboe65476332012-03-13 10:37:04 +01001474 bottom_align = gtk_alignment_new(0, 1, 1, 0);
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +01001475 ui->buttonbox = gtk_hbox_new(FALSE, 0);
Jens Axboe65476332012-03-13 10:37:04 +01001476 gtk_container_add(GTK_CONTAINER(bottom_align), ui->buttonbox);
1477 gtk_box_pack_start(GTK_BOX(main_vbox), bottom_align, FALSE, FALSE, 0);
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +01001478
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001479 /*
1480 * Set up thread status progress bar
1481 */
1482 ui->thread_status_pb = gtk_progress_bar_new();
1483 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(ui->thread_status_pb), 0.0);
Jens Axboe8663ea62012-03-02 14:04:30 +01001484 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(ui->thread_status_pb), "No connections");
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001485 gtk_container_add(GTK_CONTAINER(ui->buttonbox), ui->thread_status_pb);
1486
Jens Axboe2f99deb2012-03-09 14:37:29 +01001487 return main_vbox;
1488}
1489
1490static gboolean notebook_switch_page(GtkNotebook *notebook, GtkWidget *widget,
1491 guint page, gpointer data)
1492
1493{
Jens Axboe02421e62012-03-12 12:05:50 +01001494 struct gui *ui = (struct gui *) data;
Jens Axboe85dd01e2012-03-12 14:33:16 +01001495 struct gui_entry *ge;
Jens Axboe02421e62012-03-12 12:05:50 +01001496
Jens Axboe85dd01e2012-03-12 14:33:16 +01001497 if (!page) {
1498 set_job_menu_visible(ui, 0);
Jens Axboe781ccba2012-03-15 09:44:42 +01001499 set_view_results_visible(ui, 0);
Jens Axboe85dd01e2012-03-12 14:33:16 +01001500 return TRUE;
1501 }
1502
1503 set_job_menu_visible(ui, 1);
Jens Axboe6e02ad62012-03-20 12:25:36 +01001504 ge = get_ge_from_page(ui, page, NULL);
Jens Axboe85dd01e2012-03-12 14:33:16 +01001505 if (ge)
1506 update_button_states(ui, ge);
1507
Jens Axboe2f99deb2012-03-09 14:37:29 +01001508 return TRUE;
1509}
1510
Jens Axboe38634cb2012-03-13 12:26:41 +01001511static gint compare_recent_items(GtkRecentInfo *a, GtkRecentInfo *b)
1512{
1513 time_t time_a = gtk_recent_info_get_visited(a);
1514 time_t time_b = gtk_recent_info_get_visited(b);
1515
1516 return time_b - time_a;
1517}
1518
1519static void add_recent_file_items(struct gui *ui)
1520{
1521 const gchar *gfio = g_get_application_name();
1522 GList *items, *item;
1523 int i = 0;
1524
1525 if (ui->recent_ui_id) {
1526 gtk_ui_manager_remove_ui(ui->uimanager, ui->recent_ui_id);
1527 gtk_ui_manager_ensure_update(ui->uimanager);
1528 }
1529 ui->recent_ui_id = gtk_ui_manager_new_merge_id(ui->uimanager);
1530
1531 if (ui->actiongroup) {
1532 gtk_ui_manager_remove_action_group(ui->uimanager, ui->actiongroup);
1533 g_object_unref(ui->actiongroup);
1534 }
1535 ui->actiongroup = gtk_action_group_new("RecentFileActions");
1536
1537 gtk_ui_manager_insert_action_group(ui->uimanager, ui->actiongroup, -1);
1538
1539 items = gtk_recent_manager_get_items(ui->recentmanager);
1540 items = g_list_sort(items, (GCompareFunc) compare_recent_items);
1541
1542 for (item = items; item && item->data; item = g_list_next(item)) {
1543 GtkRecentInfo *info = (GtkRecentInfo *) item->data;
1544 gchar *action_name;
1545 const gchar *label;
1546 GtkAction *action;
1547
1548 if (!gtk_recent_info_has_application(info, gfio))
1549 continue;
1550
1551 /*
1552 * We only support local files for now
1553 */
1554 if (!gtk_recent_info_is_local(info) || !gtk_recent_info_exists(info))
1555 continue;
1556
1557 action_name = g_strdup_printf("RecentFile%u", i++);
1558 label = gtk_recent_info_get_display_name(info);
1559
1560 action = g_object_new(GTK_TYPE_ACTION,
1561 "name", action_name,
1562 "label", label, NULL);
1563
1564 g_object_set_data_full(G_OBJECT(action), "gtk-recent-info",
1565 gtk_recent_info_ref(info),
1566 (GDestroyNotify) gtk_recent_info_unref);
1567
1568
1569 g_signal_connect(action, "activate", G_CALLBACK(recent_open), ui);
1570
1571 gtk_action_group_add_action(ui->actiongroup, action);
1572 g_object_unref(action);
1573
1574 gtk_ui_manager_add_ui(ui->uimanager, ui->recent_ui_id,
1575 "/MainMenu/FileMenu/FileRecentFiles",
1576 label, action_name,
1577 GTK_UI_MANAGER_MENUITEM, FALSE);
1578
1579 g_free(action_name);
1580
1581 if (i == 8)
1582 break;
1583 }
1584
1585 g_list_foreach(items, (GFunc) gtk_recent_info_unref, NULL);
1586 g_list_free(items);
1587}
1588
Jens Axboea6790902012-03-13 15:16:11 +01001589static void drag_and_drop_received(GtkWidget *widget, GdkDragContext *ctx,
Jens Axboe6e02ad62012-03-20 12:25:36 +01001590 gint x, gint y, GtkSelectionData *seldata,
1591 guint info, guint time, gpointer *data)
Jens Axboea6790902012-03-13 15:16:11 +01001592{
Jens Axboe6e02ad62012-03-20 12:25:36 +01001593 struct gui *ui = (struct gui *) data;
Jens Axboea6790902012-03-13 15:16:11 +01001594 gchar **uris;
1595 GtkWidget *source;
Jens Axboea6790902012-03-13 15:16:11 +01001596
1597 source = gtk_drag_get_source_widget(ctx);
1598 if (source && widget == gtk_widget_get_toplevel(source)) {
1599 gtk_drag_finish(ctx, FALSE, FALSE, time);
1600 return;
1601 }
1602
Jens Axboe6e02ad62012-03-20 12:25:36 +01001603 uris = gtk_selection_data_get_uris(seldata);
Jens Axboea6790902012-03-13 15:16:11 +01001604 if (!uris) {
1605 gtk_drag_finish(ctx, FALSE, FALSE, time);
1606 return;
1607 }
1608
Jens Axboe0cf3ece2012-03-21 10:15:20 +01001609 if (uris[0])
1610 do_file_open_with_tab(ui, uris[0]);
Jens Axboea6790902012-03-13 15:16:11 +01001611
1612 gtk_drag_finish(ctx, TRUE, FALSE, time);
1613 g_strfreev(uris);
1614}
1615
Jens Axboe2f99deb2012-03-09 14:37:29 +01001616static void init_ui(int *argc, char **argv[], struct gui *ui)
1617{
1618 GtkSettings *settings;
Jens Axboe02421e62012-03-12 12:05:50 +01001619 GtkWidget *vbox;
Jens Axboe2f99deb2012-03-09 14:37:29 +01001620
1621 /* Magical g*thread incantation, you just need this thread stuff.
1622 * Without it, the update that happens in gfio_update_thread_status
1623 * doesn't really happen in a timely fashion, you need expose events
1624 */
1625 if (!g_thread_supported())
1626 g_thread_init(NULL);
1627 gdk_threads_init();
1628
1629 gtk_init(argc, argv);
1630 settings = gtk_settings_get_default();
1631 gtk_settings_set_long_property(settings, "gtk_tooltip_timeout", 10, "gfio setting");
1632 g_type_init();
Jens Axboe1252d8f2012-03-21 11:13:31 +01001633 gdk_color_parse("white", &gfio_color_white);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001634
1635 ui->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
Stephen M. Cameron814479d2012-03-15 07:58:14 +01001636 gtk_window_set_title(GTK_WINDOW(ui->window), "fio");
Jens Axboe2f99deb2012-03-09 14:37:29 +01001637 gtk_window_set_default_size(GTK_WINDOW(ui->window), 1024, 768);
1638
Jens Axboe6e02ad62012-03-20 12:25:36 +01001639 g_signal_connect(ui->window, "delete-event", G_CALLBACK(quit_clicked), ui);
1640 g_signal_connect(ui->window, "destroy", G_CALLBACK(quit_clicked), ui);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001641
1642 ui->vbox = gtk_vbox_new(FALSE, 0);
1643 gtk_container_add(GTK_CONTAINER(ui->window), ui->vbox);
1644
Jens Axboe02421e62012-03-12 12:05:50 +01001645 ui->uimanager = gtk_ui_manager_new();
1646 ui->menu = get_menubar_menu(ui->window, ui->uimanager, ui);
1647 gfio_ui_setup(settings, ui->menu, ui->vbox, ui->uimanager);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001648
Jens Axboe38634cb2012-03-13 12:26:41 +01001649 ui->recentmanager = gtk_recent_manager_get_default();
1650 add_recent_file_items(ui);
1651
Jens Axboe2f99deb2012-03-09 14:37:29 +01001652 ui->notebook = gtk_notebook_new();
1653 g_signal_connect(ui->notebook, "switch-page", G_CALLBACK(notebook_switch_page), ui);
Jens Axboeb870c312012-03-09 17:22:01 +01001654 gtk_notebook_set_scrollable(GTK_NOTEBOOK(ui->notebook), 1);
Jens Axboe0aa928c2012-03-09 17:24:07 +01001655 gtk_notebook_popup_enable(GTK_NOTEBOOK(ui->notebook));
Jens Axboe2f99deb2012-03-09 14:37:29 +01001656 gtk_container_add(GTK_CONTAINER(ui->vbox), ui->notebook);
1657
1658 vbox = new_main_page(ui);
Jens Axboe0cf3ece2012-03-21 10:15:20 +01001659 gtk_drag_dest_set(GTK_WIDGET(ui->window), GTK_DEST_DEFAULT_ALL, NULL, 1, GDK_ACTION_COPY);
Jens Axboea6790902012-03-13 15:16:11 +01001660 gtk_drag_dest_add_uri_targets(GTK_WIDGET(ui->window));
1661 g_signal_connect(ui->window, "drag-data-received", G_CALLBACK(drag_and_drop_received), ui);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001662
1663 gtk_notebook_append_page(GTK_NOTEBOOK(ui->notebook), vbox, gtk_label_new("Main"));
1664
Jens Axboe9b260bd2012-03-06 11:02:52 +01001665 gfio_ui_setup_log(ui);
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001666
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001667 gtk_widget_show_all(ui->window);
1668}
1669
Stephen M. Cameron8232e282012-02-24 08:17:31 +01001670int main(int argc, char *argv[], char *envp[])
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001671{
Stephen M. Cameron8232e282012-02-24 08:17:31 +01001672 if (initialize_fio(envp))
1673 return 1;
Jens Axboe0420ba62012-02-29 11:16:52 +01001674 if (fio_init_options())
1675 return 1;
Stephen M. Camerona1820202012-02-24 08:17:31 +01001676
Jens Axboe2f99deb2012-03-09 14:37:29 +01001677 memset(&main_ui, 0, sizeof(main_ui));
Jens Axboeb98ab712012-03-21 12:48:32 +01001678 main_ui.ge_hash = g_hash_table_new(g_int_hash, g_int_equal);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001679
1680 init_ui(&argc, &argv, &main_ui);
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +01001681
Stephen M. Cameron2839f0c2012-02-24 08:17:31 +01001682 gdk_threads_enter();
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001683 gtk_main();
Stephen M. Cameron2839f0c2012-02-24 08:17:31 +01001684 gdk_threads_leave();
Jens Axboeb98ab712012-03-21 12:48:32 +01001685
1686 g_hash_table_destroy(main_ui.ge_hash);
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001687 return 0;
1688}