/* vi:set sw=2 sts=2 ts=2 et ai: */ /*- * Copyright (c) 2009 Jannis Pohlmann . * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include "thunar-job.h" #define THUNAR_JOB_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), THUNAR_TYPE_JOB, ThunarJobPrivate)) /* Property identifiers */ enum { PROP_0, PROP_SOURCE_FILES, PROP_DESTINATION_FILES, PROP_JOB_FUNCTION, }; static void thunar_job_class_init (ThunarJobClass *klass); static void thunar_job_init (ThunarJob *job); static void thunar_job_constructed (GObject *object); static void thunar_job_finalize (GObject *object); static void thunar_job_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); static void thunar_job_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); static gboolean thunar_job_finish (ThunarJob *job, GAsyncResult *result, GError **error); static void thunar_job_async_ready (GObject *object, GAsyncResult *result); static void thunar_job_data_free (ThunarJobData *data); struct _ThunarJobClass { GObjectClass __parent__; }; struct _ThunarJob { GObject __parent__; ThunarJobPrivate *priv; }; struct _ThunarJobPrivate { GCancellable *cancellable; ThunarJobFunc job_function; GList *source_files; GList *target_files; }; static GObjectClass *thunar_job_parent_class = NULL; GType thunar_job_get_type (void) { static GType type = G_TYPE_INVALID; if (G_UNLIKELY (type == G_TYPE_INVALID)) { type = g_type_register_static_simple (G_TYPE_OBJECT, "ThunarJob", sizeof (ThunarJobClass), (GClassInitFunc) thunar_job_class_init, sizeof (ThunarJob), (GInstanceInitFunc) thunar_job_init, 0); } return type; } static void thunar_job_class_init (ThunarJobClass *klass) { GObjectClass *gobject_class; g_type_class_add_private (klass, sizeof (ThunarJobPrivate)); /* Determine the parent type class */ thunar_job_parent_class = g_type_class_peek_parent (klass); gobject_class = G_OBJECT_CLASS (klass); gobject_class->constructed = thunar_job_constructed; gobject_class->finalize = thunar_job_finalize; gobject_class->get_property = thunar_job_get_property; gobject_class->set_property = thunar_job_set_property; g_object_class_install_property (gobject_class, PROP_SOURCE_FILES, g_param_spec_pointer ("source-files", "source-files", "source-files", G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property (gobject_class, PROP_DESTINATION_FILES, g_param_spec_pointer ("target-files", "target-files", "target-files", G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property (gobject_class, PROP_JOB_FUNCTION, g_param_spec_pointer ("job-function", "job-function", "job-function", G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); g_signal_new ("ask", THUNAR_TYPE_JOB, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_BOOLEAN__FLAGS, G_TYPE_BOOLEAN, 1, G_TYPE_INT); g_signal_new ("error", THUNAR_TYPE_JOB, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); g_signal_new ("finished", THUNAR_TYPE_JOB, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); g_signal_new ("status-message", THUNAR_TYPE_JOB, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1, G_TYPE_STRING); } static void thunar_job_init (ThunarJob *job) { job->priv = THUNAR_JOB_GET_PRIVATE (job); job->priv->cancellable = g_cancellable_new (); job->priv->job_function = NULL; job->priv->source_files = NULL; job->priv->target_files = NULL; } static void thunar_job_constructed (GObject *object) { ThunarJob *job = THUNAR_JOB (object); } static void thunar_job_finalize (GObject *object) { ThunarJob *job = THUNAR_JOB (object); g_object_unref (job->priv->cancellable); (*G_OBJECT_CLASS (thunar_job_parent_class)->finalize) (object); } static void thunar_job_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { ThunarJob *job = THUNAR_JOB (object); switch (prop_id) { case PROP_JOB_FUNCTION: g_value_set_pointer (value, job->priv->job_function); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void thunar_job_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { ThunarJob *job = THUNAR_JOB (object); switch (prop_id) { case PROP_SOURCE_FILES: job->priv->source_files = g_list_copy (g_value_get_pointer (value)); g_list_foreach (job->priv->source_files, (GFunc) g_object_ref, NULL); break; case PROP_DESTINATION_FILES: job->priv->target_files = g_list_copy (g_value_get_pointer (value)); g_list_foreach (job->priv->target_files, (GFunc) g_object_ref, NULL); break; case PROP_JOB_FUNCTION: job->priv->job_function = g_value_get_pointer (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static gboolean thunar_job_thread (GIOSchedulerJob *job, GCancellable *cancellable, gpointer user_data) { GSimpleAsyncResult *result = user_data; ThunarJobData *data; GError *error = NULL; gboolean success; data = g_simple_async_result_get_op_res_gpointer (result); data->gio_job = job; data->cancellable = g_object_ref (cancellable); data->error = &error; g_return_val_if_fail (THUNAR_IS_JOB (data->job), FALSE); g_return_val_if_fail (data->job->priv->job_function != NULL, FALSE); success = data->job->priv->job_function (data); g_io_scheduler_job_send_to_mainloop (job, (GSourceFunc) gtk_false, NULL, NULL); if (!success) { g_simple_async_result_set_from_error (result, error); g_error_free (error); } g_simple_async_result_complete_in_idle (result); return FALSE; } void thunar_job_launch (ThunarJob *job) { GSimpleAsyncResult *result; ThunarJobData *data; g_return_if_fail (THUNAR_IS_JOB (job)); g_return_if_fail (job->priv->job_function != NULL); data = g_new0 (ThunarJobData, 1); data->job = g_object_ref (job); data->source_files = g_list_copy (job->priv->source_files); g_list_foreach (data->source_files, (GFunc) g_object_ref, NULL); data->target_files = g_list_copy (job->priv->target_files); g_list_foreach (data->target_files, (GFunc) g_object_ref, NULL); result = g_simple_async_result_new (G_OBJECT (job), (GAsyncReadyCallback) thunar_job_async_ready, NULL, thunar_job_launch); g_simple_async_result_set_op_res_gpointer (result, data, (GDestroyNotify) thunar_job_data_free); g_io_scheduler_push_job (thunar_job_thread, result, g_object_unref, 0, job->priv->cancellable); } void thunar_job_cancel (ThunarJob *job) { g_return_if_fail (THUNAR_IS_JOB (job)); g_cancellable_cancel (job->priv->cancellable); } typedef struct { ThunarJob *job; const gchar *signal; gchar *string; gboolean response; } ThunarJobSignalData; static void thunar_job_signal_data_free (ThunarJobSignalData *data) { g_object_unref (data->job); g_free (data->string); g_free (data); } static gboolean thunar_job_emit_string_signal_in_mainloop (gpointer user_data) { ThunarJobSignalData *data = user_data; g_signal_emit_by_name (data->job, data->signal, data->string); return FALSE; } void thunar_job_emit_status_message (ThunarJobData *data, const gchar *message) { ThunarJobSignalData *signal_data; signal_data = g_new0 (ThunarJobSignalData, 1); signal_data->job = g_object_ref (data->job); signal_data->signal = "status-message"; signal_data->string = g_strdup (message); g_io_scheduler_job_send_to_mainloop (data->gio_job, thunar_job_emit_string_signal_in_mainloop, signal_data, (GDestroyNotify) thunar_job_signal_data_free); } static gboolean thunar_job_emit_ask_signal_in_mainloop (gpointer user_data) { ThunarJobSignalData *data = user_data; g_signal_emit_by_name (data->job, data->signal, 0, &(data->response)); return FALSE; } gboolean thunar_job_emit_ask (ThunarJobData *data) { ThunarJobSignalData *signal_data; gboolean response = FALSE; signal_data = g_new0 (ThunarJobSignalData, 1); signal_data->job = g_object_ref (data->job); signal_data->signal = "ask"; signal_data->response = FALSE; g_io_scheduler_job_send_to_mainloop (data->gio_job, thunar_job_emit_ask_signal_in_mainloop, signal_data, NULL); response = signal_data->response; thunar_job_signal_data_free (signal_data); return response; } static gboolean thunar_job_finish (ThunarJob *job, GAsyncResult *result, GError **error) { g_return_val_if_fail (THUNAR_IS_JOB (job), FALSE); g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE); if (G_IS_SIMPLE_ASYNC_RESULT (result)) { GSimpleAsyncResult *simple_result = G_SIMPLE_ASYNC_RESULT (result); if (g_simple_async_result_propagate_error (simple_result, error)) return FALSE; } return TRUE; } static void thunar_job_async_ready (GObject *object, GAsyncResult *result) { ThunarJob *job = THUNAR_JOB (object); GError *error = NULL; gchar *message = NULL; if (!thunar_job_finish (job, result, &error)) { g_assert (error != NULL); g_signal_emit_by_name (job, "error", error); g_error_free (error); } g_signal_emit_by_name (job, "finished", NULL); } static void thunar_job_data_free (ThunarJobData *data) { g_list_foreach (data->source_files, (GFunc) g_object_unref, NULL); g_list_foreach (data->target_files, (GFunc) g_object_unref, NULL); g_object_unref (data->job); g_object_unref (data->cancellable); g_free (data); }