[Xfce4-commits] <xfce4-screenshooter:master> Update the exo-job sources.
Jérôme Guelfucci
noreply at xfce.org
Sun Oct 11 15:42:03 CEST 2009
Updating branch refs/heads/master
to ca33e4f07e5e062d0b6c00e7d0df9c7f59422f33 (commit)
from f19d50ea4d2d47d7ff9cd1a51c8822df0f1abc64 (commit)
commit ca33e4f07e5e062d0b6c00e7d0df9c7f59422f33
Author: Jérôme Guelfucci <jeromeg at xfce.org>
Date: Sun Oct 11 15:33:58 2009 +0200
Update the exo-job sources.
lib/exo-job.c | 177 +++++++++++++++++++++++++++++++------------------
lib/exo-job.h | 37 +++++++----
lib/exo-simple-job.c | 128 +++++++++++++++++++++++++++---------
lib/exo-simple-job.h | 2 +-
4 files changed, 232 insertions(+), 112 deletions(-)
diff --git a/lib/exo-job.c b/lib/exo-job.c
index 10d4481..3f55ba7 100644
--- a/lib/exo-job.c
+++ b/lib/exo-job.c
@@ -27,12 +27,38 @@
#include <gio/gio.h>
#include <gtk/gtk.h>
+#include <libxfce4util/libxfce4util.h>
#include "exo-job.h"
+#define I_(string) (g_intern_static_string ((string)))
+
+/**
+ * SECTION: exo-job
+ * @title: ExoJob
+ * @short_description: Base class for threaded/asynchronous jobs
+ * @include: exo/exo.h
+ * @see_also: <link linkend="ExoSimpleJob">ExoSimpleJob</link>
+ *
+ * <link linkend="ExoJob">ExoJob</link> is an abstract base class
+ * intended to wrap threaded/asynchronous operations (called jobs here).
+ * It was written because the ways of dealing with threads provided by
+ * GLib are not exactly object-oriented.
+ *
+ * It can be used to wrap any kind of long-running or possibly-blocking
+ * operation like file operations or communication with web services.
+ * The benefit of using <link linkend="ExoJob">ExoJob</link> is that one
+ * gets an object associated with each operation. After creating the job
+ * the caller can connect to signals like <link linkend="ExoJob::error">"error"
+ * </link> or <link linkend="ExoJob::percent">"percent"</link>. This
+ * design integrates very well with the usual object-oriented design of
+ * applications based on GObject.
+ **/
-#define EXO_JOB_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EXO_TYPE_JOB, ExoJobPrivate))
+
+#define EXO_JOB_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
+ EXO_TYPE_JOB, ExoJobPrivate))
@@ -52,8 +78,6 @@ typedef struct _ExoJobSignalData ExoJobSignalData;
-static void exo_job_class_init (ExoJobClass *klass);
-static void exo_job_init (ExoJob *job);
static void exo_job_finalize (GObject *object);
static void exo_job_error (ExoJob *job,
GError *error);
@@ -78,29 +102,11 @@ struct _ExoJobSignalData
-static GObjectClass *exo_job_parent_class = NULL;
-static guint job_signals[LAST_SIGNAL];
+static guint job_signals[LAST_SIGNAL];
-GType
-exo_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,
- "ExoJob",
- sizeof (ExoJobClass),
- (GClassInitFunc) exo_job_class_init,
- sizeof (ExoJob),
- (GInstanceInitFunc) exo_job_init,
- G_TYPE_FLAG_ABSTRACT);
- }
-
- return type;
-}
+G_DEFINE_ABSTRACT_TYPE (ExoJob, exo_job, G_TYPE_OBJECT)
@@ -111,9 +117,6 @@ exo_job_class_init (ExoJobClass *klass)
g_type_class_add_private (klass, sizeof (ExoJobPrivate));
- /* Determine the parent type class */
- exo_job_parent_class = g_type_class_peek_parent (klass);
-
gobject_class = G_OBJECT_CLASS (klass);
gobject_class->finalize = exo_job_finalize;
@@ -128,10 +131,19 @@ exo_job_class_init (ExoJobClass *klass)
* @job : an #ExoJob.
* @error : a #GError describing the cause.
*
- * Emitted whenever an error occurs while executing the @job.
+ * Emitted whenever an error occurs while executing the @job. This signal
+ * may not be emitted from within #ExoJob subclasses. If a subclass wants
+ * to emit an "error" signal (and thereby terminate the operation), it has
+ * to fill the #GError structure and abort from its execute() method.
+ * #ExoJob will automatically emit the "error" signal when the #GError is
+ * filled after the execute() method has finished.
+ *
+ * Callers interested in whether the @job was cancelled can connect to
+ * the "cancelled" signal of the #GCancellable returned from
+ * exo_job_get_cancellable().
**/
job_signals[ERROR] =
- g_signal_new ("error",
+ g_signal_new (I_("error"),
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_NO_HOOKS,
G_STRUCT_OFFSET (ExoJobClass, error),
@@ -145,10 +157,12 @@ exo_job_class_init (ExoJobClass *klass)
*
* This signal will be automatically emitted once the @job finishes
* its execution, no matter whether @job completed successfully or
- * was cancelled by the user.
+ * was cancelled by the user. It may not be emitted by subclasses of
+ * #ExoJob as it is automatically emitted by #ExoJob after the execute()
+ * method has finished.
**/
job_signals[FINISHED] =
- g_signal_new ("finished",
+ g_signal_new (I_("finished"),
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_NO_HOOKS,
G_STRUCT_OFFSET (ExoJobClass, finished),
@@ -161,14 +175,14 @@ exo_job_class_init (ExoJobClass *klass)
* @job : an #ExoJob.
* @message : information to be displayed about @job.
*
- * This signal is emitted to display information about the * @job.
- * Examples of messages are "Preparing..." or "Cleaning up...".
+ * This signal is emitted to display information about the status of
+ * the @job. Examples of messages are "Preparing..." or "Cleaning up...".
*
* The @message is garanteed to contain valid UTF-8, so it can be
* displayed by #GtkWidget<!---->s out of the box.
**/
job_signals[INFO_MESSAGE] =
- g_signal_new ("info-message",
+ g_signal_new (I_("info-message"),
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_NO_HOOKS,
G_STRUCT_OFFSET (ExoJobClass, info_message),
@@ -181,12 +195,12 @@ exo_job_class_init (ExoJobClass *klass)
* @job : an #ExoJob.
* @percent : the percentage of completeness.
*
- * This signal is emitted to present the state of the overall
- * progress. The @percent value is garantied to be in the range 0.0
- * to 100.0.
+ * This signal is emitted to present the overall progress of the
+ * operation. The @percent value is garantied to be a value between
+ * 0.0 and 100.0.
**/
job_signals[PERCENT] =
- g_signal_new ("percent",
+ g_signal_new (I_("percent"),
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_NO_HOOKS,
G_STRUCT_OFFSET (ExoJobClass, percent),
@@ -213,7 +227,9 @@ exo_job_finalize (GObject *object)
{
ExoJob *job = EXO_JOB (object);
- exo_job_cancel (job);
+ if (job->priv->running)
+ exo_job_cancel (job);
+
g_object_unref (job->priv->cancellable);
(*G_OBJECT_CLASS (exo_job_parent_class)->finalize) (object);
@@ -230,8 +246,8 @@ exo_job_finalize (GObject *object)
* Finishes the execution of an operation by propagating errors
* from the @result into @error.
*
- * Return value: %TRUE if there was no error during the operation,
- * %FALSE otherwise.
+ * Returns: %TRUE if there was no error during the operation,
+ * %FALSE otherwise.
**/
static gboolean
exo_job_finish (ExoJob *job,
@@ -270,7 +286,7 @@ exo_job_async_ready (GObject *object,
{
g_assert (error != NULL);
- /* don't treat cancellation as an error for now */
+ /* don't treat cancellation as an error */
if (error->code != G_IO_ERROR_CANCELLED)
exo_job_error (job, error);
@@ -278,6 +294,8 @@ exo_job_async_ready (GObject *object,
}
exo_job_finished (job);
+
+ job->priv->running = FALSE;
}
@@ -290,10 +308,9 @@ exo_job_async_ready (GObject *object,
*
* This function is called by the #GIOScheduler to execute the
* operation associated with the job. It basically calls the
- * ExoJobClass#execute function.
+ * execute() function of #ExoJobClass.
*
- * Return value: %FALSE, to stop the thread at the end of the
- * operation.
+ * Returns: %FALSE, to stop the thread at the end of the operation.
**/
static gboolean
exo_job_scheduler_job_func (GIOSchedulerJob *scheduler_job,
@@ -310,7 +327,7 @@ exo_job_scheduler_job_func (GIOSchedulerJob *scheduler_job,
success = (*EXO_JOB_GET_CLASS (job)->execute) (job, &error);
- /* TODO why was this necessary again? */
+ /* TODO why was this necessary again? GIO uses this too, for some reason. */
g_io_scheduler_job_send_to_mainloop (scheduler_job, (GSourceFunc) gtk_false,
NULL, NULL);
@@ -334,8 +351,8 @@ exo_job_scheduler_job_func (GIOSchedulerJob *scheduler_job,
* Called from the main loop of the application to emit the signal
* specified by the @user_data.
*
- * Return value: %FALSE, to keep the function from being called
- * multiple times in a row.
+ * Returns: %FALSE, to keep the function from being called
+ * multiple times in a row.
**/
static gboolean
exo_job_emit_valist_in_mainloop (gpointer user_data)
@@ -359,9 +376,8 @@ exo_job_emit_valist_in_mainloop (gpointer user_data)
* return type of the signal is G_TYPE_NONE, the return
* value location can be omitted.
*
- * Send a the signal with the given @signal_id and @signal_detail to the
- * main loop of the application and waits for the listeners to handle
- * it.
+ * Sends a the signal with the given @signal_id and @signal_detail to the
+ * main loop of the application and waits for listeners to handle it.
**/
static void
exo_job_emit_valist (ExoJob *job,
@@ -436,11 +452,11 @@ exo_job_finished (ExoJob *job)
* @job : an #ExoJob.
*
* This functions schedules the @job to be run as soon as possible, in
- * a separate thread. The caller can then connect to the signals of the
- * returned #ExoJob in order to be notified on errors, progress updates
+ * a separate thread. The caller can connect to signals of the @job prior
+ * or after this call in order to be notified on errors, progress updates
* and the end of the operation.
*
- * Return value: the @job itself.
+ * Returns: the @job itself.
**/
ExoJob *
exo_job_launch (ExoJob *job)
@@ -478,12 +494,17 @@ exo_job_launch (ExoJob *job)
* after the cancellation of @job, it may still emit signals, so you
* must take care of disconnecting all handlers appropriately if you
* cannot handle signals after cancellation.
+ *
+ * Calling this function when the @job has not been launched yet or
+ * when it has already finished will have no effect.
**/
void
exo_job_cancel (ExoJob *job)
{
g_return_if_fail (EXO_IS_JOB (job));
- g_cancellable_cancel (job->priv->cancellable);
+
+ if (job->priv->running)
+ g_cancellable_cancel (job->priv->cancellable);
}
@@ -495,7 +516,7 @@ exo_job_cancel (ExoJob *job)
* Checks whether @job was previously cancelled
* by a call to exo_job_cancel().
*
- * Return value: %TRUE if @job is cancelled.
+ * Returns: %TRUE if @job is cancelled.
**/
gboolean
exo_job_is_cancelled (const ExoJob *job)
@@ -512,8 +533,8 @@ exo_job_is_cancelled (const ExoJob *job)
*
* Returns the #GCancellable that can be used to cancel the @job.
*
- * Return value: the #GCancellable associated with the @job. It
- * is owned by the @job and must not be released.
+ * Returns: the #GCancellable associated with the @job. It
+ * is owned by the @job and must not be released.
**/
GCancellable *
exo_job_get_cancellable (const ExoJob *job)
@@ -537,8 +558,8 @@ exo_job_get_cancellable (const ExoJob *job)
* g_cancellable_set_error_if_cancelled (cancellable, error);
* </programlisting></informalexample>
*
- * Return value: %TRUE if the job was cancelled and @error is now set,
- * %FALSE otherwise.
+ * Returns: %TRUE if the job was cancelled and @error is now set,
+ * %FALSE otherwise.
**/
gboolean
exo_job_set_error_if_cancelled (ExoJob *job,
@@ -555,12 +576,12 @@ exo_job_set_error_if_cancelled (ExoJob *job,
* @job : an #ExoJob.
* @signal_id : the signal id.
* @signal_detail : the signal detail.
- * ... : a list of parameters to be passed to the signal,
+ * @Varargs : a list of parameters to be passed to the signal,
* followed by a location for the return value. If the
* return type of the signal is G_TYPE_NONE, the return
* value location can be omitted.
*
- * Sends the signal with @signal_id and @signal_id to the application's
+ * Sends the signal with @signal_id and @signal_detail to the application's
* main loop and waits for listeners to handle it.
**/
void
@@ -582,9 +603,9 @@ exo_job_emit (ExoJob *job,
/**
* exo_job_info_message:
- * @job : an #ExoJob.
- * @format : a format string.
- * ... : parameters for the format string.
+ * @job : an #ExoJob.
+ * @format : a format string.
+ * @Varargs : parameters for the format string.
*
* Generates and emits an "info-message" signal and sends it to the
* application's main loop.
@@ -625,7 +646,33 @@ exo_job_percent (ExoJob *job,
{
g_return_if_fail (EXO_IS_JOB (job));
- percent = MAX (0.0, MIN (100.0, percent));
+ percent = CLAMP (percent, 0.0, 100.0);
exo_job_emit (job, job_signals[PERCENT], 0, percent);
}
+
+
+/**
+ * exo_job_send_to_mainloop:
+ * @job : an #ExoJob.
+ * @func : a #GSourceFunc callback that will be called in the main thread.
+ * @user_data : data to pass to @func.
+ * @destroy_notify : a #GDestroyNotify for @user_data, or %NULL.
+ *
+ * This functions schedules @func to be run in the main loop (main thread),
+ * waiting for the result (and blocking the job in the meantime).
+ *
+ * Returns: The return value of @func.
+ **/
+gboolean
+exo_job_send_to_mainloop (ExoJob *job,
+ GSourceFunc func,
+ gpointer user_data,
+ GDestroyNotify destroy_notify)
+{
+ g_return_val_if_fail (EXO_IS_JOB (job), FALSE);
+
+ return g_io_scheduler_job_send_to_mainloop (job->priv->scheduler_job, func, user_data,
+ destroy_notify);
+}
+
diff --git a/lib/exo-job.h b/lib/exo-job.h
index 416237a..cc20ce2 100644
--- a/lib/exo-job.h
+++ b/lib/exo-job.h
@@ -18,6 +18,7 @@
* Boston, MA 02110-1301, USA.
*/
+
#ifndef __EXO_JOB_H__
#define __EXO_JOB_H__
@@ -54,6 +55,12 @@ struct _ExoJobClass
gdouble percent);
};
+/**
+ * ExoJob:
+ *
+ * The #ExoJob struct contains only private fields and should not be
+ * directly accessed.
+ **/
struct _ExoJob
{
GObject __parent__;
@@ -64,21 +71,25 @@ struct _ExoJob
GType exo_job_get_type (void) G_GNUC_CONST;
-ExoJob *exo_job_launch (ExoJob *job);
-void exo_job_cancel (ExoJob *job);
-gboolean exo_job_is_cancelled (const ExoJob *job);
-GCancellable *exo_job_get_cancellable (const ExoJob *job);
-gboolean exo_job_set_error_if_cancelled (ExoJob *job,
- GError **error);
-void exo_job_emit (ExoJob *job,
- guint signal_id,
- GQuark signal_detail,
+ExoJob *exo_job_launch (ExoJob *job);
+void exo_job_cancel (ExoJob *job);
+gboolean exo_job_is_cancelled (const ExoJob *job);
+GCancellable *exo_job_get_cancellable (const ExoJob *job);
+gboolean exo_job_set_error_if_cancelled (ExoJob *job,
+ GError **error);
+void exo_job_emit (ExoJob *job,
+ guint signal_id,
+ GQuark signal_detail,
...);
-void exo_job_info_message (ExoJob *job,
- const gchar *format,
+void exo_job_info_message (ExoJob *job,
+ const gchar *format,
...);
-void exo_job_percent (ExoJob *job,
- gdouble percent);
+void exo_job_percent (ExoJob *job,
+ gdouble percent);
+gboolean exo_job_send_to_mainloop (ExoJob *job,
+ GSourceFunc func,
+ gpointer user_data,
+ GDestroyNotify destroy_notify);
G_END_DECLS
diff --git a/lib/exo-simple-job.c b/lib/exo-simple-job.c
index b15f4fa..74e86d4 100644
--- a/lib/exo-simple-job.c
+++ b/lib/exo-simple-job.c
@@ -38,9 +38,21 @@
#include "exo-job.h"
#include "exo-simple-job.h"
+/**
+ * SECTION: exo-simple-job
+ * @title: ExoSimpleJob
+ * @short_description: Simple interface to execute functions asynchronously
+ * @include: exo/exo.h
+ * @see_also: <link linkend="ExoJob">ExoJob</link>
+ *
+ * <link linkend="ExoSimpleJob">ExoSimpleJob</link> can be used to execute
+ * functions asynchronously in an #ExoJob wrapper object. It is easier to
+ * use than the #GThread system and provides basic signals to follow the
+ * progress of an operation.
+ **/
+
-static void exo_simple_job_class_init (ExoSimpleJobClass *klass);
static void exo_simple_job_finalize (GObject *object);
static gboolean exo_simple_job_execute (ExoJob *job,
GError **error);
@@ -52,48 +64,30 @@ struct _ExoSimpleJobClass
ExoJobClass __parent__;
};
+/**
+ * ExoSimpleJob:
+ *
+ * The #ExoSimpleJob struct contains only private fields and should not be
+ * directly accessed.
+ **/
struct _ExoSimpleJob
{
- ExoJob __parent__;
ExoSimpleJobFunc func;
GValueArray *param_values;
+ ExoJob __parent__;
};
-static GObjectClass *exo_simple_job_parent_class;
-
-
-
-GType
-exo_simple_job_get_type (void)
-{
- static GType type = G_TYPE_INVALID;
-
- if (G_UNLIKELY (type == G_TYPE_INVALID))
- {
- type = g_type_register_static_simple (EXO_TYPE_JOB,
- "ExoSimpleJob",
- sizeof (ExoSimpleJobClass),
- (GClassInitFunc) exo_simple_job_class_init,
- sizeof (ExoSimpleJob),
- NULL,
- 0);
- }
-
- return type;
-}
+G_DEFINE_TYPE (ExoSimpleJob, exo_simple_job, EXO_TYPE_JOB)
static void
exo_simple_job_class_init (ExoSimpleJobClass *klass)
{
- ExoJobClass *exojob_class;
- GObjectClass *gobject_class;
-
- /* determine the parent type class */
- exo_simple_job_parent_class = g_type_class_peek_parent (klass);
+ ExoJobClass *exojob_class;
+ GObjectClass *gobject_class;
gobject_class = G_OBJECT_CLASS (klass);
gobject_class->finalize = exo_simple_job_finalize;
@@ -105,6 +99,13 @@ exo_simple_job_class_init (ExoSimpleJobClass *klass)
static void
+exo_simple_job_init (ExoSimpleJob *simple_job)
+{
+}
+
+
+
+static void
exo_simple_job_finalize (GObject *object)
{
ExoSimpleJob *simple_job = EXO_SIMPLE_JOB (object);
@@ -168,13 +169,73 @@ exo_simple_job_execute (ExoJob *job,
* An example could be:
*
* <informalexample><programlisting>
- * exo_simple_job_launch (list_directory_job, 1, G_TYPE_FILE, file);
+ * static gboolean
+ * list_directory (ExoJob *job,
+ * GValueArray *param_values,
+ * GError **error)
+ * {
+ * GFileEnumerator *enumerator;
+ * GFileInfo *info;
+ * GError *err = NULL;
+ * GFile *directory;
+ *
+ * if (exo_job_set_error_if_cancelled (EXO_JOB (job), error))
+ * return FALSE;
+ *
+ * directory = g_value_get_object (g_value_array_get_nth (param_values, 0));
+ *
+ * enumerator = g_file_enumerate_children (directory,
+ * "standard::display-name",
+ * G_FILE_QUERY_INFO_NONE,
+ * exo_job_get_cancellable (job),
+ * &err);
+ *
+ * if (err != NULL)
+ * {
+ * g_propagate_error (error, err);
+ * return FALSE;
+ * }
+ *
+ * while (TRUE)
+ * {
+ * info = g_file_enumerator_next_file (enumerator,
+ * exo_job_get_cancellable (job),
+ * &err);
+ *
+ * if (info == NULL)
+ * break;
+ *
+ * exo_job_info_message (job, _("Child: %s"),
+ * g_file_info_get_display_name (info));
+ *
+ * g_object_unref (info);
+ * }
+ *
+ * g_object_unref (enumerator);
+ *
+ * if (err != NULL)
+ * {
+ * g_propagate_error (error, err);
+ * return FALSE;
+ * }
+ * else
+ * {
+ * return TRUE;
+ * }
+ * }
+ *
+ * ...
+ *
+ * GFile *file = g_file_new_for_path ("/home/user");
+ * ExoJob *job = exo_simple_job_launch (list_directory, 1, G_TYPE_FILE, file);
+ * g_signal_connect (job, "info-message", G_CALLBACK (update_some_widget), widget);
+ * g_signal_connect (job, "finished", G_CALLBACK (unref_the_job_object), NULL);
* </programlisting></informalexample>
*
- * The caller is responsible to release the returned object using
- * g_object_unref() when no longer needed.
+ * The caller is responsible to release the returned #ExoJob object
+ * using g_object_unref() when no longer needed.
*
- * Return value: the launched #ExoJob.
+ * Returns: the launched #ExoJob.
**/
ExoJob*
exo_simple_job_launch (ExoSimpleJobFunc func,
@@ -217,3 +278,4 @@ exo_simple_job_launch (ExoSimpleJobFunc func,
/* launch the job */
return exo_job_launch (EXO_JOB (simple_job));
}
+
diff --git a/lib/exo-simple-job.h b/lib/exo-simple-job.h
index c27c5e6..6aae796 100644
--- a/lib/exo-simple-job.h
+++ b/lib/exo-simple-job.h
@@ -35,7 +35,7 @@ G_BEGIN_DECLS
* Used by the #ExoSimpleJob to process the @job. See exo_simple_job_launch()
* for further details.
*
- * Return value: %TRUE on success, %FALSE in case of an error.
+ * Returns: %TRUE on success, %FALSE in case of an error.
**/
typedef gboolean (*ExoSimpleJobFunc) (ExoJob *job,
GValueArray *param_values,
More information about the Xfce4-commits
mailing list