X-Git-Url: http://git.tdb.fi/?p=pmount-gui.git;a=blobdiff_plain;f=main.c;h=81bc4bffd77899c9b3a80e6ee34f8e98c426c393;hp=59bf3050d4e12d8f768933fa0415168729aa0bf3;hb=f11c283e0e045a9eafed90e83521d2205dea0a2c;hpb=bc3ad56fe16e81448031e2ee3799f0a1595837f7 diff --git a/main.c b/main.c index 59bf305..81bc4bf 100644 --- a/main.c +++ b/main.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -33,10 +34,16 @@ typedef struct sDevice typedef struct sGuiContext { int manager; + int autohide; Device *devices; + GtkWidget *window; GtkWidget *list; GtkWidget *button; char *post_mount_command; + int inotify_fd; + int dev_wd; + GIOChannel *inotify_channel; + int refresh_pending; } GuiContext; int verbosity = 0; @@ -821,6 +828,28 @@ int refresh_devices(GuiContext *context, int umount) return n_listed; } +/** +Handles an automatic refresh of the device list in response to inotify events. +*/ +gboolean refresh_devices_idle(gpointer data) +{ + GuiContext *context = (GuiContext *)data; + int n_listed; + + n_listed = refresh_devices(context, -1); + context->refresh_pending = 0; + + if(context->autohide) + { + if(n_listed) + gtk_widget_show_all(context->window); + else + gtk_widget_hide(context->window); + } + + return FALSE; +} + /** Callback for selection in the device list changing. Updates the action button label according to device status. @@ -945,6 +974,32 @@ gboolean key_press(GtkWidget *widget, GdkEvent *event, gpointer user_data) return FALSE; } +/** +Callback for inotify events. +*/ +gboolean inotify_event_available(GIOChannel *source, GIOCondition condition, gpointer user_data) +{ + GuiContext *context = (GuiContext *)user_data; + int fd; + char eventbuf[sizeof(struct inotify_event)+NAME_MAX+1]; + int len; + + fd = g_io_channel_unix_get_fd(source); + len = read(fd, eventbuf, sizeof(eventbuf)); + if(len>=(int)sizeof(struct inotify_event)) + { + if(!context->refresh_pending) + { + g_timeout_add(500, &refresh_devices_idle, context); + context->refresh_pending = 1; + } + } + + (void)condition; + + return TRUE; +} + void show_help(void) { printf("pmount-gui\n" @@ -955,13 +1010,13 @@ void show_help(void) " -u Unmount a device (default is mount)\n" " -r Run a command after mounting\n" " -m Start a persistent mount manager\n" + " -M Like -m, but hide the window if there are no devices\n" " -h Display this help\n"); } int main(int argc, char **argv) { GuiContext context; - GtkWidget *window; GtkWidget *box; GtkWidget *viewport; GtkListStore *store; @@ -972,12 +1027,17 @@ int main(int argc, char **argv) int n_listed; context.manager = 0; + context.autohide = 0; context.devices = NULL; context.post_mount_command = NULL; + context.inotify_fd = -1; + context.dev_wd = -1; + context.inotify_channel = NULL; + context.refresh_pending = 0; gtk_init(&argc, &argv); - while((opt = getopt(argc, argv, "vur:mh"))!=-1) switch(opt) + while((opt = getopt(argc, argv, "vur:mMh"))!=-1) switch(opt) { case 'v': ++verbosity; @@ -990,19 +1050,24 @@ int main(int argc, char **argv) break; case 'm': context.manager = 1; + context.autohide = 0; + break; + case 'M': + context.manager = 1; + context.autohide = 1; break; case 'h': show_help(); return 0; } - window = gtk_window_new(GTK_WINDOW_TOPLEVEL); - gtk_container_set_border_width(GTK_CONTAINER(window), 5); - g_signal_connect(window, "destroy", G_CALLBACK(>k_main_quit), NULL); - g_signal_connect(window, "key-press-event", G_CALLBACK(&key_press), NULL); + context.window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_container_set_border_width(GTK_CONTAINER(context.window), 5); + g_signal_connect(context.window, "destroy", G_CALLBACK(>k_main_quit), NULL); + g_signal_connect(context.window, "key-press-event", G_CALLBACK(&key_press), NULL); box = gtk_vbox_new(FALSE, 5); - gtk_container_add(GTK_CONTAINER(window), box); + gtk_container_add(GTK_CONTAINER(context.window), box); viewport = gtk_viewport_new(NULL, NULL); gtk_viewport_set_shadow_type(GTK_VIEWPORT(viewport), GTK_SHADOW_IN); @@ -1034,6 +1099,19 @@ int main(int argc, char **argv) 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); + + context.inotify_fd = inotify_init(); + if(context.inotify_fd>=0) + { + context.dev_wd = inotify_add_watch(context.inotify_fd, "/dev/disk/by-id", IN_CREATE|IN_DELETE); + + context.inotify_channel = g_io_channel_unix_new(context.inotify_fd); + g_io_add_watch(context.inotify_channel, G_IO_IN, &inotify_event_available, &context); + } + else + printf("Warning: Unable to initialize inotify\n"); + + umount = -1; } selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(context.list)); @@ -1045,9 +1123,9 @@ int main(int argc, char **argv) n_listed = refresh_devices(&context, umount); - if(n_listed || context.manager) - gtk_widget_show_all(window); - else + if(n_listed || (context.manager && !context.autohide)) + gtk_widget_show_all(context.window); + else if(!context.manager) { GtkWidget *dialog; @@ -1061,6 +1139,8 @@ int main(int argc, char **argv) gtk_main(); free_devices(context.devices); + if(context.inotify_fd>=0) + close(context.inotify_fd); return 0; }