static void thunar_uca_provider_child_watch (ThunarUcaProvider *uca_provider, gint exit_status) { GFileMonitor *monitor; GFile *file; g_return_if_fail (THUNAR_UCA_IS_PROVIDER (uca_provider)); GDK_THREADS_ENTER (); /* verify that we still have a valid child_watch_path */ if (G_LIKELY (uca_provider->child_watch_path != NULL)) { /* determine the corresponding file */ file = g_file_new_for_path (uca_provider->child_watch_path); /* schedule a changed notification on the path */ monitor = g_file_monitor (file, G_FILE_MONITOR_NONE, NULL, NULL); if (monitor != NULL) { g_file_monitor_emit_event (monitor, file, file, G_FILE_MONITOR_EVENT_CHANGED); g_object_unref (monitor); } /* release the file */ g_object_unref (file); } thunar_uca_provider_child_watch_destroy (uca_provider, NULL); GDK_THREADS_LEAVE (); }
static void thunar_uca_provider_activated (ThunarUcaProvider *uca_provider, GtkAction *action) { GtkTreeRowReference *row; ThunarUcaContext *uca_context; GtkTreePath *path; GtkTreeIter iter; GtkWidget *dialog; GtkWidget *window; gboolean succeed; GSource *source; GError *error = NULL; GList *files; gchar **argv; gchar *working_directory = NULL; gchar *filename; gchar *label; gchar *uri; gint argc; gint pid; g_return_if_fail (THUNAR_UCA_IS_PROVIDER (uca_provider)); g_return_if_fail (GTK_IS_ACTION (action)); /* check if the row reference is still valid */ row = g_object_get_qdata (G_OBJECT (action), thunar_uca_row_quark); if (G_UNLIKELY (!gtk_tree_row_reference_valid (row))) return; /* determine the iterator for the item */ path = gtk_tree_row_reference_get_path (row); gtk_tree_model_get_iter (GTK_TREE_MODEL (uca_provider->model), &iter, path); gtk_tree_path_free (path); /* determine the files and the window for the action */ uca_context = g_object_get_qdata (G_OBJECT (action), thunar_uca_context_quark); window = thunar_uca_context_get_window (uca_context); files = thunar_uca_context_get_files (uca_context); /* determine the argc/argv for the item */ succeed = thunar_uca_model_parse_argv (uca_provider->model, &iter, files, &argc, &argv, &error); if (G_LIKELY (succeed)) { /* determine the working from the first file */ if (G_LIKELY (files != NULL)) { /* determine the filename of the first selected file */ uri = thunarx_file_info_get_uri (files->data); filename = g_filename_from_uri (uri, NULL, NULL); if (G_LIKELY (filename != NULL)) { /* if this is a folder action, we just use the filename as working directory */ if (g_object_get_qdata (G_OBJECT (action), thunar_uca_folder_quark) != NULL) { working_directory = filename; filename = NULL; } else { working_directory = g_path_get_dirname (filename); } } g_free (filename); g_free (uri); } /* spawn the command on the window's screen */ succeed = gdk_spawn_on_screen (gtk_widget_get_screen (GTK_WIDGET (window)), working_directory, argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH, NULL, NULL, &pid, &error); /* check if we succeed */ if (G_LIKELY (succeed)) { /* check if we already have a child watch */ if (G_UNLIKELY (uca_provider->child_watch_id >= 0)) { /* reset the callback function to g_spawn_close_pid() so the plugin can be * safely unloaded and the child will still not become a zombie afterwards. */ source = g_main_context_find_source_by_id (NULL, uca_provider->child_watch_id); g_source_set_callback (source, (GSourceFunc) g_spawn_close_pid, NULL, NULL); } /* schedule the new child watch */ uca_provider->child_watch_id = g_child_watch_add_full (G_PRIORITY_LOW, pid, thunar_uca_provider_child_watch, uca_provider, thunar_uca_provider_child_watch_destroy); /* take over ownership of the working directory as child watch path */ uca_provider->child_watch_path = working_directory; working_directory = NULL; } /* cleanup */ g_free (working_directory); g_strfreev (argv); } /* present error message to the user */ if (G_UNLIKELY (!succeed)) { g_object_get (G_OBJECT (action), "label", &label, NULL); dialog = gtk_message_dialog_new ((GtkWindow *) window, GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, _("Failed to launch action \"%s\"."), label); gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s.", error->message); gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (dialog); g_error_free (error); g_free (label); } }
static void thunar_uca_provider_activated (ThunarUcaProvider *uca_provider, GtkAction *action) { GtkTreeRowReference *row; ThunarUcaContext *uca_context; GtkTreePath *path; GtkTreeIter iter; GtkWidget *dialog; GtkWidget *window; gboolean succeed; GError *error = NULL; GList *files; gchar **argv; gchar *working_directory = NULL; gchar *filename; gchar *label; gchar *uri; gint argc; gchar *icon_name = NULL; gboolean startup_notify; GClosure *child_watch; g_return_if_fail (THUNAR_UCA_IS_PROVIDER (uca_provider)); g_return_if_fail (GTK_IS_ACTION (action)); /* check if the row reference is still valid */ row = g_object_get_qdata (G_OBJECT (action), thunar_uca_row_quark); if (G_UNLIKELY (!gtk_tree_row_reference_valid (row))) return; /* determine the iterator for the item */ path = gtk_tree_row_reference_get_path (row); gtk_tree_model_get_iter (GTK_TREE_MODEL (uca_provider->model), &iter, path); gtk_tree_path_free (path); /* determine the files and the window for the action */ uca_context = g_object_get_qdata (G_OBJECT (action), thunar_uca_context_quark); window = thunar_uca_context_get_window (uca_context); files = thunar_uca_context_get_files (uca_context); /* determine the argc/argv for the item */ succeed = thunar_uca_model_parse_argv (uca_provider->model, &iter, files, &argc, &argv, &error); if (G_LIKELY (succeed)) { /* get the icon name and whether startup notification is active */ gtk_tree_model_get (GTK_TREE_MODEL (uca_provider->model), &iter, THUNAR_UCA_MODEL_COLUMN_ICON, &icon_name, THUNAR_UCA_MODEL_COLUMN_STARTUP_NOTIFY, &startup_notify, -1); /* determine the working from the first file */ if (G_LIKELY (files != NULL)) { /* determine the filename of the first selected file */ uri = thunarx_file_info_get_uri (files->data); filename = g_filename_from_uri (uri, NULL, NULL); if (G_LIKELY (filename != NULL)) { /* if this is a folder action, we just use the filename as working directory */ if (g_object_get_qdata (G_OBJECT (action), thunar_uca_folder_quark) != NULL) { working_directory = filename; filename = NULL; } else { working_directory = g_path_get_dirname (filename); } } g_free (filename); g_free (uri); } /* build closre for child watch */ child_watch = g_cclosure_new_swap (G_CALLBACK (thunar_uca_provider_child_watch), uca_provider, thunar_uca_provider_child_watch_destroy); g_closure_ref (child_watch); g_closure_sink (child_watch); /* spawn the command on the window's screen */ succeed = xfce_spawn_on_screen_with_child_watch (gtk_widget_get_screen (GTK_WIDGET (window)), working_directory, argv, NULL, G_SPAWN_SEARCH_PATH, startup_notify, gtk_get_current_event_time (), icon_name, child_watch, &error); /* check if we succeed */ if (G_LIKELY (succeed)) { /* release existing child watch */ thunar_uca_provider_child_watch_destroy (uca_provider, NULL); /* set new closure */ uca_provider->child_watch = child_watch; /* take over ownership of the working directory as child watch path */ uca_provider->child_watch_path = working_directory; working_directory = NULL; } else { /* spawn failed, release watch */ g_closure_unref (child_watch); } /* cleanup */ g_free (working_directory); g_strfreev (argv); g_free (icon_name); } /* present error message to the user */ if (G_UNLIKELY (!succeed)) { g_object_get (G_OBJECT (action), "label", &label, NULL); dialog = gtk_message_dialog_new ((GtkWindow *) window, GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, _("Failed to launch action \"%s\"."), label); gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s.", error->message); gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (dialog); g_error_free (error); g_free (label); } }