[latexila/wip/build-tools] Build tools: handle correctly several build views



commit 8d6ce2bb2f6ceeae56ff0065d984cead464f8b40
Author: Sébastien Wilmet <swilmet gnome org>
Date:   Mon Oct 6 15:38:40 2014 +0200

    Build tools: handle correctly several build views
    
    There can be several main windows, each with a build view.
    Before, at most one task was supported per BuildTool and BuildJob, but
    it doesn't work well with several build views (showing/hiding the
    details worked only for the last task).
    
    Now GTask is used more correctly, so a BuildTool and a BuildJob support
    several tasks.

 docs/reference/latexila-sections.txt  |    3 +-
 src/liblatexila/latexila-build-job.c  |  302 +++++++++++++++++---------------
 src/liblatexila/latexila-build-job.h  |    2 -
 src/liblatexila/latexila-build-tool.c |  265 ++++++++++++++++-------------
 src/liblatexila/latexila-build-tool.h |    2 -
 src/main_window_build_tools.vala      |    9 +-
 6 files changed, 310 insertions(+), 273 deletions(-)
---
diff --git a/docs/reference/latexila-sections.txt b/docs/reference/latexila-sections.txt
index c76bee2..fa84048 100644
--- a/docs/reference/latexila-sections.txt
+++ b/docs/reference/latexila-sections.txt
@@ -69,7 +69,6 @@ latexila_build_tool_get_description
 latexila_build_tool_to_xml
 latexila_build_tool_run_async
 latexila_build_tool_run_finish
-latexila_build_tool_clear
 <SUBSECTION Standard>
 LATEXILA_BUILD_TOOL
 LATEXILA_BUILD_TOOL_CLASS
@@ -91,7 +90,6 @@ latexila_build_job_clone
 latexila_build_job_to_xml
 latexila_build_job_run_async
 latexila_build_job_run_finish
-latexila_build_job_clear
 <SUBSECTION Standard>
 LATEXILA_BUILD_JOB
 LATEXILA_BUILD_JOB_CLASS
@@ -182,6 +180,7 @@ latexila_post_processor_all_output_get_type
 <TITLE>LatexilaPostProcessorLatex</TITLE>
 LatexilaPostProcessorLatex
 latexila_post_processor_latex_new
+latexila_post_processor_latex_get_errors_count
 <SUBSECTION Standard>
 LATEXILA_IS_POST_PROCESSOR_LATEX
 LATEXILA_IS_POST_PROCESSOR_LATEX_CLASS
diff --git a/src/liblatexila/latexila-build-job.c b/src/liblatexila/latexila-build-job.c
index 8daa601..0a9e314 100644
--- a/src/liblatexila/latexila-build-job.c
+++ b/src/liblatexila/latexila-build-job.c
@@ -39,9 +39,13 @@ struct _LatexilaBuildJobPrivate
 {
   gchar *command;
   LatexilaPostProcessorType post_processor_type;
+  guint running_tasks_count;
+};
 
