[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