gfio: add recently opened files to File menu
Signed-off-by: Jens Axboe <axboe@kernel.dk>
diff --git a/gfio.c b/gfio.c
index 02211f4..f5df1bb 100644
--- a/gfio.c
+++ b/gfio.c
@@ -32,6 +32,8 @@
#include "fio.h"
#include "graph.h"
+#define GFIO_MIME "text/fio"
+
static int gfio_server_running;
static const char *gfio_graph_font;
static unsigned int gfio_graph_limit = 100;
@@ -105,6 +107,9 @@
*/
struct gui {
GtkUIManager *uimanager;
+ GtkRecentManager *recentmanager;
+ GtkActionGroup *actiongroup;
+ guint recent_ui_id;
GtkWidget *menu;
GtkWidget *window;
GtkWidget *vbox;
@@ -2082,13 +2087,19 @@
* Return the 'ge' corresponding to the tab. If the active tab is the
* main tab, open a new tab.
*/
-static struct gui_entry *get_ge_from_page(gint cur_page)
+static struct gui_entry *get_ge_from_page(gint cur_page, int *created)
{
struct flist_head *entry;
struct gui_entry *ge;
- if (!cur_page)
+ if (!cur_page) {
+ if (created)
+ *created = 1;
return get_new_ge_with_tab("Untitled");
+ }
+
+ if (created)
+ *created = 0;
flist_for_each(entry, &main_ui.list) {
ge = flist_entry(entry, struct gui_entry, list);
@@ -2109,7 +2120,7 @@
*/
cur_page = gtk_notebook_get_current_page(GTK_NOTEBOOK(ui->notebook));
if (cur_page)
- return get_ge_from_page(cur_page);
+ return get_ge_from_page(cur_page, NULL);
return NULL;
}
@@ -2136,25 +2147,68 @@
gtk_main_quit();
}
+static void file_add_recent(struct gui *ui, const gchar *uri)
+{
+ gtk_recent_manager_add_item(ui->recentmanager, uri);
+}
+
+static gchar *get_filename_from_uri(const gchar *uri)
+{
+ if (strncmp(uri, "file://", 7))
+ return strdup(uri);
+
+ return strdup(uri + 7);
+}
+
+static int do_file_open(struct gui_entry *ge, const gchar *uri, char *host,
+ int type, int port)
+{
+ struct fio_client *client;
+ gchar *filename;
+
+ filename = get_filename_from_uri(uri);
+
+ ge->job_files = realloc(ge->job_files, (ge->nr_job_files + 1) * sizeof(char *));
+ ge->job_files[ge->nr_job_files] = strdup(filename);
+ ge->nr_job_files++;
+
+ client = fio_client_add_explicit(&gfio_client_ops, host, type, port);
+ if (!client) {
+ GError *error;
+
+ error = g_error_new(g_quark_from_string("fio"), 1,
+ "Failed to add client %s", host);
+ report_error(error);
+ g_error_free(error);
+ return 1;
+ }
+
+ gfio_client_added(ge, client);
+ file_add_recent(ge->ui, uri);
+ return 0;
+}
+
static void file_open(GtkWidget *w, gpointer data)
{
struct gui *ui = data;
GtkWidget *dialog;
GSList *filenames, *fn_glist;
GtkFileFilter *filter;
- char *host;
- int port, type, server_start;
+ int port, type, server_start, ge_is_new = 0;
struct gui_entry *ge;
gint cur_page;
+ char *host;
/*
* Creates new tab if current tab is the main window, or the
* current tab already has a client.
*/
cur_page = gtk_notebook_get_current_page(GTK_NOTEBOOK(ui->notebook));
- ge = get_ge_from_page(cur_page);
- if (ge->client)
+ ge = get_ge_from_page(cur_page, &ge_is_new);
+ if (ge->client) {
ge = get_new_ge_with_tab("Untitled");
+ ge_is_new = 1;
+ }
gtk_notebook_set_current_page(GTK_NOTEBOOK(ui->notebook), ge->page_num);
@@ -2170,11 +2224,14 @@
gtk_file_filter_add_pattern(filter, "*.fio");
gtk_file_filter_add_pattern(filter, "*.job");
gtk_file_filter_add_pattern(filter, "*.ini");
- gtk_file_filter_add_mime_type(filter, "text/fio");
+ gtk_file_filter_add_mime_type(filter, GFIO_MIME);
gtk_file_filter_set_name(filter, "Fio job file");
gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(dialog), filter);
if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT) {
+ if (ge_is_new)
+ gtk_widget_destroy(ge->vbox);
+
gtk_widget_destroy(dialog);
return;
}
@@ -2183,28 +2240,16 @@
gtk_widget_destroy(dialog);
- if (get_connection_details(&host, &port, &type, &server_start))
- goto err;
+ if (get_connection_details(&host, &port, &type, &server_start)) {
+ if (ge_is_new)
+ gtk_widget_destroy(ge->vbox);
+
+ goto done;
+ }
filenames = fn_glist;
while (filenames != NULL) {
- struct fio_client *client;
-
- ge->job_files = realloc(ge->job_files, (ge->nr_job_files + 1) * sizeof(char *));
- ge->job_files[ge->nr_job_files] = strdup(filenames->data);
- ge->nr_job_files++;
-
- client = fio_client_add_explicit(&gfio_client_ops, host, type, port);
- if (!client) {
- GError *error;
-
- error = g_error_new(g_quark_from_string("fio"), 1,
- "Failed to add client %s", host);
- report_error(error);
- g_error_free(error);
- }
- gfio_client_added(ge, client);
-
+ do_file_open(ge, filenames->data, host, type, port);
g_free(filenames->data);
filenames = g_slist_next(filenames);
}
@@ -2212,8 +2257,9 @@
if (server_start)
gfio_start_server();
-err:
+done:
g_slist_free(fn_glist);
+
}
static void file_save(GtkWidget *w, gpointer data)
@@ -2773,13 +2819,138 @@
}
set_job_menu_visible(ui, 1);
- ge = get_ge_from_page(page);
+ ge = get_ge_from_page(page, NULL);
if (ge)
update_button_states(ui, ge);
return TRUE;
}
+static void recent_open(GtkAction *action, gpointer data)
+{
+ struct gui *ui = (struct gui *) data;
+ int port, type, server_start;
+ struct gui_entry *ge;
+ GtkRecentInfo *info;
+ const gchar *uri;
+ gint cur_page;
+ char *host;
+ int ret, ge_is_new = 0;
+
+ /*
+ * Creates new tab if current tab is the main window, or the
+ * current tab already has a client.
+ */
+ cur_page = gtk_notebook_get_current_page(GTK_NOTEBOOK(ui->notebook));
+ ge = get_ge_from_page(cur_page, &ge_is_new);
+ if (ge->client) {
+ ge = get_new_ge_with_tab("Untitled");
+ ge_is_new = 1;
+ }
+
+ gtk_notebook_set_current_page(GTK_NOTEBOOK(ui->notebook), ge->page_num);
+
+ info = g_object_get_data(G_OBJECT(action), "gtk-recent-info");
+ uri = gtk_recent_info_get_uri(info);
+
+ if (get_connection_details(&host, &port, &type, &server_start)) {
+ if (ge_is_new)
+ gtk_widget_destroy(ge->vbox);
+
+ return;
+ }
+
+ ret = do_file_open(ge, uri, host, type, port);
+
+ free(host);
+
+ if (!ret) {
+ if (server_start)
+ gfio_start_server();
+ } else {
+ if (ge_is_new)
+ gtk_widget_destroy(ge->vbox);
+ }
+}
+
+static gint compare_recent_items(GtkRecentInfo *a, GtkRecentInfo *b)
+{
+ time_t time_a = gtk_recent_info_get_visited(a);
+ time_t time_b = gtk_recent_info_get_visited(b);
+
+ return time_b - time_a;
+}
+
+static void add_recent_file_items(struct gui *ui)
+{
+ const gchar *gfio = g_get_application_name();
+ GList *items, *item;
+ int i = 0;
+
+ if (ui->recent_ui_id) {
+ gtk_ui_manager_remove_ui(ui->uimanager, ui->recent_ui_id);
+ gtk_ui_manager_ensure_update(ui->uimanager);
+ }
+ ui->recent_ui_id = gtk_ui_manager_new_merge_id(ui->uimanager);
+
+ if (ui->actiongroup) {
+ gtk_ui_manager_remove_action_group(ui->uimanager, ui->actiongroup);
+ g_object_unref(ui->actiongroup);
+ }
+ ui->actiongroup = gtk_action_group_new("RecentFileActions");
+
+ gtk_ui_manager_insert_action_group(ui->uimanager, ui->actiongroup, -1);
+
+ items = gtk_recent_manager_get_items(ui->recentmanager);
+ items = g_list_sort(items, (GCompareFunc) compare_recent_items);
+
+ for (item = items; item && item->data; item = g_list_next(item)) {
+ GtkRecentInfo *info = (GtkRecentInfo *) item->data;
+ gchar *action_name;
+ const gchar *label;
+ GtkAction *action;
+
+ if (!gtk_recent_info_has_application(info, gfio))
+ continue;
+
+ /*
+ * We only support local files for now
+ */
+ if (!gtk_recent_info_is_local(info) || !gtk_recent_info_exists(info))
+ continue;
+
+ action_name = g_strdup_printf("RecentFile%u", i++);
+ label = gtk_recent_info_get_display_name(info);
+
+ action = g_object_new(GTK_TYPE_ACTION,
+ "name", action_name,
+ "label", label, NULL);
+
+ g_object_set_data_full(G_OBJECT(action), "gtk-recent-info",
+ gtk_recent_info_ref(info),
+ (GDestroyNotify) gtk_recent_info_unref);
+
+
+ g_signal_connect(action, "activate", G_CALLBACK(recent_open), ui);
+
+ gtk_action_group_add_action(ui->actiongroup, action);
+ g_object_unref(action);
+
+ gtk_ui_manager_add_ui(ui->uimanager, ui->recent_ui_id,
+ "/MainMenu/FileMenu/FileRecentFiles",
+ label, action_name,
+ GTK_UI_MANAGER_MENUITEM, FALSE);
+
+ g_free(action_name);
+
+ if (i == 8)
+ break;
+ }
+
+ g_list_foreach(items, (GFunc) gtk_recent_info_unref, NULL);
+ g_list_free(items);
+}
+
static void init_ui(int *argc, char **argv[], struct gui *ui)
{
GtkSettings *settings;
@@ -2812,6 +2983,9 @@
ui->menu = get_menubar_menu(ui->window, ui->uimanager, ui);
gfio_ui_setup(settings, ui->menu, ui->vbox, ui->uimanager);
+ ui->recentmanager = gtk_recent_manager_get_default();
+ add_recent_file_items(ui);
+
ui->notebook = gtk_notebook_new();
g_signal_connect(ui->notebook, "switch-page", G_CALLBACK(notebook_switch_page), ui);
gtk_notebook_set_scrollable(GTK_NOTEBOOK(ui->notebook), 1);