-  /* Used for running the build job. */
-  GTask *task;
+/* Used for running the build job. */
+typedef struct _TaskData TaskData;
+struct _TaskData
+{
   GFile *file;
   LatexilaBuildView *build_view;
   GtkTreeIter job_title;
@@ -66,6 +70,26 @@ enum
 
 G_DEFINE_TYPE_WITH_PRIVATE (LatexilaBuildJob, latexila_build_job, G_TYPE_OBJECT)
 
+static TaskData *
+task_data_new (void)
+{
+  return g_slice_new0 (TaskData);
+}
+
+static void
+task_data_free (TaskData *data)
+{
+  if (data != NULL)
+    {
+      g_clear_object (&data->file);
+      g_clear_object (&data->build_view);
+      g_clear_object (&data->post_processor);
+      g_clear_object (&data->post_processor_result);
+
+      g_slice_free (TaskData, data);
+    }
+}
+
 static void
 latexila_build_job_get_property (GObject    *object,
                                  guint       prop_id,
@@ -99,7 +123,7 @@ latexila_build_job_set_property (GObject      *object,
   LatexilaBuildJob *build_job = LATEXILA_BUILD_JOB (object);
 
   /* The build job can not be modified when it is running. */
-  g_return_if_fail (build_job->priv->task == NULL);
+  g_return_if_fail (build_job->priv->running_tasks_count == 0);
 
   switch (prop_id)
     {
@@ -119,19 +143,6 @@ latexila_build_job_set_property (GObject      *object,
 }
 
 static void
-latexila_build_job_dispose (GObject *object)
-{
-  LatexilaBuildJob *build_job = LATEXILA_BUILD_JOB (object);
-
-  g_clear_object (&build_job->priv->task);
-  g_clear_object (&build_job->priv->file);
-
-  latexila_build_job_clear (build_job);
-
-  G_OBJECT_CLASS (latexila_build_job_parent_class)->dispose (object);
-}
-
-static void
 latexila_build_job_finalize (GObject *object)
 {
   LatexilaBuildJob *build_job = LATEXILA_BUILD_JOB (object);
@@ -148,7 +159,6 @@ latexila_build_job_class_init (LatexilaBuildJobClass *klass)
 
   object_class->get_property = latexila_build_job_get_property;
   object_class->set_property = latexila_build_job_set_property;
-  object_class->dispose = latexila_build_job_dispose;
   object_class->finalize = latexila_build_job_finalize;
 
   g_object_class_install_property (object_class,
@@ -174,9 +184,9 @@ latexila_build_job_class_init (LatexilaBuildJobClass *klass)
 }
 
 static void
-latexila_build_job_init (LatexilaBuildJob *self)
+latexila_build_job_init (LatexilaBuildJob *build_job)
 {
-  self->priv = latexila_build_job_get_instance_private (self);
+  build_job->priv = latexila_build_job_get_instance_private (build_job);
 }
 
 /**
@@ -226,10 +236,12 @@ latexila_build_job_to_xml (LatexilaBuildJob *build_job)
 }
 
 static gchar **
-get_command_argv (LatexilaBuildJob  *build_job,
-                  gboolean           for_printing,
-                  GError           **error)
+get_command_argv (GTask     *task,
+                  gboolean   for_printing,
+                  GError   **error)
 {
+  LatexilaBuildJob *build_job = g_task_get_source_object (task);
+  TaskData *data = g_task_get_task_data (task);
   gchar **argv;
   gchar *base_filename;
   gchar *base_shortname;
@@ -256,7 +268,7 @@ get_command_argv (LatexilaBuildJob  *build_job,
     }
 
   /* Replace placeholders */
-  base_filename = g_file_get_basename (build_job->priv->file);
+  base_filename = g_file_get_basename (data->file);
   base_shortname = latexila_utils_get_shortname (base_filename);
 
   for (i = 0; argv[i] != NULL; i++)
@@ -290,12 +302,12 @@ get_command_argv (LatexilaBuildJob  *build_job,
 }
 
 static gchar *
-get_command_name (LatexilaBuildJob *build_job)
+get_command_name (GTask *task)
 {
   gchar **argv;
   gchar *command_name;
 
-  argv = get_command_argv (build_job, TRUE, NULL);
+  argv = get_command_argv (task, TRUE, NULL);
 
   if (argv == NULL || argv[0] == NULL || argv[0][0] == '\0')
     command_name = NULL;
@@ -307,29 +319,30 @@ get_command_name (LatexilaBuildJob *build_job)
 }
 
 static void
-display_error (LatexilaBuildJob *build_job,
-               const gchar      *message,
-               GError           *error)
+display_error (GTask       *task,
+               const gchar *message,
+               GError      *error)
 {
+  TaskData *data = g_task_get_task_data (task);
   LatexilaBuildMsg *build_msg;
 
   g_assert (error != NULL);
 
-  latexila_build_view_set_title_state (build_job->priv->build_view,
-                                       &build_job->priv->job_title,
+  latexila_build_view_set_title_state (data->build_view,
+                                       &data->job_title,
                                        LATEXILA_BUILD_STATE_FAILED);
 
   build_msg = latexila_build_msg_new ();
   build_msg->text = (gchar *) message;
   build_msg->type = LATEXILA_BUILD_MSG_TYPE_ERROR;
-  latexila_build_view_append_single_message (build_job->priv->build_view,
-                                             &build_job->priv->job_title,
+  latexila_build_view_append_single_message (data->build_view,
+                                             &data->job_title,
                                              build_msg);
 
   build_msg->text = g_strdup (error->message);
   build_msg->type = LATEXILA_BUILD_MSG_TYPE_INFO;
-  latexila_build_view_append_single_message (build_job->priv->build_view,
-                                             &build_job->priv->job_title,
+  latexila_build_view_append_single_message (data->build_view,
+                                             &data->job_title,
                                              build_msg);
 
   /* If the command doesn't seem to be installed, display a more understandable
@@ -338,15 +351,15 @@ display_error (LatexilaBuildJob *build_job,
   if (error->domain == G_SPAWN_ERROR &&
       error->code == G_SPAWN_ERROR_NOENT)
     {
-      gchar *command_name = get_command_name (build_job);
+      gchar *command_name = get_command_name (task);
 
       if (command_name != NULL)
         {
           g_free (build_msg->text);
           build_msg->text = g_strdup_printf (_("%s doesn't seem to be installed."), command_name);
 
-          latexila_build_view_append_single_message (build_job->priv->build_view,
-                                                     &build_job->priv->job_title,
+          latexila_build_view_append_single_message (data->build_view,
+                                                     &data->job_title,
                                                      build_msg);
 
           g_free (command_name);
@@ -355,34 +368,37 @@ display_error (LatexilaBuildJob *build_job,
 
   g_error_free (error);
   latexila_build_msg_free (build_msg);
-  g_task_return_boolean (build_job->priv->task, FALSE);
+  g_task_return_boolean (task, FALSE);
+  g_object_unref (task);
 }
 
 /* Returns TRUE on success. */
 static gboolean
-display_command_line (LatexilaBuildJob *build_job)
+display_command_line (GTask *task)
 {
+  LatexilaBuildJob *build_job = g_task_get_source_object (task);
+  TaskData *data = g_task_get_task_data (task);
   gchar **argv;
   gchar *command_line;
   GError *error = NULL;
 
-  argv = get_command_argv (build_job, TRUE, &error);
+  argv = get_command_argv (task, TRUE, &error);
 
   if (error != NULL)
     {
-      build_job->priv->job_title = latexila_build_view_add_job_title (build_job->priv->build_view,
-                                                                      build_job->priv->command,
-                                                                      LATEXILA_BUILD_STATE_FAILED);
+      data->job_title = latexila_build_view_add_job_title (data->build_view,
+                                                           build_job->priv->command,
+                                                           LATEXILA_BUILD_STATE_FAILED);
 
-      display_error (build_job, "Failed to parse command line:", error);
+      display_error (task, "Failed to parse command line:", error);
       return FALSE;
     }
 
   command_line = g_strjoinv (" ", argv);
 
-  build_job->priv->job_title = latexila_build_view_add_job_title (build_job->priv->build_view,
-                                                                  command_line,
-                                                                  LATEXILA_BUILD_STATE_RUNNING);
+  data->job_title = latexila_build_view_add_job_title (data->build_view,
+                                                       command_line,
+                                                       LATEXILA_BUILD_STATE_RUNNING);
 
   g_strfreev (argv);
   g_free (command_line);
@@ -392,97 +408,102 @@ display_command_line (LatexilaBuildJob *build_job)
 static void
 show_details_notify_cb (LatexilaBuildView *build_view,
                         GParamSpec        *pspec,
-                        LatexilaBuildJob  *build_job)
+                        GTask             *task)
 {
+  TaskData *data = g_task_get_task_data (task);
   const GList *messages;
   gboolean show_details;
 
-  latexila_build_view_remove_children (build_view,
-                                       &build_job->priv->job_title);
+  latexila_build_view_remove_children (build_view, &data->job_title);
 
   g_object_get (build_view, "show-details", &show_details, NULL);
 
-  messages = latexila_post_processor_get_messages (build_job->priv->post_processor,
+  messages = latexila_post_processor_get_messages (data->post_processor,
                                                    show_details);
 
   latexila_build_view_append_messages (build_view,
-                                       &build_job->priv->job_title,
+                                       &data->job_title,
                                        messages,
                                        TRUE);
 }
 
 static void
-finish_post_processor (LatexilaBuildJob *build_job)
+finish_post_processor (GTask *task)
 {
+  TaskData *data = g_task_get_task_data (task);
   gboolean has_details;
 
-  g_assert (build_job->priv->succeeded_set);
-  g_assert (build_job->priv->post_processor_result != NULL);
+  g_assert (data->succeeded_set);
+  g_assert (data->post_processor_result != NULL);
 
-  latexila_post_processor_process_finish (build_job->priv->post_processor,
-                                          build_job->priv->post_processor_result,
-                                          build_job->priv->succeeded);
+  latexila_post_processor_process_finish (data->post_processor,
+                                          data->post_processor_result,
+                                          data->succeeded);
 
-  g_clear_object (&build_job->priv->post_processor_result);
+  g_clear_object (&data->post_processor_result);
 
-  g_object_get (build_job->priv->post_processor,
+  g_object_get (data->post_processor,
                 "has-details", &has_details,
                 NULL);
 
   if (has_details)
-    g_object_set (build_job->priv->build_view,
+    g_object_set (data->build_view,
                   "has-details", TRUE,
                   NULL);
 
-  g_signal_connect (build_job->priv->build_view,
-                    "notify::show-details",
-                    G_CALLBACK (show_details_notify_cb),
-                    build_job);
+  g_signal_connect_object (data->build_view,
+                           "notify::show-details",
+                           G_CALLBACK (show_details_notify_cb),
+                           task,
+                           0);
 
-  show_details_notify_cb (build_job->priv->build_view,
-                          NULL,
-                          build_job);
+  show_details_notify_cb (data->build_view, NULL, task);
 }
 
 static void
 post_processor_cb (LatexilaPostProcessor *pp,
                    GAsyncResult          *result,
-                   LatexilaBuildJob      *build_job)
+                   GTask                 *task)
 {
-  if (build_job->priv->post_processor_result != NULL)
+  TaskData *data = g_task_get_task_data (task);
+
+  if (data->post_processor_result != NULL)
     {
       g_warning ("BuildJob: got two post-processor results.");
-      g_object_unref (build_job->priv->post_processor_result);
+      g_object_unref (data->post_processor_result);
     }
 
-  build_job->priv->post_processor_result = g_object_ref (result);
+  data->post_processor_result = g_object_ref (result);
 
-  if (build_job->priv->succeeded_set)
-    finish_post_processor (build_job);
+  if (data->succeeded_set)
+    finish_post_processor (task);
+
+  g_object_unref (task);
 }
 
 static void
-subprocess_wait_cb (GSubprocess      *subprocess,
-                    GAsyncResult     *result,
-                    LatexilaBuildJob *build_job)
+subprocess_wait_cb (GSubprocess  *subprocess,
+                    GAsyncResult *result,
+                    GTask        *task)
 {
+  TaskData *data = g_task_get_task_data (task);
   gboolean ret;
   LatexilaBuildState state;
 
   ret = g_subprocess_wait_finish (subprocess, result, NULL);
 
-  if (build_job->priv->succeeded_set)
+  if (data->succeeded_set)
     g_warning ("BuildJob: subprocess finished two times.");
 
-  build_job->priv->succeeded = g_subprocess_get_successful (subprocess);
-  build_job->priv->succeeded_set = TRUE;
+  data->succeeded = g_subprocess_get_successful (subprocess);
+  data->succeeded_set = TRUE;
 
   if (!ret)
     {
       state = LATEXILA_BUILD_STATE_ABORTED;
       g_subprocess_force_exit (subprocess);
     }
-  else if (build_job->priv->succeeded)
+  else if (data->succeeded)
     {
       state = LATEXILA_BUILD_STATE_SUCCEEDED;
     }
@@ -492,20 +513,24 @@ subprocess_wait_cb (GSubprocess      *subprocess,
       state = LATEXILA_BUILD_STATE_FAILED;
     }
 
-  latexila_build_view_set_title_state (build_job->priv->build_view,
-                                       &build_job->priv->job_title,
+  latexila_build_view_set_title_state (data->build_view,
+                                       &data->job_title,
                                        state);
 
-  g_task_return_boolean (build_job->priv->task, ret);
-  g_object_unref (subprocess);
+  g_task_return_boolean (task, ret);
+
+  if (data->post_processor_result != NULL)
+    finish_post_processor (task);
 
-  if (build_job->priv->post_processor_result != NULL)
-    finish_post_processor (build_job);
+  g_object_unref (subprocess);
+  g_object_unref (task);
 }
 
 static void
-launch_subprocess (LatexilaBuildJob *build_job)
+launch_subprocess (GTask *task)
 {
+  LatexilaBuildJob *build_job = g_task_get_source_object (task);
+  TaskData *data = g_task_get_task_data (task);
   GSubprocessLauncher *launcher;
   GSubprocess *subprocess;
   GFile *parent_dir;
@@ -520,7 +545,7 @@ launch_subprocess (LatexilaBuildJob *build_job)
     launcher = g_subprocess_launcher_new (G_SUBPROCESS_FLAGS_STDOUT_PIPE |
                                           G_SUBPROCESS_FLAGS_STDERR_MERGE);
 
-  parent_dir = g_file_get_parent (build_job->priv->file);
+  parent_dir = g_file_get_parent (data->file);
   working_directory = g_file_get_path (parent_dir);
   g_object_unref (parent_dir);
 
@@ -528,7 +553,7 @@ launch_subprocess (LatexilaBuildJob *build_job)
   g_free (working_directory);
 
   /* The error is already catched in display_command_line(). */
-  argv = get_command_argv (build_job, FALSE, NULL);
+  argv = get_command_argv (task, FALSE, NULL);
 
   subprocess = g_subprocess_launcher_spawnv (launcher, (const gchar * const *) argv, &error);
   g_strfreev (argv);
@@ -536,11 +561,11 @@ launch_subprocess (LatexilaBuildJob *build_job)
 
   if (error != NULL)
     {
-      display_error (build_job, "Failed to launch command:", error);
+      display_error (task, "Failed to launch command:", error);
       return;
     }
 
-  g_clear_object (&build_job->priv->post_processor);
+  g_clear_object (&data->post_processor);
 
   switch (build_job->priv->post_processor_type)
     {
@@ -548,33 +573,37 @@ launch_subprocess (LatexilaBuildJob *build_job)
       break;
 
     case LATEXILA_POST_PROCESSOR_TYPE_ALL_OUTPUT:
-      build_job->priv->post_processor = latexila_post_processor_all_output_new ();
+      data->post_processor = latexila_post_processor_all_output_new ();
       break;
 
     case LATEXILA_POST_PROCESSOR_TYPE_LATEX:
-      build_job->priv->post_processor = latexila_post_processor_latex_new ();
+      data->post_processor = latexila_post_processor_latex_new ();
       break;
 
     case LATEXILA_POST_PROCESSOR_TYPE_LATEXMK:
-      build_job->priv->post_processor = latexila_post_processor_latexmk_new ();
+      data->post_processor = latexila_post_processor_latexmk_new ();
       break;
 
     default:
       g_return_if_reached ();
     }
 
-  if (build_job->priv->post_processor != NULL)
-    latexila_post_processor_process_async (build_job->priv->post_processor,
-                                           build_job->priv->file,
-                                           g_subprocess_get_stdout_pipe (subprocess),
-                                           g_task_get_cancellable (build_job->priv->task),
-                                           (GAsyncReadyCallback) post_processor_cb,
-                                           build_job);
+  if (data->post_processor != NULL)
+    {
+      g_object_ref (task);
+
+      latexila_post_processor_process_async (data->post_processor,
+                                             data->file,
+                                             g_subprocess_get_stdout_pipe (subprocess),
+                                             g_task_get_cancellable (task),
+                                             (GAsyncReadyCallback) post_processor_cb,
+                                             task);
+    }
 
   g_subprocess_wait_async (subprocess,
-                           g_task_get_cancellable (build_job->priv->task),
+                           g_task_get_cancellable (task),
                            (GAsyncReadyCallback) subprocess_wait_cb,
-                           build_job);
+                           task);
 }
 
 /**
@@ -598,25 +627,29 @@ latexila_build_job_run_async (LatexilaBuildJob    *build_job,
                               GAsyncReadyCallback  callback,
                               gpointer             user_data)
 {
+  GTask *task;
+  TaskData *data;
+
   g_return_if_fail (LATEXILA_IS_BUILD_JOB (build_job));
   g_return_if_fail (G_IS_FILE (file));
   g_return_if_fail (LATEXILA_IS_BUILD_VIEW (build_view));
-  g_return_if_fail (build_job->priv->task == NULL);
-
-  build_job->priv->task = g_task_new (build_job, cancellable, callback, user_data);
 
-  g_clear_object (&build_job->priv->file);
-  build_job->priv->file = g_object_ref (file);
+  task = g_task_new (build_job, cancellable, callback, user_data);
+  build_job->priv->running_tasks_count++;
 
-  latexila_build_job_clear (build_job);
+  data = task_data_new ();
+  g_task_set_task_data (task, data, (GDestroyNotify) task_data_free);
 
-  build_job->priv->build_view = g_object_ref (build_view);
+  data->file = g_object_ref (file);
+  data->build_view = g_object_ref (build_view);
 
-  if (!display_command_line (build_job))
+  if (!display_command_line (task))
     return;
 
-  if (!g_task_return_error_if_cancelled (build_job->priv->task))
-    launch_subprocess (build_job);
+  if (g_task_return_error_if_cancelled (task))
+    g_object_unref (task);
+  else
+    launch_subprocess (task);
 }
 
 /**
@@ -626,53 +659,38 @@ latexila_build_job_run_async (LatexilaBuildJob    *build_job,
  *
  * Finishes the operation started with latexila_build_job_run_async().
  *
+ * Before calling this function, you should keep a reference to @result as long
+ * as the build messages are displayed in the build view.
+ *
  * Returns: %TRUE if the build job has run successfully.
  */
 gboolean
 latexila_build_job_run_finish (LatexilaBuildJob *build_job,
                                GAsyncResult     *result)
 {
+  GTask *task;
+  TaskData *data;
   GCancellable *cancellable;
   gboolean succeed;
 
   g_return_if_fail (g_task_is_valid (result, build_job));
 
-  cancellable = g_task_get_cancellable (G_TASK (result));
+  task = G_TASK (result);
+  data = g_task_get_task_data (task);
+
+  cancellable = g_task_get_cancellable (task);
   if (g_cancellable_is_cancelled (cancellable))
     {
-      latexila_build_view_set_title_state (build_job->priv->build_view,
-                                           &build_job->priv->job_title,
+      latexila_build_view_set_title_state (data->build_view,
+                                           &data->job_title,
                                            LATEXILA_BUILD_STATE_ABORTED);
       succeed = FALSE;
     }
   else
     {
-      succeed = g_task_propagate_boolean (G_TASK (result), NULL);
+      succeed = g_task_propagate_boolean (task, NULL);
     }
 
-  g_clear_object (&build_job->priv->task);
-  g_clear_object (&build_job->priv->file);
-
+  build_job->priv->running_tasks_count--;
   return succeed;
 }
-
-/**
- * latexila_build_job_clear:
- * @build_job: a build job.
- *
- * Clears the last run operation. latexila_build_job_run_finish() must have been
- * called before calling this function.
- */
-void
-latexila_build_job_clear (LatexilaBuildJob *build_job)
-{
-  if (build_job->priv->build_view != NULL)
-    g_signal_handlers_disconnect_by_func (build_job->priv->build_view,
-                                          show_details_notify_cb,
-                                          build_job);
-
-  g_clear_object (&build_job->priv->build_view);
-  g_clear_object (&build_job->priv->post_processor);
-  g_clear_object (&build_job->priv->post_processor_result);
-  build_job->priv->succeeded_set = FALSE;
-}
diff --git a/src/liblatexila/latexila-build-job.h b/src/liblatexila/latexila-build-job.h
index bff5294..f4bef9b 100644
--- a/src/liblatexila/latexila-build-job.h
+++ b/src/liblatexila/latexila-build-job.h
@@ -66,8 +66,6 @@ void                latexila_build_job_run_async                  (LatexilaBuild
 gboolean            latexila_build_job_run_finish                 (LatexilaBuildJob *build_job,
                                                                    GAsyncResult     *result);
 
-void                latexila_build_job_clear                      (LatexilaBuildJob *build_job);
-
 G_END_DECLS
 
 #endif /* __LATEXILA_BUILD_JOB_H__ */
diff --git a/src/liblatexila/latexila-build-tool.c b/src/liblatexila/latexila-build-tool.c
index 892fcc3..5bcc903 100644
--- a/src/liblatexila/latexila-build-tool.c
+++ b/src/liblatexila/latexila-build-tool.c
@@ -42,23 +42,34 @@ struct _LatexilaBuildToolPrivate
   gchar *extensions;
   gchar *icon;
   gchar *files_to_open;
+  gchar **files_to_open_split;
   gint id;
 
   /* A list of LatexilaBuildJob's. */
   GQueue *jobs;
 
-  /* Used for running the build tool. */
-  GTask *task;
+  guint running_tasks_count;
+
+  guint enabled : 1;
+};
+
+/* Used for running the build tool. */
+typedef struct _TaskData TaskData;
+struct _TaskData
+{
   GFile *file;
   LatexilaBuildView *build_view;
   GtkTreeIter main_title;
+
+  /* Position in priv->jobs. */
   GList *current_job;
 
-  gchar **files_to_open_split;
-  gchar **current_file_to_open; /* Position in files_to_open_split */
+  /* Position in priv->files_to_open_split. */
+  gchar **current_file_to_open;
+
   GtkTreeIter open_file_job_title;
 
-  guint enabled : 1;
+  GSList *job_results;
 };
 
 enum
@@ -76,8 +87,27 @@ enum
 G_DEFINE_TYPE_WITH_PRIVATE (LatexilaBuildTool, latexila_build_tool, G_TYPE_OBJECT)
 
 /* Prototypes */
-static void run_job (LatexilaBuildTool *build_tool);
-static void open_file (LatexilaBuildTool *build_tool);
+static void run_job (GTask *task);
+static void open_file (GTask *task);
+
+static TaskData *
+task_data_new (void)
+{
+  return g_slice_new0 (TaskData);
+}
+
+static void
+task_data_free (TaskData *data)
+{
+  if (data != NULL)
+    {
+      g_clear_object (&data->file);
+      g_clear_object (&data->build_view);
+      g_slist_free_full (data->job_results, g_object_unref);
+
+      g_slice_free (TaskData, data);
+    }
+}
 
 static void
 latexila_build_tool_get_property (GObject    *object,
@@ -132,7 +162,7 @@ latexila_build_tool_set_property (GObject      *object,
   LatexilaBuildTool *build_tool = LATEXILA_BUILD_TOOL (object);
 
   /* The build tool can not be modified when it is running. */
-  g_return_if_fail (build_tool->priv->task == NULL);
+  g_return_if_fail (build_tool->priv->running_tasks_count == 0);
 
   switch (prop_id)
     {
@@ -191,10 +221,6 @@ latexila_build_tool_dispose (GObject *object)
       build_tool->priv->jobs = NULL;
     }
 
-  g_clear_object (&build_tool->priv->task);
-  g_clear_object (&build_tool->priv->file);
-  g_clear_object (&build_tool->priv->build_view);
-
   G_OBJECT_CLASS (latexila_build_tool_parent_class)->dispose (object);
 }
 
@@ -392,7 +418,7 @@ latexila_build_tool_add_job (LatexilaBuildTool *build_tool,
   g_return_if_fail (LATEXILA_IS_BUILD_JOB (build_job));
 
   /* The build tool can not be modified when it is running. */
-  g_return_if_fail (build_tool->priv->task == NULL);
+  g_return_if_fail (build_tool->priv->running_tasks_count == 0);
 
   g_queue_push_tail (build_tool->priv->jobs, build_job);
   g_object_ref (build_job);
@@ -464,29 +490,32 @@ latexila_build_tool_to_xml (LatexilaBuildTool *tool)
 }
 
 static void
-failed (LatexilaBuildTool *build_tool)
+failed (GTask *task)
 {
+  TaskData *data = g_task_get_task_data (task);
   GCancellable *cancellable;
   LatexilaBuildState state;
 
-  cancellable = g_task_get_cancellable (build_tool->priv->task);
+  cancellable = g_task_get_cancellable (task);
   if (g_cancellable_is_cancelled (cancellable))
     state = LATEXILA_BUILD_STATE_ABORTED;
   else
     state = LATEXILA_BUILD_STATE_FAILED;
 
-  latexila_build_view_set_title_state (build_tool->priv->build_view,
-                                       &build_tool->priv->main_title,
+  latexila_build_view_set_title_state (data->build_view,
+                                       &data->main_title,
                                        state);
 
-  g_task_return_boolean (build_tool->priv->task, FALSE);
+  g_task_return_boolean (task, FALSE);
+  g_object_unref (task);
 }
 
 static void
-query_exists_cb (GFile             *file,
-                 GAsyncResult      *result,
-                 LatexilaBuildTool *build_tool)
+query_exists_cb (GFile        *file,
+                 GAsyncResult *result,
+                 GTask        *task)
 {
+  TaskData *data = g_task_get_task_data (task);
   gboolean file_exists;
   GCancellable *cancellable;
   gchar *uri = NULL;
@@ -494,13 +523,13 @@ query_exists_cb (GFile             *file,
 
   file_exists = latexila_utils_file_query_exists_finish (file, result);
 
-  cancellable = g_task_get_cancellable (build_tool->priv->task);
+  cancellable = g_task_get_cancellable (task);
   if (g_cancellable_is_cancelled (cancellable))
     {
-      latexila_build_view_set_title_state (build_tool->priv->build_view,
-                                           &build_tool->priv->open_file_job_title,
+      latexila_build_view_set_title_state (data->build_view,
+                                           &data->open_file_job_title,
                                            LATEXILA_BUILD_STATE_ABORTED);
-      failed (build_tool);
+      failed (task);
       goto out;
     }
 
@@ -510,26 +539,26 @@ query_exists_cb (GFile             *file,
     {
       LatexilaBuildMsg *msg;
 
-      latexila_build_view_set_title_state (build_tool->priv->build_view,
-                                           &build_tool->priv->open_file_job_title,
+      latexila_build_view_set_title_state (data->build_view,
+                                           &data->open_file_job_title,
                                            LATEXILA_BUILD_STATE_FAILED);
 
       msg = latexila_build_msg_new ();
       msg->text = g_strdup_printf (_("The file '%s' doesn't exist."), uri);
       msg->type = LATEXILA_BUILD_MSG_TYPE_ERROR;
 
-      latexila_build_view_append_single_message (build_tool->priv->build_view,
-                                                 &build_tool->priv->open_file_job_title,
+      latexila_build_view_append_single_message (data->build_view,
+                                                 &data->open_file_job_title,
                                                  msg);
 
       latexila_build_msg_free (msg);
-      failed (build_tool);
+      failed (task);
       goto out;
     }
 
   /* Show URI */
 
-  gtk_show_uri (gtk_widget_get_screen (GTK_WIDGET (build_tool->priv->build_view)),
+  gtk_show_uri (gtk_widget_get_screen (GTK_WIDGET (data->build_view)),
                 uri,
                 GDK_CURRENT_TIME,
                 &error);
@@ -538,39 +567,39 @@ query_exists_cb (GFile             *file,
     {
       LatexilaBuildMsg *msg;
 
-      latexila_build_view_set_title_state (build_tool->priv->build_view,
-                                           &build_tool->priv->open_file_job_title,
+      latexila_build_view_set_title_state (data->build_view,
+                                           &data->open_file_job_title,
                                            LATEXILA_BUILD_STATE_FAILED);
 
       msg = latexila_build_msg_new ();
       msg->text = g_strdup_printf (_("Failed to open '%s':"), uri);
       msg->type = LATEXILA_BUILD_MSG_TYPE_ERROR;
 
-      latexila_build_view_append_single_message (build_tool->priv->build_view,
-                                                 &build_tool->priv->open_file_job_title,
+      latexila_build_view_append_single_message (data->build_view,
+                                                 &data->open_file_job_title,
                                                  msg);
 
       g_free (msg->text);
       msg->text = g_strdup (error->message);
       msg->type = LATEXILA_BUILD_MSG_TYPE_INFO;
 
-      latexila_build_view_append_single_message (build_tool->priv->build_view,
-                                                 &build_tool->priv->open_file_job_title,
+      latexila_build_view_append_single_message (data->build_view,
+                                                 &data->open_file_job_title,
                                                  msg);
 
       latexila_build_msg_free (msg);
       g_error_free (error);
 
-      failed (build_tool);
+      failed (task);
       goto out;
     }
 
-  latexila_build_view_set_title_state (build_tool->priv->build_view,
-                                       &build_tool->priv->open_file_job_title,
+  latexila_build_view_set_title_state (data->build_view,
+                                       &data->open_file_job_title,
                                        LATEXILA_BUILD_STATE_SUCCEEDED);
 
-  build_tool->priv->current_file_to_open++;
-  open_file (build_tool);
+  data->current_file_to_open++;
+  open_file (task);
 
 out:
   g_object_unref (file);
@@ -578,8 +607,9 @@ out:
 }
 
 static void
-open_file (LatexilaBuildTool *build_tool)
+open_file (GTask *task)
 {
+  TaskData *data = g_task_get_task_data (task);
   const gchar *file_to_open;
   gchar *filename;
   gchar *shortname;
@@ -590,32 +620,33 @@ open_file (LatexilaBuildTool *build_tool)
 
   while (TRUE)
     {
-      if (build_tool->priv->current_file_to_open == NULL ||
-          build_tool->priv->current_file_to_open[0] == NULL)
+      if (data->current_file_to_open == NULL ||
+          data->current_file_to_open[0] == NULL)
         {
           /* Finished */
-          latexila_build_view_set_title_state (build_tool->priv->build_view,
-                                               &build_tool->priv->main_title,
+          latexila_build_view_set_title_state (data->build_view,
+                                               &data->main_title,
                                                LATEXILA_BUILD_STATE_SUCCEEDED);
 
-          g_task_return_boolean (build_tool->priv->task, TRUE);
+          g_task_return_boolean (task, TRUE);
+          g_object_unref (task);
           return;
         }
 
       /* Check if the file to open is an empty string. It happens if there are
        * two contiguous spaces in priv->files_to_open for example.
        */
-      if (build_tool->priv->current_file_to_open[0][0] == '\0')
-        build_tool->priv->current_file_to_open++;
+      if (data->current_file_to_open[0][0] == '\0')
+        data->current_file_to_open++;
       else
         break;
     }
 
-  file_to_open = build_tool->priv->current_file_to_open[0];
+  file_to_open = data->current_file_to_open[0];
 
   /* Replace placeholders */
 
-  filename = g_file_get_uri (build_tool->priv->file);
+  filename = g_file_get_uri (data->file);
   shortname = latexila_utils_get_shortname (filename);
 
   if (strstr (file_to_open, "$filename") != NULL)
@@ -630,18 +661,18 @@ open_file (LatexilaBuildTool *build_tool)
   basename = g_path_get_basename (uri);
   message = g_strdup_printf (_("Open %s"), basename);
 
-  build_tool->priv->open_file_job_title = latexila_build_view_add_job_title (build_tool->priv->build_view,
-                                                                             message,
-                                                                             LATEXILA_BUILD_STATE_RUNNING);
+  data->open_file_job_title = latexila_build_view_add_job_title (data->build_view,
+                                                                 message,
+                                                                 LATEXILA_BUILD_STATE_RUNNING);
 
   /* Check if the file exists */
 
   file = g_file_new_for_uri (uri);
 
   latexila_utils_file_query_exists_async (file,
-                                          g_task_get_cancellable (build_tool->priv->task),
+                                          g_task_get_cancellable (task),
                                           (GAsyncReadyCallback) query_exists_cb,
-                                          build_tool);
+                                          task);
 
   g_free (filename);
   g_free (shortname);
@@ -651,54 +682,65 @@ open_file (LatexilaBuildTool *build_tool)
 }
 
 static void
-open_files (LatexilaBuildTool *build_tool)
+open_files (GTask *task)
 {
-  build_tool->priv->current_file_to_open = build_tool->priv->files_to_open_split;
-  open_file (build_tool);
+  TaskData *data = g_task_get_task_data (task);
+  LatexilaBuildTool *build_tool = g_task_get_source_object (task);
+
+  data->current_file_to_open = build_tool->priv->files_to_open_split;
+  open_file (task);
 }
 
 static void
-run_job_cb (LatexilaBuildJob  *build_job,
-            GAsyncResult      *result,
-            LatexilaBuildTool *build_tool)
+run_job_cb (LatexilaBuildJob *build_job,
+            GAsyncResult     *result,
+            GTask            *task)
 {
+  TaskData *data = g_task_get_task_data (task);
   gboolean success;
 
+  data->job_results = g_slist_prepend (data->job_results,
+                                       g_object_ref (result));
+
   success = latexila_build_job_run_finish (build_job, result);
 
   if (success)
     {
-      build_tool->priv->current_job = build_tool->priv->current_job->next;
-      run_job (build_tool);
+      data->current_job = data->current_job->next;
+      run_job (task);
     }
   else
     {
-      failed (build_tool);
+      failed (task);
     }
 }
 
 static void
-run_job (LatexilaBuildTool *build_tool)
+run_job (GTask *task)
 {
+  TaskData *data = g_task_get_task_data (task);
   LatexilaBuildJob *build_job;
 
-  if (g_task_return_error_if_cancelled (build_tool->priv->task))
-    return;
+  if (g_task_return_error_if_cancelled (task))
+    {
+      g_object_unref (task);
+      return;
+    }
 
-  if (build_tool->priv->current_job == NULL)
+  if (data->current_job == NULL)
     {
-      open_files (build_tool);
+      open_files (task);
       return;
     }
 
-  build_job = build_tool->priv->current_job->data;
+  build_job = data->current_job->data;
 
   latexila_build_job_run_async (build_job,
-                                build_tool->priv->file,
-                                build_tool->priv->build_view,
-                                g_task_get_cancellable (build_tool->priv->task),
+                                data->file,
+                                data->build_view,
+                                g_task_get_cancellable (task),
                                 (GAsyncReadyCallback) run_job_cb,
-                                build_tool);
+                                task);
 }
 
 /**
@@ -720,27 +762,30 @@ latexila_build_tool_run_async (LatexilaBuildTool   *build_tool,
                                GAsyncReadyCallback  callback,
                                gpointer             user_data)
 {
+  GTask *task;
+  TaskData *data;
+
   g_return_if_fail (LATEXILA_IS_BUILD_TOOL (build_tool));
   g_return_if_fail (G_IS_FILE (file));
   g_return_if_fail (LATEXILA_IS_BUILD_VIEW (build_view));
-  g_return_if_fail (build_tool->priv->task == NULL);
 
-  build_tool->priv->task = g_task_new (build_tool, cancellable, callback, user_data);
+  task = g_task_new (build_tool, cancellable, callback, user_data);
+  build_tool->priv->running_tasks_count++;
 
-  g_clear_object (&build_tool->priv->file);
-  build_tool->priv->file = g_object_ref (file);
+  data = task_data_new ();
+  g_task_set_task_data (task, data, (GDestroyNotify) task_data_free);
 
-  g_clear_object (&build_tool->priv->build_view);
-  build_tool->priv->build_view = g_object_ref (build_view);
+  data->file = g_object_ref (file);
+  data->build_view = g_object_ref (build_view);
 
   latexila_build_view_clear (build_view);
 
-  build_tool->priv->main_title = latexila_build_view_add_main_title (build_view,
-                                                                     build_tool->priv->label,
-                                                                     LATEXILA_BUILD_STATE_RUNNING);
+  data->main_title = latexila_build_view_add_main_title (build_view,
+                                                         build_tool->priv->label,
+                                                         LATEXILA_BUILD_STATE_RUNNING);
 
-  build_tool->priv->current_job = build_tool->priv->jobs->head;
-  run_job (build_tool);
+  data->current_job = build_tool->priv->jobs->head;
+  run_job (task);
 }
 
 /**
@@ -749,48 +794,30 @@ latexila_build_tool_run_async (LatexilaBuildTool   *build_tool,
  * @result: a #GAsyncResult.
  *
  * Finishes the operation started with latexila_build_tool_run_async().
+ *
+ * Before calling this function you should keep a reference to @result as long
+ * as the build messages are displayed in the build view. @result is needed for
+ * example to show/hide some messages when the "More details" button is toggled.
  */
 void
 latexila_build_tool_run_finish (LatexilaBuildTool *build_tool,
                                 GAsyncResult      *result)
 {
+  GTask *task;
+  TaskData *data;
   GCancellable *cancellable;
 
   g_return_if_fail (g_task_is_valid (result, build_tool));
 
-  cancellable = g_task_get_cancellable (G_TASK (result));
+  task = G_TASK (result);
+  data = g_task_get_task_data (task);
+
+  cancellable = g_task_get_cancellable (task);
   if (g_cancellable_is_cancelled (cancellable))
-    latexila_build_view_set_title_state (build_tool->priv->build_view,
-                                         &build_tool->priv->main_title,
+    latexila_build_view_set_title_state (data->build_view,
+                                         &data->main_title,
                                          LATEXILA_BUILD_STATE_ABORTED);
 
-  g_task_propagate_boolean (G_TASK (result), NULL);
-
-  g_clear_object (&build_tool->priv->task);
-  g_clear_object (&build_tool->priv->file);
-  g_clear_object (&build_tool->priv->build_view);
-}
-
-/**
- * latexila_build_tool_clear:
- * @build_tool: a build tool
- *
- * Clears the last run operation. latexila_build_tool_run_finish() must have
- * been called before calling this function.
- *
- * The build tool can keep build messages or other information in memory. For
- * example if a build job contains detailed messages, the two trees of messages
- * must be kept in memory so it can switch between them when the "More details"
- * button is toggled.
- */
-void
-latexila_build_tool_clear (LatexilaBuildTool *build_tool)
-{
-  GList *l;
-
-  for (l = build_tool->priv->jobs->head; l != NULL; l = l->next)
-    {
-      LatexilaBuildJob *build_job = l->data;
-      latexila_build_job_clear (build_job);
-    }
+  g_task_propagate_boolean (task, NULL);
+  build_tool->priv->running_tasks_count--;
 }
diff --git a/src/liblatexila/latexila-build-tool.h b/src/liblatexila/latexila-build-tool.h
index b497fe8..32c5dc6 100644
--- a/src/liblatexila/latexila-build-tool.h
+++ b/src/liblatexila/latexila-build-tool.h
@@ -72,8 +72,6 @@ void                  latexila_build_tool_run_async                 (LatexilaBui
 void                  latexila_build_tool_run_finish                (LatexilaBuildTool *build_tool,
                                                                      GAsyncResult      *result);
 
-void                  latexila_build_tool_clear                     (LatexilaBuildTool *build_tool);
-
 G_END_DECLS
 
 #endif /* __LATEXILA_BUILD_TOOL_H__ */
diff --git a/src/main_window_build_tools.vala b/src/main_window_build_tools.vala
index e67fc78..a615168 100644
--- a/src/main_window_build_tools.vala
+++ b/src/main_window_build_tools.vala
@@ -59,8 +59,8 @@ public class MainWindowBuildTools
     private BottomPanel _bottom_panel;
 
     // Used for running a build tool, and clear it when running another build tool.
-    private Latexila.BuildTool? _build_tool;
     private Cancellable? _cancellable;
+    private AsyncResult? _build_tool_result;
 
     private Gtk.ActionGroup _static_action_group;
     private Gtk.ActionGroup _dynamic_action_group;
@@ -377,18 +377,15 @@ public class MainWindowBuildTools
             Utils.flush_queue ();
         }
 
-        if (_build_tool != null)
-            _build_tool.clear ();
-
-        _build_tool = tool;
-
         /* Run the build tool */
 
         File main_file = active_doc.get_main_file ();
         _cancellable = new Cancellable ();
+        _build_tool_result = null;
         update_sensitivity ();
         tool.run_async.begin (main_file, _build_view, _cancellable, (obj, result) =>
         {
+            _build_tool_result = result;
             tool.run_async.end (result);
             _cancellable = null;
             update_sensitivity ();



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]