From 2853a5c24eb6daa351687f6685f5fe71560412b7 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Sat, 29 Aug 2015 21:47:05 +0300 Subject: [PATCH] Implement a mount manager mode --- README.txt | 4 ++ main.c | 123 ++++++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 101 insertions(+), 26 deletions(-) diff --git a/README.txt b/README.txt index 9bdd562..cb99468 100644 --- a/README.txt +++ b/README.txt @@ -18,6 +18,10 @@ In addition, there are some command-line switches: manager. The command is run without arguments in the directory where the device was mounted. + -m + Start a persistent mount manager window from which devices can be both + mounted and unmounted. + -h Displays a summary of options. diff --git a/main.c b/main.c index 5aa9611..24b87fc 100644 --- a/main.c +++ b/main.c @@ -30,8 +30,15 @@ typedef struct sDevice time_t time; } Device; +typedef struct sGuiContext +{ + int manager; + GtkWidget *list; + GtkWidget *button; + char *post_mount_command; +} GuiContext; + int verbosity = 0; -char *post_mount_command = NULL; /** Parses a string of the form name=value and places the components in a Property @@ -759,12 +766,29 @@ int toggle_device(Device *device, char *out_buf, int out_size) return 0; } +/** +Callback for selection in the device list changing. Updates the action button +label according to device status. +*/ +void selection_changed(GtkTreeSelection *selection, gpointer user_data) +{ + GuiContext *context = (GuiContext *)user_data; + GtkTreeIter iter; + GtkTreeModel *model; + Device *device; + + gtk_tree_selection_get_selected(selection, &model, &iter); + gtk_tree_model_get(model, &iter, 1, &device, -1); + gtk_button_set_label(GTK_BUTTON(context->button), (device->mount_point ? "Unmount" : "Mount")); +} + /** Callback for activating a row in the device list. Mounts or unmounts the device depending on operating mode. */ void row_activated(GtkTreeView *list, GtkTreePath *path, GtkTreeViewColumn *column, gpointer user_data) { + GuiContext *context = (GuiContext *)user_data; GtkTreeModel *model; GtkTreeIter iter; Device *device; @@ -786,23 +810,36 @@ void row_activated(GtkTreeView *list, GtkTreePath *path, GtkTreeViewColumn *colu /* Pmount terminated with nonzero status or a signal. Display an error to the user. */ dialog = gtk_message_dialog_new(NULL, 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "%s", output); - g_signal_connect(dialog, "response", >k_main_quit, NULL); + if(context->manager) + g_signal_connect(dialog, "response", G_CALLBACK(>k_widget_destroy), dialog); + else + g_signal_connect(dialog, "response", G_CALLBACK(>k_main_quit), NULL); gtk_widget_show_all(dialog); return; } - gtk_main_quit(); + if(context->manager) + { + gtk_list_store_set(GTK_LIST_STORE(model), &iter, + 2, !!device->mount_point, + 3, device->mount_point, + -1); + + gtk_button_set_label(GTK_BUTTON(context->button), (device->mount_point ? "Unmount" : "Mount")); + } + else + gtk_main_quit(); - if(post_mount_command && device->mount_point) + if(context->post_mount_command && device->mount_point) { if(verbosity>=1) - printf("Running %s in %s\n", post_mount_command, device->mount_point); + printf("Running %s in %s\n", context->post_mount_command, device->mount_point); pid = fork(); if(pid==0) { chdir(device->mount_point); - execlp(post_mount_command, post_mount_command, NULL); + execlp(context->post_mount_command, context->post_mount_command, NULL); _exit(1); } } @@ -817,16 +854,18 @@ list to be activated. */ void button_clicked(GtkButton *button, gpointer user_data) { - GtkWidget *list = (GtkWidget *)user_data; + GuiContext *context = (GuiContext *)user_data; GtkTreeSelection *selection; GtkTreeIter iter; GtkTreeModel *model; GtkTreePath *path; + GtkTreeViewColumn *column; - selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(list)); + selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(context->list)); gtk_tree_selection_get_selected(selection, &model, &iter); path = gtk_tree_model_get_path(model, &iter); - gtk_tree_view_row_activated(GTK_TREE_VIEW(list), path, gtk_tree_view_get_column(GTK_TREE_VIEW(list), 0)); + column = gtk_tree_view_get_column(GTK_TREE_VIEW(context->list), 0); + gtk_tree_view_row_activated(GTK_TREE_VIEW(context->list), path, column); gtk_tree_path_free(path); (void)button; @@ -858,18 +897,19 @@ void show_help(void) " -v Increase verbosity\n" " -u Unmount a device (default is mount)\n" " -r Run a command after mounting\n" + " -m Start a persistent mount manager\n" " -h Display this help\n"); } int main(int argc, char **argv) { + GuiContext context; GtkWidget *window; GtkWidget *box; GtkWidget *viewport; - GtkWidget *list; GtkListStore *store; GtkTreeSelection *selection; - GtkWidget *button; + GtkCellRenderer *mounted_toggle; GtkTreeIter iter; Device *devices; int i; @@ -878,9 +918,12 @@ int main(int argc, char **argv) int umount = 0; int n_listed; + context.manager = 0; + context.post_mount_command = NULL; + gtk_init(&argc, &argv); - while((opt = getopt(argc, argv, "vur:h"))!=-1) switch(opt) + while((opt = getopt(argc, argv, "vur:mh"))!=-1) switch(opt) { case 'v': ++verbosity; @@ -889,7 +932,10 @@ int main(int argc, char **argv) umount = 1; break; case 'r': - post_mount_command = optarg; + context.post_mount_command = optarg; + break; + case 'm': + context.manager = 1; break; case 'h': show_help(); @@ -908,20 +954,40 @@ int main(int argc, char **argv) gtk_viewport_set_shadow_type(GTK_VIEWPORT(viewport), GTK_SHADOW_IN); gtk_box_pack_start(GTK_BOX(box), viewport, TRUE, TRUE, 0); - list = gtk_tree_view_new(); - gtk_container_add(GTK_CONTAINER(viewport), list); - g_signal_connect(list, "row-activated", G_CALLBACK(&row_activated), NULL); + context.list = gtk_tree_view_new(); + gtk_container_add(GTK_CONTAINER(viewport), context.list); + g_signal_connect(context.list, "row-activated", G_CALLBACK(&row_activated), &context); - store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_POINTER); - gtk_tree_view_set_model(GTK_TREE_VIEW(list), GTK_TREE_MODEL(store)); - gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(list), + store = gtk_list_store_new(4, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_BOOLEAN, G_TYPE_STRING); + gtk_tree_view_set_model(GTK_TREE_VIEW(context.list), GTK_TREE_MODEL(store)); + gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(context.list), -1, "Device", gtk_cell_renderer_text_new(), "text", 0, NULL); - selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(list)); + if(context.manager) + { + GtkTreeViewColumn *mounted_column; + GtkCellRenderer *mount_point_renderer; + + mounted_column = gtk_tree_view_column_new(); + gtk_tree_view_column_set_title(mounted_column, "Mounted"); + + mounted_toggle = gtk_cell_renderer_toggle_new(); + gtk_tree_view_column_pack_start(mounted_column, mounted_toggle, FALSE); + gtk_tree_view_column_add_attribute(mounted_column, mounted_toggle, "active", 2); + + mount_point_renderer = gtk_cell_renderer_text_new(); + gtk_tree_view_column_pack_start(mounted_column, mount_point_renderer, TRUE); + gtk_tree_view_column_add_attribute(mounted_column, mount_point_renderer, "text", 3); + + gtk_tree_view_insert_column(GTK_TREE_VIEW(context.list), mounted_column, -1); + } + + selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(context.list)); + g_signal_connect(selection, "changed", G_CALLBACK(&selection_changed), &context); - button = gtk_button_new_with_label(umount ? "Unmount" : "Mount"); - g_signal_connect(button, "clicked", G_CALLBACK(&button_clicked), list); - gtk_box_pack_start(GTK_BOX(box), button, FALSE, TRUE, 0); + context.button = gtk_button_new_with_label(umount ? "Unmount" : "Mount"); + g_signal_connect(context.button, "clicked", G_CALLBACK(&button_clicked), &context); + gtk_box_pack_start(GTK_BOX(box), context.button, FALSE, TRUE, 0); devices = get_devices(); n_listed = 0; @@ -930,10 +996,15 @@ int main(int argc, char **argv) /* Populate the list with devices in appropriate state. */ latest = 0; for(i=0; devices[i].node; ++i) - if(!devices[i].mount_point==!umount) + if(!devices[i].mount_point==!umount || context.manager) { gtk_list_store_append(store, &iter); - gtk_list_store_set(store, &iter, 0, devices[i].description, 1, &devices[i], -1); + gtk_list_store_set(store, &iter, + 0, devices[i].description, + 1, &devices[i], + 2, !!devices[i].mount_point, + 3, devices[i].mount_point, + -1); if(devices[i].time>latest) { /* Pre-select the device that appeared on the system most recently. */ @@ -946,7 +1017,7 @@ int main(int argc, char **argv) } - if(n_listed) + if(n_listed || context.manager) gtk_widget_show_all(window); else { -- 2.43.0