[Goodies-commits] r7340 - in xfce4-screenshooter/trunk: . lib src

Jerome Guelfucci jeromeg at xfce.org
Fri May 15 18:23:26 CEST 2009


Author: jeromeg
Date: 2009-05-15 16:23:26 +0000 (Fri, 15 May 2009)
New Revision: 7340

Added:
   xfce4-screenshooter/trunk/lib/exo-job.c
   xfce4-screenshooter/trunk/lib/exo-job.h
   xfce4-screenshooter/trunk/lib/exo-simple-job.c
   xfce4-screenshooter/trunk/lib/exo-simple-job.h
   xfce4-screenshooter/trunk/lib/screenshooter-job.c
   xfce4-screenshooter/trunk/lib/screenshooter-job.h
   xfce4-screenshooter/trunk/lib/screenshooter-marshal.list
   xfce4-screenshooter/trunk/lib/screenshooter-simple-job.c
   xfce4-screenshooter/trunk/lib/screenshooter-simple-job.h
Modified:
   xfce4-screenshooter/trunk/ChangeLog
   xfce4-screenshooter/trunk/configure.ac.in
   xfce4-screenshooter/trunk/lib/
   xfce4-screenshooter/trunk/lib/Makefile.am
   xfce4-screenshooter/trunk/lib/screenshooter-actions.c
   xfce4-screenshooter/trunk/lib/screenshooter-zimagez.c
   xfce4-screenshooter/trunk/lib/screenshooter-zimagez.h
   xfce4-screenshooter/trunk/src/main.c
Log:
	* src/main.c:
	  - add the glib and stdlib headers.
	  - use RETURN_SUCCESS and RETURN_FAILURE instead of 0 and 1.
	* lib/exo-simple-job.{c,h}, lib/exo-job.{c,h}: take the job framework
	  from Exo written by Jannis Pohlmann. Thank you Jannis!
	* lib/screenshooter-job.{c,h}, lib/screenshooter-simple-job.{c,h}:
	  ScreenshooterJob is based on ExoJob, it provides to additional signals,
	  ask and image-uploaded.
	* lib/screenshooter-marshal.list: add some marshallers for the new
	  signals.
	* lib/screenshooter-zimagez.{c,h}: port the existing code to use a
	  ScreenshooterJob. Thanks to Jannis for his great help! This fixes
	  a bunch of problems that occured with the previous implementation.
	  The dialogs still need to be polished.
	* lib/screenshooter-actions.c: use the new function.
	* lib/Makefile.am:
	  - add some magic to generate the marshallers.
	  - sort the source files by alphabetical order.
	* configure.ac.in: bump the GThreads required version to 2.16.



Modified: xfce4-screenshooter/trunk/ChangeLog
===================================================================
--- xfce4-screenshooter/trunk/ChangeLog	2009-05-15 06:58:00 UTC (rev 7339)
+++ xfce4-screenshooter/trunk/ChangeLog	2009-05-15 16:23:26 UTC (rev 7340)
@@ -1,3 +1,25 @@
+2009-05-15 jeromeg
+
+	* src/main.c:
+	  - add the glib and stdlib headers.
+	  - use RETURN_SUCCESS and RETURN_FAILURE instead of 0 and 1.
+	* lib/exo-simple-job.{c,h}, lib/exo-job.{c,h}: take the job framework
+	  from Exo written by Jannis Pohlmann. Thank you Jannis!
+	* lib/screenshooter-job.{c,h}, lib/screenshooter-simple-job.{c,h}:
+	  ScreenshooterJob is based on ExoJob, it provides to additional signals,
+	  ask and image-uploaded.
+	* lib/screenshooter-marshal.list: add some marshallers for the new
+	  signals.
+	* lib/screenshooter-zimagez.{c,h}: port the existing code to use a
+	  ScreenshooterJob. Thanks to Jannis for his great help! This fixes
+	  a bunch of problems that occured with the previous implementation.
+	  The dialogs still need to be polished.
+	* lib/screenshooter-actions.c: use the new function.
+	* lib/Makefile.am:
+	  - add some magic to generate the marshallers.
+	  - sort the source files by alphabetical order.
+	* configure.ac.in: bump the GThreads required version to 2.16.
+
 2009-05-05 jeromeg
 
 	* lib/screenshooter-zimagez.c: make the dialog unresizable and destroy

Modified: xfce4-screenshooter/trunk/configure.ac.in
===================================================================
--- xfce4-screenshooter/trunk/configure.ac.in	2009-05-15 06:58:00 UTC (rev 7339)
+++ xfce4-screenshooter/trunk/configure.ac.in	2009-05-15 16:23:26 UTC (rev 7340)
@@ -53,7 +53,7 @@
 XDT_CHECK_PACKAGE([LIBXFCE4PANEL], [libxfce4panel-1.0], [4.4.0])
 XDT_CHECK_PACKAGE([LIBXFCE4UTIL], [libxfce4util-1.0], [4.4.0])
 XDT_CHECK_PACKAGE([LIBXFCEGUI4], [libxfcegui4-1.0], [4.4.0])
-XDT_CHECK_PACKAGE([GTHREAD], [gthread-2.0], [2.6.0])
+XDT_CHECK_PACKAGE([GTHREAD], [gthread-2.0], [2.16.0])
 XDT_CHECK_PACKAGE([GTK], [gtk+-2.0], [2.12.0])
 XDT_CHECK_PACKAGE([GLIB], [glib-2.0], [2.16.0])
 


Property changes on: xfce4-screenshooter/trunk/lib
___________________________________________________________________
Modified: svn:ignore
   - Makefile.in
Makefile
.deps

   + Makefile.in
Makefile
.deps
stamp-screenshooter-marshal.h
screenshooter-marshal.c
screenshooter-marshal.h



Modified: xfce4-screenshooter/trunk/lib/Makefile.am
===================================================================
--- xfce4-screenshooter/trunk/lib/Makefile.am	2009-05-15 06:58:00 UTC (rev 7339)
+++ xfce4-screenshooter/trunk/lib/Makefile.am	2009-05-15 16:23:26 UTC (rev 7340)
@@ -1,15 +1,23 @@
 noinst_LTLIBRARIES = 							\
 	libscreenshooter.la
 
+libscreenshooter_built_sources = \
+	screenshooter-marshal.c screenshooter-marshal.h
+
 libscreenshooter_la_SOURCES =							\
+	$(libscreenshooter_built_sources) \
 	libscreenshooter.h \
+  exo-job.c exo-job.h \
+	exo-simple-job.c exo-simple-job.h \
+	screenshooter-actions.c screenshooter-actions.h \
+	screenshooter-capture.c screenshooter-capture.h \
+  screenshooter-dialogs.c screenshooter-dialogs.h \
 	screenshooter-global.h \
+	screenshooter-job.c screenshooter-job.h \
+	screenshooter-simple-job.c screenshooter-simple-job.h \
 	screenshooter-utils.c screenshooter-utils.h \
-  sexy-url-label.c sexy-url-label.h \
-	screenshooter-capture.c screenshooter-capture.h \
-	screenshooter-dialogs.c screenshooter-dialogs.h \
-	screenshooter-actions.c screenshooter-actions.h \
-	screenshooter-zimagez.c screenshooter-zimagez.h
+	screenshooter-zimagez.c screenshooter-zimagez.h \
+  sexy-url-label.c sexy-url-label.h
 
 libscreenshooter_la_CFLAGS = \
 	-I$(top_srcdir)	\
@@ -26,3 +34,40 @@
 	@LIBXFCE4UTIL_LIBS@ \
 	@LIBXFCEGUI4_LIBS@ \
   @GLIB_LIBS@
+
+##
+## Rules to auto-generate built sources
+##
+## This is a bit tricky with automake, and non-trivial to implement. The
+## rules below seem to work fine and don't seem to break the build, but
+## they are only enabled in maintainer mode, so arbitrary users don't get
+## trapped in automake's oddities. Therefore we ship the autogenerated
+## files as part of the dist tarball.
+##
+
+DISTCLEANFILES =	\
+	stamp-screenshooter-marshal.h \
+	$(libscreenshooter_built_sources)
+
+BUILT_SOURCES = \
+	$(libscreenshooter_built_sources)
+
+screenshooter-marshal.h: stamp-screenshooter-marshal.h
+	@true
+stamp-screenshooter-marshal.h: screenshooter-marshal.list Makefile
+	( cd $(srcdir) && glib-genmarshal \
+		--prefix=_screenshooter_marshal \
+		--header screenshooter-marshal.list ) >> xgen-emh \
+	&& ( cmp -s xgen-emh screenshooter-marshal.h || cp xgen-emh screenshooter-marshal.h ) \
+	&& rm -f xgen-emh \
+	&& echo timestamp > $(@F)
+
+screenshooter-marshal.c: screenshooter-marshal.list Makefile
+	( cd $(srcdir) && glib-genmarshal \
+		--prefix=_screenshooter_marshal \
+		--body screenshooter-marshal.list ) >> xgen-emc \
+	&& cp xgen-emc screenshooter-marshal.c \
+	&& rm -f xgen-emc
+
+EXTRA_DIST = \
+	screenshooter-marshal.list

Added: xfce4-screenshooter/trunk/lib/exo-job.c
===================================================================
--- xfce4-screenshooter/trunk/lib/exo-job.c	                        (rev 0)
+++ xfce4-screenshooter/trunk/lib/exo-job.c	2009-05-15 16:23:26 UTC (rev 7340)
@@ -0,0 +1,631 @@
+/* vi:set et ai sw=2 sts=2 ts=2: */
+/*-
+ * Copyright (c) 2009 Jannis Pohlmann <jannis at xfce.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <gio/gio.h>
+#include <gtk/gtk.h>
+
+#include "exo-job.h"
+
+
+
+#define EXO_JOB_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EXO_TYPE_JOB, ExoJobPrivate))
+
+
+
+/* Signal identifiers */
+enum
+{
+  ERROR,
+  FINISHED,
+  INFO_MESSAGE,
+  PERCENT,
+  LAST_SIGNAL,
+};
+
+
+
+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);
+static void exo_job_finished   (ExoJob       *job);
+
+
+
+struct _ExoJobPrivate
+{
+  GIOSchedulerJob *scheduler_job;
+  GCancellable    *cancellable;
+  guint            running : 1;
+};
+
+struct _ExoJobSignalData
+{
+  gpointer instance;
+  GQuark   signal_detail;
+  guint    signal_id;
+  va_list  var_args;
+};
+
+
+
+static GObjectClass *exo_job_parent_class = NULL;
+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;
+}
+
+
+
+static void
+exo_job_class_init (ExoJobClass *klass)
+{
+  GObjectClass *gobject_class;
+
+  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; 
+
+  klass->execute = NULL;
+  klass->error = NULL;
+  klass->finished = NULL;
+  klass->info_message = NULL;
+  klass->percent = NULL;
+
+  /**
+   * ExoJob::error:
+   * @job   : an #ExoJob.
+   * @error : a #GError describing the cause.
+   *
+   * Emitted whenever an error occurs while executing the @job.
+   **/
+  job_signals[ERROR] =
+    g_signal_new ("error",
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_NO_HOOKS, 
+                  G_STRUCT_OFFSET (ExoJobClass, error), 
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__POINTER,
+                  G_TYPE_NONE, 1, G_TYPE_POINTER);
+
+  /**
+   * ExoJob::finished:
+   * @job : an #ExoJob.
+   *
+   * This signal will be automatically emitted once the @job finishes 
+   * its execution, no matter whether @job completed successfully or 
+   * was cancelled by the user.
+   **/
+  job_signals[FINISHED] =
+    g_signal_new ("finished",
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_NO_HOOKS, 
+                  G_STRUCT_OFFSET (ExoJobClass, finished), 
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__VOID,
+                  G_TYPE_NONE, 0);
+
+  /**
+   * ExoJob::info-message:
+   * @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...".
+   *
+   * 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_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_NO_HOOKS, 
+                  G_STRUCT_OFFSET (ExoJobClass, info_message), 
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__STRING,
+                  G_TYPE_NONE, 1, G_TYPE_STRING);
+
+  /**
+   * ExoJob::percent:
+   * @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.
+   **/
+  job_signals[PERCENT] =
+    g_signal_new ("percent",
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_NO_HOOKS, 
+                  G_STRUCT_OFFSET (ExoJobClass, percent), 
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__DOUBLE,
+                  G_TYPE_NONE, 1, G_TYPE_DOUBLE);
+}
+
+
+
+static void
+exo_job_init (ExoJob *job)
+{
+  job->priv = EXO_JOB_GET_PRIVATE (job);
+  job->priv->cancellable = g_cancellable_new ();
+  job->priv->running = FALSE;
+  job->priv->scheduler_job = NULL;
+}
+
+
+
+static void
+exo_job_finalize (GObject *object)
+{
+  ExoJob *job = EXO_JOB (object);
+
+  exo_job_cancel (job);
+  g_object_unref (job->priv->cancellable);
+
+  (*G_OBJECT_CLASS (exo_job_parent_class)->finalize) (object);
+}
+
+
+
+/**
+ * exo_job_finish:
+ * @job    : an #ExoJob.
+ * @result : the #GSimpleAsyncResult of the job.
+ * @error  : return location for errors.
+ *
+ * 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.
+ **/
+static gboolean
+exo_job_finish (ExoJob             *job,
+                GSimpleAsyncResult *result,
+                GError            **error)
+{
+  g_return_val_if_fail (EXO_IS_JOB (job), FALSE);
+  g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (result), FALSE);
+  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+  return !g_simple_async_result_propagate_error (result, error);
+}
+
+
+
+/**
+ * exo_job_async_ready:
+ * @object : an #ExoJob.
+ * @result : the #GAsyncResult of the job.
+ *
+ * This function is called by the #GIOScheduler at the end of the 
+ * operation. It checks if there were errors during the operation
+ * and emits "error" and "finished" signals.
+ **/
+static void
+exo_job_async_ready (GObject      *object,
+                     GAsyncResult *result)
+{
+  ExoJob *job = EXO_JOB (object);
+  GError *error = NULL;
+
+  g_return_if_fail (EXO_IS_JOB (job));
+  g_return_if_fail (G_IS_SIMPLE_ASYNC_RESULT (result));
+
+  if (!exo_job_finish (job, G_SIMPLE_ASYNC_RESULT (result), &error))
+    {
+      g_assert (error != NULL);
+
+      /* don't treat cancellation as an error for now */
+      if (error->code != G_IO_ERROR_CANCELLED)
+        exo_job_error (job, error);
+
+      g_error_free (error);
+    }
+
+  exo_job_finished (job);
+}
+
+
+
+/**
+ * exo_job_scheduler_job_func:
+ * @scheduler_job : the #GIOSchedulerJob running the operation.
+ * @cancellable   : the #GCancellable associated with the job.
+ * @user_data     : a #GSimpleAsyncResult.
+ *
+ * This function is called by the #GIOScheduler to execute the
+ * operation associated with the job. It basically calls the 
+ * ExoJobClass#execute function.
+ *
+ * Return value: %FALSE, to stop the thread at the end of the
+ *               operation.
+ **/
+static gboolean
+exo_job_scheduler_job_func (GIOSchedulerJob *scheduler_job,
+                            GCancellable    *cancellable,
+                            gpointer         user_data)
+{
+  GSimpleAsyncResult *result = user_data;
+  ExoJob             *job;
+  GError             *error = NULL;
+  gboolean            success;
+
+  job = g_simple_async_result_get_op_res_gpointer (result);
+  job->priv->scheduler_job = scheduler_job;
+
+  success = (*EXO_JOB_GET_CLASS (job)->execute) (job, &error);
+
+  /* TODO why was this necessary again? */
+  g_io_scheduler_job_send_to_mainloop (scheduler_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;
+}
+
+
+
+/**
+ * exo_job_emit_valist_in_mainloop:
+ * @user_data : an #ExoJobSignalData.
+ *
+ * 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.
+ **/
+static gboolean
+exo_job_emit_valist_in_mainloop (gpointer user_data)
+{
+  ExoJobSignalData *data = user_data;
+
+  g_signal_emit_valist (data->instance, data->signal_id, data->signal_detail, 
+                        data->var_args);
+
+  return FALSE;
+}
+
+
+/**
+ * exo_job_emit_valist:
+ * @job           : an #ExoJob.
+ * @signal_id     : the signal id.
+ * @signal_detail : the signal detail.
+ * @var_args      : 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.
+ *
+ * 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.
+ **/
+static void
+exo_job_emit_valist (ExoJob *job,
+                     guint   signal_id,
+                     GQuark  signal_detail,
+                     va_list var_args)
+{
+  ExoJobSignalData data;
+
+  g_return_if_fail (EXO_IS_JOB (job));
+  g_return_if_fail (job->priv->scheduler_job != NULL);
+
+  data.instance = job;
+  data.signal_id = signal_id;
+  data.signal_detail = signal_detail;
+  
+  /* copy the variable argument list */
+  G_VA_COPY (data.var_args, var_args);
+
+  /* emit the signal in the main loop */
+  g_io_scheduler_job_send_to_mainloop (job->priv->scheduler_job,
+                                       exo_job_emit_valist_in_mainloop,
+                                       &data, NULL);
+}
+
+
+
+/**
+ * exo_job_error:
+ * @job   : an #ExoJob.
+ * @error : a #GError.
+ *
+ * Emits the "error" signal and passes the @error to it so that the
+ * application can handle it (e.g. by displaying an error dialog).
+ *
+ * This function should never be called from outside the application's
+ * main loop.
+ **/
+static void
+exo_job_error (ExoJob *job,
+               GError *error)
+{
+  g_return_if_fail (EXO_IS_JOB (job));
+  g_return_if_fail (error != NULL);
+
+  g_signal_emit (job, job_signals[ERROR], 0, error);
+}
+
+
+
+/**
+ * exo_job_finished:
+ * @job : an #ExoJob.
+ *
+ * Emits the "finished" signal to notify listeners of the end of the
+ * operation. 
+ *
+ * This function should never be called from outside the application's
+ * main loop.
+ **/
+static void
+exo_job_finished (ExoJob *job)
+{
+  g_return_if_fail (EXO_IS_JOB (job));
+  g_signal_emit (job, job_signals[FINISHED], 0);
+}
+
+
+
+/**
+ * exo_job_launch:
+ * @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
+ * and the end of the operation.
+ *
+ * Return value: the @job itself.
+ **/
+ExoJob *
+exo_job_launch (ExoJob *job)
+{
+  GSimpleAsyncResult *result;
+
+  g_return_val_if_fail (EXO_IS_JOB (job), NULL);
+  g_return_val_if_fail (!job->priv->running, NULL);
+  g_return_val_if_fail (EXO_JOB_GET_CLASS (job)->execute != NULL, NULL);
+
+  /* mark the job as running */
+  job->priv->running = TRUE;
+
+  result = g_simple_async_result_new (G_OBJECT (job),
+                                      (GAsyncReadyCallback) exo_job_async_ready,
+                                      NULL, exo_job_launch);
+
+  g_simple_async_result_set_op_res_gpointer (result, g_object_ref (job),
+                                             (GDestroyNotify) g_object_unref);
+
+  g_io_scheduler_push_job (exo_job_scheduler_job_func, result,
+                           (GDestroyNotify) g_object_unref,
+                           G_PRIORITY_HIGH, job->priv->cancellable);
+
+  return job;
+}
+
+
+
+/**
+ * exo_job_cancel:
+ * @job : a #ExoJob.
+ *
+ * Attempts to cancel the operation currently performed by @job. Even 
+ * 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.
+ **/
+void
+exo_job_cancel (ExoJob *job)
+{
+  g_return_if_fail (EXO_IS_JOB (job));
+  g_cancellable_cancel (job->priv->cancellable);
+}
+
+
+
+/**
+ * exo_job_is_cancelled:
+ * @job : a #ExoJob.
+ *
+ * Checks whether @job was previously cancelled
+ * by a call to exo_job_cancel().
+ *
+ * Return value: %TRUE if @job is cancelled.
+ **/
+gboolean
+exo_job_is_cancelled (const ExoJob *job)
+{
+  g_return_val_if_fail (EXO_IS_JOB (job), FALSE);
+  return g_cancellable_is_cancelled (job->priv->cancellable);
+}
+
+
+
+/**
+ * exo_job_get_cancellable:
+ * @job : an #ExoJob.
+ *
+ * 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.
+ **/
+GCancellable *
+exo_job_get_cancellable (const ExoJob *job)
+{
+  g_return_val_if_fail (EXO_IS_JOB (job), NULL);
+  return job->priv->cancellable;
+}
+
+
+
+/**
+ * exo_job_set_error_if_cancelled:
+ * @job   : an #ExoJob.
+ * @error : error to be set if the @job was cancelled.
+ *
+ * Sets the @error if the @job was cancelled. This is a convenience
+ * function that is equivalent to 
+ * <informalexample><programlisting>
+ * GCancellable *cancellable;
+ * cancellable = exo_job_get_cancllable (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.
+ **/
+gboolean
+exo_job_set_error_if_cancelled (ExoJob  *job,
+                                GError **error)
+{
+  g_return_val_if_fail (EXO_IS_JOB (job), FALSE);
+  return g_cancellable_set_error_if_cancelled (job->priv->cancellable, error);
+}
+
+
+
+/**
+ * exo_job_emit:
+ * @job           : an #ExoJob.
+ * @signal_id     : the signal id.
+ * @signal_detail : the signal detail.
+ * ...            : 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
+ * main loop and waits for listeners to handle it.
+ **/
+void
+exo_job_emit (ExoJob *job,
+              guint   signal_id,
+              GQuark  signal_detail,
+              ...)
+{
+  va_list var_args;
+
+  g_return_if_fail (EXO_IS_JOB (job));
+
+  va_start (var_args, signal_detail);
+  exo_job_emit_valist (job, signal_id, signal_detail, var_args);
+  va_end (var_args);
+}
+
+
+
+/**
+ * exo_job_info_message:
+ * @job    : an #ExoJob.
+ * @format : a format string.
+ * ...     : parameters for the format string.
+ *
+ * Generates and emits an "info-message" signal and sends it to the
+ * application's main loop.
+ **/
+void
+exo_job_info_message (ExoJob      *job,
+                      const gchar *format,
+                      ...)
+{
+  va_list var_args;
+  gchar  *message;
+
+  g_return_if_fail (EXO_IS_JOB (job));
+  g_return_if_fail (format != NULL);
+
+  va_start (var_args, format);
+  message = g_strdup_vprintf (format, var_args);
+
+  exo_job_emit (job, job_signals[INFO_MESSAGE], 0, message);
+
+  g_free (message);
+  va_end (var_args);
+}
+
+
+
+/**
+ * exo_job_percent:
+ * @job     : an #ExoJob.
+ * @percent : percentage of completeness of the operation.
+ *
+ * Emits a "percent" signal and sends it to the application's main
+ * loop. Also makes sure that @percent is between 0.0 and 100.0.
+ **/
+void
+exo_job_percent (ExoJob *job,
+                 gdouble percent)
+{
+  g_return_if_fail (EXO_IS_JOB (job));
+
+  percent = MAX (0.0, MIN (100.0, percent));
+  exo_job_emit (job, job_signals[PERCENT], 0, percent);
+}
+

Added: xfce4-screenshooter/trunk/lib/exo-job.h
===================================================================
--- xfce4-screenshooter/trunk/lib/exo-job.h	                        (rev 0)
+++ xfce4-screenshooter/trunk/lib/exo-job.h	2009-05-15 16:23:26 UTC (rev 7340)
@@ -0,0 +1,85 @@
+/* vi:set et ai sw=2 sts=2 ts=2: */
+/*-
+ * Copyright (c) 2009 Jannis Pohlmann <jannis at xfce.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __EXO_JOB_H__
+#define __EXO_JOB_H__
+
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+
+#define EXO_TYPE_JOB            (exo_job_get_type ())
+#define EXO_JOB(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), EXO_TYPE_JOB, ExoJob))
+#define EXO_JOB_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), EXO_TYPE_JOB, ExoJobClass))
+#define EXO_IS_JOB(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EXO_TYPE_JOB))
+#define EXO_IS_JOB_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EXO_TYPE_JOB)
+#define EXO_JOB_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), EXO_TYPE_JOB, ExoJobClass))
+
+typedef struct _ExoJobPrivate ExoJobPrivate;
+typedef struct _ExoJobClass   ExoJobClass;
+typedef struct _ExoJob        ExoJob;
+
+struct _ExoJobClass
+{
+  GObjectClass __parent__;
+
+  /* virtual methods */
+  gboolean   (*execute)      (ExoJob      *job,
+                              GError     **error); 
+
+  /* signals */
+  void       (*error)        (ExoJob      *job,
+                              GError      *error);
+  void       (*finished)     (ExoJob      *job);
+  void       (*info_message) (ExoJob      *job,
+                              const gchar *message);
+  void       (*percent)      (ExoJob      *job,
+                              gdouble      percent);
+};
+
+struct _ExoJob
+{
+  GObject __parent__;
+
+  /*< private >*/
+  ExoJobPrivate *priv;
+};
+
+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,
+                                                ...);
+void            exo_job_info_message           (ExoJob       *job,
+                                                const gchar  *format,
+                                                ...);
+void            exo_job_percent                (ExoJob       *job,
+                                                gdouble       percent);
+
+G_END_DECLS
+
+#endif /* !__EXO_JOB_H__ */

Added: xfce4-screenshooter/trunk/lib/exo-simple-job.c
===================================================================
--- xfce4-screenshooter/trunk/lib/exo-simple-job.c	                        (rev 0)
+++ xfce4-screenshooter/trunk/lib/exo-simple-job.c	2009-05-15 16:23:26 UTC (rev 7340)
@@ -0,0 +1,219 @@
+/* $Id$ */
+/*-
+ * Copyright (c) 2006 Benedikt Meurer <benny at xfce.org>
+ * Copyright (c) 2009 Jannis Pohlmann <jannis at xfce.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+#ifdef HAVE_STDARG_H
+#include <stdarg.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#include <gobject/gvaluecollector.h>
+
+#include "exo-job.h"
+#include "exo-simple-job.h"
+
+
+
+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);
+
+
+
+struct _ExoSimpleJobClass
+{
+  ExoJobClass __parent__;
+};
+
+struct _ExoSimpleJob
+{
+  ExoJob           __parent__;
+  ExoSimpleJobFunc func;
+  GValueArray     *param_values;
+};
+
+
+
+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;
+}
+
+
+
+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);
+
+  gobject_class = G_OBJECT_CLASS (klass);
+  gobject_class->finalize = exo_simple_job_finalize;
+
+  exojob_class = EXO_JOB_CLASS (klass);
+  exojob_class->execute = exo_simple_job_execute;
+}
+
+
+
+static void
+exo_simple_job_finalize (GObject *object)
+{
+  ExoSimpleJob *simple_job = EXO_SIMPLE_JOB (object);
+
+  /* release the param values */
+  g_value_array_free (simple_job->param_values);
+
+  (*G_OBJECT_CLASS (exo_simple_job_parent_class)->finalize) (object);
+}
+
+
+
+static gboolean
+exo_simple_job_execute (ExoJob  *job,
+                        GError **error)
+{
+  ExoSimpleJob *simple_job = EXO_SIMPLE_JOB (job);
+  gboolean         success = TRUE;
+  GError          *err = NULL;
+
+  g_return_val_if_fail (EXO_IS_SIMPLE_JOB (job), FALSE);
+  g_return_val_if_fail (simple_job->func != NULL, FALSE);
+
+  /* try to execute the job using the supplied function */
+  success = (*simple_job->func) (job, simple_job->param_values, &err);
+
+  if (!success)
+    {
+      g_assert (err != NULL || exo_job_is_cancelled (job));
+
+      /* set error if the job was cancelled. otherwise just propagate 
+       * the results of the processing function */
+      if (exo_job_set_error_if_cancelled (job, error))
+        {
+          g_clear_error (&err);
+        }
+      else
+        {
+          if (err != NULL)
+            g_propagate_error (error, err);
+        }
+
+      return FALSE;
+    }
+  else
+    return TRUE;
+}
+
+
+
+/**
+ * exo_simple_job_launch:
+ * @func           : the #ExoSimpleJobFunc to execute the job.
+ * @n_param_values : the number of parameters to pass to the @func.
+ * @...            : a list of #GType and parameter pairs (exactly
+ *                   @n_param_values pairs) that are passed to @func.
+ *
+ * Allocates a new #ExoJob which executes the specified @func with 
+ * the specified parameters. 
+ *
+ * An example could be:
+ *
+ * <informalexample><programlisting>
+ * exo_simple_job_launch (list_directory_job, 1, G_TYPE_FILE, file);
+ * </programlisting></informalexample>
+ *
+ * The caller is responsible to release the returned object using
+ * g_object_unref() when no longer needed.
+ *
+ * Return value: the launched #ExoJob.
+ **/
+ExoJob*
+exo_simple_job_launch (ExoSimpleJobFunc func,
+                       guint            n_param_values,
+                       ...)
+{
+  ExoSimpleJob *simple_job;
+  va_list       var_args;
+  GValue        value = { 0, };
+  gchar        *error_message;
+  gint          n;
+
+  /* allocate and initialize the simple job */
+  simple_job = g_object_new (EXO_TYPE_SIMPLE_JOB, NULL);
+  simple_job->func = func;
+  simple_job->param_values = g_value_array_new (n_param_values);
+
+  /* collect the parameters */
+  va_start (var_args, n_param_values);
+  for (n = 0; n < n_param_values; ++n)
+    {
+      /* initialize the value to hold the next parameter */
+      g_value_init (&value, va_arg (var_args, GType));
+
+      /* collect the value from the stack */
+      G_VALUE_COLLECT (&value, var_args, 0, &error_message);
+
+      /* check if an error occurred */
+      if (G_UNLIKELY (error_message != NULL))
+        {
+          g_error ("%s: %s", G_STRLOC, error_message);
+          g_free (error_message);
+        }
+
+      g_value_array_insert (simple_job->param_values, n, &value);
+      g_value_unset (&value);
+    }
+  va_end (var_args);
+
+  /* launch the job */
+  return exo_job_launch (EXO_JOB (simple_job));
+}

Added: xfce4-screenshooter/trunk/lib/exo-simple-job.h
===================================================================
--- xfce4-screenshooter/trunk/lib/exo-simple-job.h	                        (rev 0)
+++ xfce4-screenshooter/trunk/lib/exo-simple-job.h	2009-05-15 16:23:26 UTC (rev 7340)
@@ -0,0 +1,63 @@
+/* vi:set et ai sw=2 sts=2 ts=2: */
+/*-
+ * Copyright (c) 2009 Jannis Pohlmann <jannis at xfce.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __EXO_SIMPLE_JOB_H__
+#define __EXO_SIMPLE_JOB_H__
+
+#include "exo-job.h"
+
+G_BEGIN_DECLS
+
+/**
+ * ExoSimpleJobFunc:
+ * @job            : an #ExoJob.
+ * @param_values   : a #GValueArray of the #GValue<!---->s passed to 
+ *                   exo_simple_job_launch().
+ * @error          : return location for errors.
+ *
+ * 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.
+ **/
+typedef gboolean (*ExoSimpleJobFunc) (ExoJob      *job,
+                                      GValueArray *param_values,
+                                      GError     **error);
+
+
+#define EXO_TYPE_SIMPLE_JOB            (exo_simple_job_get_type ())
+#define EXO_SIMPLE_JOB(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), EXO_TYPE_SIMPLE_JOB, ExoSimpleJob))
+#define EXO_SIMPLE_JOB_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), EXO_TYPE_SIMPLE_JOB, ExoSimpleJobClass))
+#define EXO_IS_SIMPLE_JOB(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EXO_TYPE_SIMPLE_JOB))
+#define EXO_IS_SIMPLE_JOB_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EXO_TYPE_SIMPLE_JOB))
+#define EXO_SIMPLE_JOB_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), EXO_TYPE_SIMPLE_JOB, ExoSimpleJobClass))
+
+typedef struct _ExoSimpleJobClass ExoSimpleJobClass;
+typedef struct _ExoSimpleJob      ExoSimpleJob;
+
+GType   exo_simple_job_get_type (void) G_GNUC_CONST;
+
+ExoJob *exo_simple_job_launch   (ExoSimpleJobFunc func,
+                                 guint            n_param_values,
+                                 ...) G_GNUC_MALLOC G_GNUC_WARN_UNUSED_RESULT;
+
+G_END_DECLS
+
+#endif /* !__EXO_SIMPLE_JOB_H__ */

Modified: xfce4-screenshooter/trunk/lib/screenshooter-actions.c
===================================================================
--- xfce4-screenshooter/trunk/lib/screenshooter-actions.c	2009-05-15 06:58:00 UTC (rev 7339)
+++ xfce4-screenshooter/trunk/lib/screenshooter-actions.c	2009-05-15 16:23:26 UTC (rev 7340)
@@ -56,11 +56,7 @@
             }
           else
             {
-              const gchar *upload_name =
-                screenshooter_upload_to_zimagez (screenshot_path);
-
-              if (upload_name != NULL)
-                screenshooter_display_zimagez_links (upload_name);
+              screenshooter_upload_to_zimagez (screenshot_path);
             }
         }
 

Added: xfce4-screenshooter/trunk/lib/screenshooter-job.c
===================================================================
--- xfce4-screenshooter/trunk/lib/screenshooter-job.c	                        (rev 0)
+++ xfce4-screenshooter/trunk/lib/screenshooter-job.c	2009-05-15 16:23:26 UTC (rev 7340)
@@ -0,0 +1,195 @@
+/*  $Id$
+ *
+ *  Copyright © 2008-2009 Jérôme Guelfucci <jerome.guelfucci at gmail.com>
+ *
+ *  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 Library 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.
+ */
+
+#include "screenshooter-job.h"
+
+
+
+#define SCREENSHOOTER_JOB_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), SCREENSHOOTER_TYPE_JOB, ScreenshooterJobPrivate))
+
+
+
+/* Signal identifiers */
+enum
+{
+  ASK,
+  IMAGE_UPLOADED,
+  LAST_SIGNAL,
+};
+
+
+
+static void  screenshooter_job_class_init (ScreenshooterJobClass *klass);
+static void  screenshooter_job_init       (ScreenshooterJob      *job);
+static void  screenshooter_job_finalize   (GObject               *object);
+/*static void  screenshooter_job_real_ask   (ScreenshooterJob      *job,
+                                           GtkListStore          *liststore,
+                                           const gchar           *message);*/
+
+
+
+static ExoJobClass *screenshooter_job_parent_class;
+static guint        job_signals[LAST_SIGNAL];
+
+
+
+GType
+screenshooter_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,
+                                            "ScreenshooterJob",
+                                            sizeof (ScreenshooterJobClass),
+                                            (GClassInitFunc) screenshooter_job_class_init,
+                                            sizeof (ScreenshooterJob),
+                                            (GInstanceInitFunc) screenshooter_job_init,
+                                            G_TYPE_FLAG_ABSTRACT);
+    }
+
+  return type;
+}
+
+
+
+static void
+screenshooter_job_class_init (ScreenshooterJobClass *klass)
+{
+  GObjectClass *gobject_class;
+
+  /* determine the parent class */
+  screenshooter_job_parent_class = g_type_class_peek_parent (klass);
+
+  gobject_class = G_OBJECT_CLASS (klass);
+  gobject_class->finalize = screenshooter_job_finalize;
+
+  klass->ask = NULL;
+
+  /**
+   * ScreenshooterJob::ask:
+   * @job     : a #ScreenshooterJob.
+   * @info    : a #GtkListStore.
+   * @message : message to display to the user.
+   *
+   * The @message is garantied to contain valid UTF-8.
+   *
+   * @info contains the information already gathered. The first column tells you the
+   * name of the information, the second its contents. Some contents might be empty,
+   * it means that the user did not provide the correct information as explained per
+   * @message.
+   *
+   * The callback asks for the information which is not valid and updates @info.
+   **/
+  job_signals[ASK] =
+    g_signal_new ("ask",
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_NO_HOOKS | G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (ScreenshooterJobClass, ask),
+                  NULL, NULL,
+                  _screenshooter_marshal_VOID__POINTER_STRING,
+                  G_TYPE_NONE,
+                  2, G_TYPE_POINTER, G_TYPE_STRING);
+
+  /**
+   * ScreenshooterJob::image-uploaded:
+   * @job       : a #ScreenshooterJob.
+   * @file_name : the name of the uploaded image on ZimageZ.com.
+   *
+   * This signal is emitted when the upload is finished. If it was successful,
+   * @file_name contains the name of the file on ZimageZ.com, else it is NULL.
+   **/
+  job_signals[IMAGE_UPLOADED] =
+    g_signal_new ("image-uploaded",
+                  G_TYPE_FROM_CLASS (klass), G_SIGNAL_NO_HOOKS,
+                  0, NULL, NULL,
+                  _screenshooter_marshal_VOID__STRING,
+                  G_TYPE_NONE,
+                  1, G_TYPE_STRING);
+}
+
+
+
+static void
+screenshooter_job_init (ScreenshooterJob *job)
+{
+
+}
+
+
+
+static void
+screenshooter_job_finalize (GObject *object)
+{
+  (*G_OBJECT_CLASS (screenshooter_job_parent_class)->finalize) (object);
+}
+
+
+
+/*static void
+screenshooter_job_real_ask (ScreenshooterJob *job,
+                            GtkListStore     *liststore,
+                            const gchar      *message)
+{
+  g_return_if_fail (SCREENSHOOTER_IS_JOB (job));
+
+  TRACE ("Emit ask signal.");
+  g_signal_emit (job, job_signals[ASK], 0, liststore, message);
+}*/
+
+
+
+/* Public */
+
+
+
+void screenshooter_job_ask_info (ScreenshooterJob *job,
+                                 GtkListStore     *info,
+                                 const gchar      *format,
+                                 ...)
+{
+  va_list va_args = NULL;
+  gchar *message;
+
+  g_return_if_fail (SCREENSHOOTER_IS_JOB (job));
+  g_return_if_fail (GTK_IS_LIST_STORE (info));
+  g_return_if_fail (format != NULL);
+
+  if (G_UNLIKELY (exo_job_is_cancelled (EXO_JOB (job))))
+  
+  va_start (va_args, format);
+  message = g_strdup_vprintf (format, va_args);
+  va_end (va_args);
+
+  exo_job_emit (EXO_JOB (job), job_signals[ASK], 0, info, message);
+
+  g_free (message);
+}
+
+
+
+void
+screenshooter_job_image_uploaded (ScreenshooterJob *job, const gchar *file_name)
+{
+  g_return_if_fail (SCREENSHOOTER_IS_JOB (job));
+
+  TRACE ("Emit image-uploaded signal.");
+  exo_job_emit (EXO_JOB (job), job_signals[IMAGE_UPLOADED], 0, file_name);
+}

Added: xfce4-screenshooter/trunk/lib/screenshooter-job.h
===================================================================
--- xfce4-screenshooter/trunk/lib/screenshooter-job.h	                        (rev 0)
+++ xfce4-screenshooter/trunk/lib/screenshooter-job.h	2009-05-15 16:23:26 UTC (rev 7340)
@@ -0,0 +1,77 @@
+/*  $Id$
+ *
+ *  Copyright © 2008-2009 Jérôme Guelfucci <jerome.guelfucci at gmail.com>
+ *
+ *  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 Library 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.
+ */
+
+#ifndef __SCREENSHOOTER_JOB_H__
+#define __SCREENSHOOTER_JOB_H__
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <gio/gio.h>
+#include <gtk/gtk.h>
+#include <libxfce4util/libxfce4util.h>
+
+#include "exo-simple-job.h"
+#include "screenshooter-marshal.h"
+
+G_BEGIN_DECLS
+
+typedef struct _ScreenshooterJobClass   ScreenshooterJobClass;
+typedef struct _ScreenshooterJob        ScreenshooterJob;
+
+#define SCREENSHOOTER_TYPE_JOB            (screenshooter_job_get_type ())
+#define SCREENSHOOTER_JOB(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), SCREENSHOOTER_TYPE_JOB, ScreenshooterJob))
+#define SCREENSHOOTER_JOB_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), SCREENSHOOTER_TYPE_JOB, ScreenshooterJobClass))
+#define SCREENSHOOTER_IS_JOB(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SCREENSHOOTER_TYPE_JOB))
+#define SCREENSHOOTER_IS_JOB_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SCREENSHOOTER_TYPE_JOB))
+#define SCREENSHOOTER_JOB_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), SCREENSHOOTER_TYPE_JOB, ScreenshooterJobClass))
+
+struct _ScreenshooterJobClass
+{
+  /*< private >*/
+  ExoJobClass __parent__;
+
+  /*< public >*/
+
+  /* signals */
+  void (*ask) (ScreenshooterJob *job, GtkListStore *info, const gchar *message);
+};
+
+struct _ScreenshooterJob
+{
+  /*< private >*/
+  ExoJob __parent__;
+};
+
+GType screenshooter_job_get_type       (void) G_GNUC_CONST;
+
+void  screenshooter_job_ask_info       (ScreenshooterJob *job,
+                                        GtkListStore     *info,
+                                        const gchar      *format,
+                                        ...);
+                                        
+
+void  screenshooter_job_image_uploaded (ScreenshooterJob *job,
+                                        const gchar      *file_name);
+
+G_END_DECLS
+
+#endif /* !__SCREENSHOOTER_JOB_H__ */
+


Property changes on: xfce4-screenshooter/trunk/lib/screenshooter-job.h
___________________________________________________________________
Added: svn:executable
   + *

Added: xfce4-screenshooter/trunk/lib/screenshooter-marshal.list
===================================================================
--- xfce4-screenshooter/trunk/lib/screenshooter-marshal.list	                        (rev 0)
+++ xfce4-screenshooter/trunk/lib/screenshooter-marshal.list	2009-05-15 16:23:26 UTC (rev 7340)
@@ -0,0 +1,2 @@
+VOID:STRING
+VOID:POINTER,STRING

Added: xfce4-screenshooter/trunk/lib/screenshooter-simple-job.c
===================================================================
--- xfce4-screenshooter/trunk/lib/screenshooter-simple-job.c	                        (rev 0)
+++ xfce4-screenshooter/trunk/lib/screenshooter-simple-job.c	2009-05-15 16:23:26 UTC (rev 7340)
@@ -0,0 +1,202 @@
+/*  $Id$
+ *
+ *  Copyright © 2008-2009 Jérôme Guelfucci <jerome.guelfucci at gmail.com>
+ *
+ *  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 Library 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.
+ */
+
+#include "screenshooter-simple-job.h"
+
+static void     screenshooter_simple_job_class_init (ScreenshooterSimpleJobClass  *klass);
+static void     screenshooter_simple_job_finalize   (GObject                      *object);
+static gboolean screenshooter_simple_job_execute    (ExoJob                       *job,
+                                                     GError                      **error);
+
+
+
+struct _ScreenshooterSimpleJobClass
+{
+  ScreenshooterJobClass __parent__;
+};
+
+struct _ScreenshooterSimpleJob
+{
+  ScreenshooterJob            __parent__;
+  ScreenshooterSimpleJobFunc  func;
+  GValueArray                *param_values;
+};
+
+
+
+static GObjectClass *screenshooter_simple_job_parent_class;
+
+
+
+GType
+screenshooter_simple_job_get_type (void)
+{
+  static GType type = G_TYPE_INVALID;
+
+  if (G_UNLIKELY (type == G_TYPE_INVALID))
+    {
+      type = g_type_register_static_simple (SCREENSHOOTER_TYPE_JOB, 
+                                            "ScreenshooterSimpleJob",
+                                            sizeof (ScreenshooterSimpleJobClass),
+                                            (GClassInitFunc) screenshooter_simple_job_class_init,
+                                            sizeof (ScreenshooterSimpleJob),
+                                            NULL, 
+                                            0);
+    }
+
+  return type;
+}
+
+
+
+static void
+screenshooter_simple_job_class_init (ScreenshooterSimpleJobClass *klass)
+{
+  GObjectClass *gobject_class;
+  ExoJobClass  *exojob_class;
+
+  /* determine the parent type class */
+  screenshooter_simple_job_parent_class = g_type_class_peek_parent (klass);
+
+  gobject_class = G_OBJECT_CLASS (klass);
+  gobject_class->finalize = screenshooter_simple_job_finalize;
+
+  exojob_class = EXO_JOB_CLASS (klass);
+  exojob_class->execute = screenshooter_simple_job_execute;
+}
+
+
+
+static void
+screenshooter_simple_job_finalize (GObject *object)
+{
+  ScreenshooterSimpleJob *simple_job = SCREENSHOOTER_SIMPLE_JOB (object);
+
+  /* release the param values */
+  g_value_array_free (simple_job->param_values);
+
+  (*G_OBJECT_CLASS (screenshooter_simple_job_parent_class)->finalize) (object);
+}
+
+
+
+static gboolean
+screenshooter_simple_job_execute (ExoJob  *job,
+                           GError **error)
+{
+  ScreenshooterSimpleJob *simple_job = SCREENSHOOTER_SIMPLE_JOB (job);
+  gboolean success = TRUE;
+  GError *err = NULL;
+
+  g_return_val_if_fail (SCREENSHOOTER_IS_SIMPLE_JOB (job), FALSE);
+  g_return_val_if_fail (simple_job->func != NULL, FALSE);
+
+  /* try to execute the job using the supplied function */
+  success = (*simple_job->func) (SCREENSHOOTER_JOB (job), simple_job->param_values, &err);
+
+  if (!success)
+    {
+      g_assert (err != NULL || exo_job_is_cancelled (job));
+
+      /* set error if the job was cancelled. otherwise just propagate 
+       * the results of the processing function */
+      if (exo_job_set_error_if_cancelled (job, error))
+        {
+          g_clear_error (&err);
+        }
+      else
+        {
+          if (err != NULL)
+            g_propagate_error (error, err);
+        }
+
+      return FALSE;
+    }
+  else
+    return TRUE;
+}
+
+
+
+/**
+ * screenshooter_simple_job_launch:
+ * @func           : the #ScreenshooterSimpleJobFunc to execute the job.
+ * @n_param_values : the number of parameters to pass to the @func.
+ * @...            : a list of #GType and parameter pairs (exactly
+ *                   @n_param_values pairs) that are passed to @func.
+ *
+ * Allocates a new #ScreenshooterSimpleJob, which executes the specified
+ * @func with the specified parameters.
+ *
+ * The caller is responsible to release the returned object using
+ * screenshooter_job_unref() when no longer needed.
+ *
+ * Return value: the launched #ScreenshooterJob.
+ **/
+ScreenshooterJob *
+screenshooter_simple_job_launch (ScreenshooterSimpleJobFunc func,
+                                 guint                      n_param_values,
+                                 ...)
+{
+  ScreenshooterSimpleJob *simple_job;
+  va_list var_args;
+  GValue value = { 0, };
+  gchar *error_message;
+  gint n;
+
+  /* allocate and initialize the simple job */
+  simple_job = g_object_new (SCREENSHOOTER_TYPE_SIMPLE_JOB, NULL);
+  simple_job->func = func;
+  simple_job->param_values = g_value_array_new (n_param_values);
+
+  /* collect the parameters */
+  va_start (var_args, n_param_values);
+  for (n = 0; n < n_param_values; ++n)
+    {
+      /* initialize the value to hold the next parameter */
+      g_value_init (&value, va_arg (var_args, GType));
+
+      /* collect the value from the stack */
+      G_VALUE_COLLECT (&value, var_args, 0, &error_message);
+
+      /* check if an error occurred */
+      if (G_UNLIKELY (error_message != NULL))
+        {
+          g_error ("%s: %s", G_STRLOC, error_message);
+          g_free (error_message);
+        }
+
+      g_value_array_insert (simple_job->param_values, n, &value);
+      g_value_unset (&value);
+    }
+  va_end (var_args);
+
+  /* launch the job */
+  return SCREENSHOOTER_JOB (exo_job_launch (EXO_JOB (simple_job)));
+}
+
+
+
+GValueArray *
+screenshooter_simple_job_get_param_values (ScreenshooterSimpleJob *job)
+{
+  g_return_val_if_fail (SCREENSHOOTER_IS_SIMPLE_JOB (job), NULL);
+
+  return job->param_values;
+}

Added: xfce4-screenshooter/trunk/lib/screenshooter-simple-job.h
===================================================================
--- xfce4-screenshooter/trunk/lib/screenshooter-simple-job.h	                        (rev 0)
+++ xfce4-screenshooter/trunk/lib/screenshooter-simple-job.h	2009-05-15 16:23:26 UTC (rev 7340)
@@ -0,0 +1,70 @@
+/*  $Id$
+ *
+ *  Copyright © 2008-2009 Jérôme Guelfucci <jerome.guelfucci at gmail.com>
+ *
+ *  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 Library 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.
+ */
+
+#ifndef __SCREENSHOOTER_SIMPLE_JOB_H__
+#define __SCREENSHOOTER_SIMPLE_JOB_H__
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "screenshooter-job.h"
+
+#include <gobject/gvaluecollector.h>
+#include <string.h>
+
+G_BEGIN_DECLS
+
+/**
+ * ScreenshooterSimpleJobFunc:
+ * @job            : a #ScreenshooterJob.
+ * @param_values   : a #GValueArray of the #GValue<!---->s passed to 
+ *                   screenshooter_simple_job_launch().
+ * @error          : return location for errors.
+ *
+ * Used by the #ScreenshooterSimpleJob to process the @job. See
+ * screenshooter_simple_job_launch() for further details.
+ *
+ * Return value: %TRUE on success, %FALSE in case of an error.
+ **/
+typedef gboolean (*ScreenshooterSimpleJobFunc) (ScreenshooterJob *job,
+                                                GValueArray      *param_values,
+                                                GError           **error);
+
+
+typedef struct _ScreenshooterSimpleJobClass ScreenshooterSimpleJobClass;
+typedef struct _ScreenshooterSimpleJob      ScreenshooterSimpleJob;
+
+#define SCREENSHOOTER_TYPE_SIMPLE_JOB            (screenshooter_simple_job_get_type ())
+#define SCREENSHOOTER_SIMPLE_JOB(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), SCREENSHOOTER_TYPE_SIMPLE_JOB, ScreenshooterSimpleJob))
+#define SCREENSHOOTER_SIMPLE_JOB_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), SCREENSHOOTER_TYPE_SIMPLE_JOB, ScreenshooterSimpleJobClass))
+#define SCREENSHOOTER_IS_SIMPLE_JOB(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SCREENSHOOTER_TYPE_SIMPLE_JOB))
+#define SCREENSHOOTER_IS_SIMPLE_JOB_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SCREENSHOOTER_TYPE_SIMPLE_JOB))
+#define SCREENSHOOTER_SIMPLE_JOB_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), SCREENSHOOTER_TYPE_SIMPLE_JOB, ScreenshooterSimpleJobClass))
+
+GType             screenshooter_simple_job_get_type         (void) G_GNUC_CONST;
+
+ScreenshooterJob *screenshooter_simple_job_launch           (ScreenshooterSimpleJobFunc  func,
+                                                             guint                       n_param_values,
+                                                             ...) G_GNUC_MALLOC G_GNUC_WARN_UNUSED_RESULT;
+GValueArray      *screenshooter_simple_job_get_param_values (ScreenshooterSimpleJob     *job);
+
+G_END_DECLS
+
+#endif /* !__SCREENSHOOTER_SIMPLE_JOB_H__ */

Modified: xfce4-screenshooter/trunk/lib/screenshooter-zimagez.c
===================================================================
--- xfce4-screenshooter/trunk/lib/screenshooter-zimagez.c	2009-05-15 06:58:00 UTC (rev 7339)
+++ xfce4-screenshooter/trunk/lib/screenshooter-zimagez.c	2009-05-15 16:23:26 UTC (rev 7340)
@@ -45,43 +45,36 @@
 
 
 
-static gboolean
-warn_if_fault_occurred      (xmlrpc_env * const    envP);
+static void              open_url_hook             (GtkLinkButton     *button,
+                                                    const gchar       *link,
+                                                    gpointer           user_data);
+static void              open_zimagez_link         (gpointer           unused);
+static ScreenshooterJob *zimagez_upload_to_zimagez (const gchar       *file_name);
+static gboolean          zimagez_upload_job        (ScreenshooterJob  *job,
+                                                    GValueArray       *param_values,
+                                                    GError           **error);
+static void              cb_ask_for_information    (ScreenshooterJob  *job,
+                                                    GtkListStore      *liststore,
+                                                    const gchar       *message,
+                                                    gpointer           unused);
+static void              cb_image_uploaded         (ScreenshooterJob  *job,
+                                                    gchar             *upload_name,
+                                                    gpointer           unused);
+static void              cb_error                  (ExoJob            *job,
+                                                    GError            *error,
+                                                    gpointer           unused);
+static void              cb_finished               (ExoJob            *job,
+                                                    GtkWidget         *dialog);
+static void              cb_update_info            (ExoJob            *job,
+                                                    gchar             *message,
+                                                    GtkWidget         *label);
 
-static void
-open_url_hook               (GtkLinkButton        *button,
-                             const gchar          *link,
-                             gpointer              user_data);
 
-static void
-open_zimagez_link            (gpointer             unused);
 
-
-
 /* Private */
 
 
 
-static gboolean warn_if_fault_occurred (xmlrpc_env * const envP)
-{
-  gboolean error_occured = FALSE;
-
-  if (envP->fault_occurred)
-    {
-      TRACE ("An error occured during the XML transaction %s, %d",
-             envP->fault_string, envP->fault_code );
-
-      xfce_err (_("An error occurred during the XML exchange: %s (%d).\n The screenshot "
-                  "could not be uploaded."),
-                envP->fault_string, envP->fault_code );
-
-      error_occured = TRUE;
-    }
-
-  return error_occured;
-}
-
-
 static void
 open_url_hook (GtkLinkButton *button, const gchar *link, gpointer user_data)
 {
@@ -105,27 +98,24 @@
 }
 
 
-/* Public */
 
+static gboolean
+zimagez_upload_job (ScreenshooterJob *job, GValueArray *param_values, GError **error)
+{
+  const gchar *encoded_data;
+  const gchar *image_path;
+  gchar *comment = g_strdup ("");
+  gchar *data = NULL;
+  gchar *encoded_password = NULL;
+  gchar *file_name = NULL;
+  gchar *login_response = NULL;
+  gchar *online_file_name = NULL;
+  gchar *password = g_strdup ("");
+  gchar *title = g_strdup ("");
+  gchar *user = g_strdup ("");
 
+  gsize data_length;
 
-/**
- * screenshooter_upload_to_zimagez:
- * @image_path: the local path of the image that should be uploaded to
- * ZimageZ.com.
- *
- * Uploads the image whose path is @image_path: a dialog asks for the user
- * login, password, a title for the image and a comment; then the image is
- * uploaded. The dialog is shown again with a warning is the password did
- * match the user name. The user can also cancel the upload procedure.
- *
- * Returns: NULL is the upload failed or was cancelled, a #gchar* with the name of
- * the image on Zimagez.com (see the API at the beginning of this file for more
- * details).
- **/
-
-gchar *screenshooter_upload_to_zimagez (const gchar *image_path)
-{
   xmlrpc_env env;
   xmlrpc_value *resultP = NULL;
   xmlrpc_bool response = 0;
@@ -135,233 +125,184 @@
   const gchar * const method_logout = "apiXml.xmlrpcLogout";
   const gchar * const method_upload = "apiXml.xmlrpcUpload";
 
-  gchar *data;
-  gchar *password = NULL;
-  gchar *user = NULL;
-  gchar *title = NULL;
-  gchar *comment = NULL;
-  gchar *encoded_password = NULL;
-  const gchar *encoded_data;
-  const gchar *file_name = g_path_get_basename (image_path);
-  const gchar *online_file_name;
-  const gchar *login_response;
-  gsize data_length;
+  GtkTreeIter iter;
+  GtkListStore *liststore;
 
-  GtkWidget *dialog;
-  GtkWidget *information_label;
-  GtkWidget *vbox, *main_alignment;
-  GtkWidget *table;
-  GtkWidget *user_entry, *password_entry, *title_entry, *comment_entry;
-  GtkWidget *user_label, *password_label, *title_label, *comment_label;
+  g_return_val_if_fail (SCREENSHOOTER_IS_JOB (job), FALSE);
+  g_return_val_if_fail (param_values != NULL, FALSE);
+  g_return_val_if_fail (param_values->n_values == 1, FALSE);
+  g_return_val_if_fail (G_VALUE_HOLDS_STRING (&param_values->values[0]), FALSE);
+  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
-  /* Get the user information */
-  /* Create the information dialog */
-  dialog =
-    xfce_titled_dialog_new_with_buttons (_("Details about the screenshot for ZimageZ©"),
-                                         NULL,
-                                         GTK_DIALOG_NO_SEPARATOR,
-                                         GTK_STOCK_CANCEL,
-                                         GTK_RESPONSE_CANCEL,
-                                         GTK_STOCK_OK,
-                                         GTK_RESPONSE_OK,
-                                         NULL);
+  if (exo_job_set_error_if_cancelled (EXO_JOB (job), error))
+    return FALSE;
 
-  gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER);
-  gtk_box_set_spacing (GTK_BOX (GTK_DIALOG(dialog)->vbox), 12);
+  /* Get the path of the image that is to be uploaded */
+  image_path = g_value_get_string (g_value_array_get_nth (param_values, 0));
 
-  gtk_window_set_icon_name (GTK_WINDOW (dialog), "gtk-info");
-  gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
+  /* Start the user XML RPC session */
 
-  gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
+  exo_job_info_message (EXO_JOB (job), _("Initialize the connexion..."));
 
-  /* Create the main alignment for the dialog */
+  TRACE ("Initialize the RPC environment");
+  xmlrpc_env_init(&env);
 
-  main_alignment = gtk_alignment_new (0, 0, 1, 1);
+  TRACE ("Initialize the RPC client");
+  xmlrpc_client_init2 (&env, XMLRPC_CLIENT_NO_FLAGS, PACKAGE_NAME, PACKAGE_VERSION,
+                       NULL, 0);
 
-  gtk_alignment_set_padding (GTK_ALIGNMENT (main_alignment), 6, 0, 12, 12);
-  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), main_alignment, TRUE, TRUE, 0);
+  if (env.fault_occurred)
+    {
+      GError *tmp_error =
+        g_error_new (G_IO_ERROR, G_IO_ERROR_FAILED,
+                     _("An error occurred during the XML exchange: %s (%d).\n "
+                       "The screenshot could not be uploaded."),
+                     env.fault_string, env.fault_code);
 
-  /* Create the main box for the dialog */
+      xmlrpc_env_clean (&env);
+      xmlrpc_client_cleanup ();
 
-  vbox = gtk_vbox_new (FALSE, 10);
+      g_propagate_error (error, tmp_error);
 
-  gtk_container_set_border_width (GTK_CONTAINER (vbox), 12);
+      return FALSE;
+    }
 
-  gtk_container_add (GTK_CONTAINER (main_alignment), vbox);
+  TRACE ("Get the information liststore ready.");
 
-  /* Create the information label */
+  liststore = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING);
 
-  information_label = sexy_url_label_new ();
+  TRACE ("Append the user");
 
-  /* Note for translators : make sure to put the <a>....</a> on the first line */
-  sexy_url_label_set_markup (SEXY_URL_LABEL (information_label),
-                             _("Please file the following fields with your "
-                               "<a href=\"http://www.zimagez.com\">ZimageZ©</a> \n"
-                               "user name, passsword and details about the screenshot."));
+  gtk_list_store_append (liststore, &iter);
+  gtk_list_store_set (liststore, &iter,
+                      0, g_strdup ("user"),
+                      1, user,
+                      -1);
 
-  g_signal_connect_swapped (G_OBJECT (information_label), "url-activated",
-                            G_CALLBACK (open_zimagez_link), NULL);
+  TRACE ("Append the password");
 
-  gtk_misc_set_alignment (GTK_MISC (information_label), 0, 0);
+  gtk_list_store_append (liststore, &iter);
+  gtk_list_store_set (liststore, &iter,
+                      0, g_strdup ("password"),
+                      1, password,
+                      -1);
 
-  gtk_container_add (GTK_CONTAINER (vbox), information_label);
+  TRACE ("Append the title");
 
-  /* Create the layout table */
+  gtk_list_store_append (liststore, &iter);
+  gtk_list_store_set (liststore, &iter,
+                      0, g_strdup ("title"),
+                      1, title,
+                      -1);
 
-  table = gtk_table_new (4, 2, FALSE);
+  TRACE ("Append the comment");
 
-  gtk_table_set_col_spacings (GTK_TABLE (table), 6);
-  gtk_table_set_row_spacings (GTK_TABLE (table), 12);
+  gtk_list_store_append (liststore, &iter);
+  gtk_list_store_set (liststore, &iter,
+                      0, g_strdup ("comment"),
+                      1, comment,
+                      -1);
 
-  gtk_container_add (GTK_CONTAINER (vbox), table);
+  TRACE ("Ask for the user information");
 
-  /* Create the user label */
-  user_label = gtk_label_new (_("User:"));
+  screenshooter_job_ask_info (job, liststore,
+                              _("Please file the following fields with your "
+                                "<a href=\"http://www.zimagez.com\">ZimageZ©</a> \n"
+                                "user name, passsword and details about the screenshot."));
 
-  gtk_misc_set_alignment (GTK_MISC (user_label), 0, 0.5);
+  gtk_tree_model_get_iter_first (GTK_TREE_MODEL (liststore), &iter);
 
-  gtk_table_attach (GTK_TABLE (table), user_label,
-                    0, 1,
-                    0, 1,
-                    GTK_FILL, GTK_FILL,
-                    0, 0);
+  do
+    {
+      gchar *field_name = NULL;
+      gchar *field_value = NULL;
 
-  /* Create the user entry */
-  user_entry = gtk_entry_new ();
+      gtk_tree_model_get (GTK_TREE_MODEL (liststore), &iter,
+                          0, &field_name,
+                          1, &field_value,
+                          -1);
 
-  gtk_widget_set_tooltip_text (user_entry,
-                               _("Your Zimagez user name, if you do not have one yet"
-                                 "please create one on the Web page linked above"));
+      if (g_str_equal (field_name, "user"))
+        {
+          user = g_strdup (field_value);
+        }
+      else if (g_str_equal (field_name, "password"))
+        {
+          password = g_strdup (field_value);
+        }
+      else if (g_str_equal (field_name, "title"))
+        {
+          title = g_strdup (field_value);
+        }
+      else if (g_str_equal (field_name, "comment"))
+        {
+          comment = g_strdup (field_value);
+        }
 
+      g_free (field_name);
+      g_free (field_value);
+    }
+  while (gtk_tree_model_iter_next (GTK_TREE_MODEL (liststore), &iter));
 
-  gtk_table_attach_defaults (GTK_TABLE (table), user_entry, 1, 2, 0, 1);
-
-  /* Create the password label */
-  password_label = gtk_label_new (_("Password:"));
-
-  gtk_misc_set_alignment (GTK_MISC (password_label), 0, 0.5);
-
-  gtk_table_attach (GTK_TABLE (table), password_label,
-                    0, 1,
-                    1, 2,
-                    GTK_FILL, GTK_FILL,
-                    0, 0);
-
-  /* Create the password entry */
-  password_entry = gtk_entry_new ();
-
-  gtk_widget_set_tooltip_text (password_entry, _("The password for the user above"));
-
-  gtk_entry_set_visibility (GTK_ENTRY (password_entry), FALSE);
-
-  gtk_table_attach_defaults (GTK_TABLE (table), password_entry, 1, 2, 1, 2);
-
-  /* Create the title label */
-  title_label = gtk_label_new (_("Title:"));
-
-  gtk_misc_set_alignment (GTK_MISC (title_label), 0, 0.5);
-
-  gtk_table_attach (GTK_TABLE (table), title_label,
-                    0, 1,
-                    2, 3,
-                    GTK_FILL, GTK_FILL,
-                    0, 0);
-
-  /* Create the title entry */
-  title_entry = gtk_entry_new ();
-
-  gtk_widget_set_tooltip_text (title_entry,
-                               _("The title of the screenshot, it will be used when"
-                                 " displaying the screenshot on ZimageZ"));
-
-  gtk_table_attach_defaults (GTK_TABLE (table), title_entry, 1, 2, 2, 3);
-
-  /* Create the comment label */
-  comment_label = gtk_label_new (_("Comment:"));
-
-  gtk_misc_set_alignment (GTK_MISC (comment_label), 0, 0.5);
-
-  gtk_table_attach (GTK_TABLE (table), comment_label,
-                    0, 1,
-                    3, 4,
-                    GTK_FILL, GTK_FILL,
-                    0, 0);
-
-  /* Create the comment entry */
-  comment_entry = gtk_entry_new ();
-
-  gtk_widget_set_tooltip_text (title_entry,
-                               _("A comment on the screenshot, it will be used when"
-                                 " displaying the screenshot on ZimageZ"));
-
-  gtk_table_attach_defaults (GTK_TABLE (table), comment_entry, 1, 2, 3, 4);
-
-  /* Show the widgets of the dialog main box*/
-
-  gtk_widget_show_all (GTK_DIALOG(dialog)->vbox);
-
-  /* Start the user XML RPC session */
-
-  TRACE ("Initiate the RPC environment");
-  xmlrpc_env_init(&env);
-
-  TRACE ("Initiate the RPC client");
-  xmlrpc_client_init2 (&env, XMLRPC_CLIENT_NO_FLAGS, PACKAGE_NAME, PACKAGE_VERSION,
-                       NULL, 0);
-
-  if (warn_if_fault_occurred (&env))
+  if (exo_job_set_error_if_cancelled (EXO_JOB (job), error))
     {
       xmlrpc_env_clean (&env);
       xmlrpc_client_cleanup ();
 
-      return NULL;
+      TRACE ("The upload job was cancelled.");
+
+      return FALSE;
     }
 
   while (!response)
     {
-      gint dialog_response = gtk_dialog_run (GTK_DIALOG (dialog));
+      gboolean empty_field = FALSE;
 
-      if (dialog_response == GTK_RESPONSE_CANCEL)
+      if (exo_job_set_error_if_cancelled (EXO_JOB (job), error))
         {
           xmlrpc_env_clean (&env);
           xmlrpc_client_cleanup ();
 
-          return NULL;
+          g_free (user);
+          g_free (password);
+          g_free (title);
+          g_free (comment);
+          if (encoded_password != NULL)
+            g_free (encoded_password);
+
+          TRACE ("The upload job was cancelled.");
+
+          return FALSE;
         }
 
-      user = g_strdup (gtk_entry_get_text (GTK_ENTRY (user_entry)));
-      password = g_strdup (gtk_entry_get_text (GTK_ENTRY (password_entry)));
-      title = g_strdup (gtk_entry_get_text (GTK_ENTRY (title_entry)));
-      comment = g_strdup (gtk_entry_get_text (GTK_ENTRY (comment_entry)));
+      exo_job_info_message (EXO_JOB (job), _("Check the user information..."));
 
-      if ((dialog_response == GTK_RESPONSE_OK) && (g_str_equal (user, "") ||
-                                                   g_str_equal (password, "") ||
-                                                   g_str_equal (title, "") ||
-                                                   g_str_equal (comment, "")))
+      /* Test if one of the information fields is empty */
+      TRACE ("Check for empty fields");
+      gtk_tree_model_get_iter_first (GTK_TREE_MODEL (liststore), &iter);
+
+      do
         {
-          TRACE ("One of the fields was empty, let the user file it.");
+          gchar *field = NULL;
 
-          gtk_label_set_markup (GTK_LABEL (information_label),
-                                _("<span weight=\"bold\" foreground=\"darkred\" "
-                                  "stretch=\"semiexpanded\">You must fill all the "
-                                  " fields.</span>"));
+          gtk_tree_model_get (GTK_TREE_MODEL (liststore), &iter, 1, &field, -1);
+          empty_field = g_str_equal (field, "");
 
-          g_free (user);
-          g_free (password);
-          g_free (title);
-          g_free (comment);
+          g_free (field);
+        }
+      while (gtk_tree_model_iter_next (GTK_TREE_MODEL (liststore), &iter));
 
+      if (empty_field)
+        {
+          TRACE ("One of the fields was empty, let the user file it.");
+
+          screenshooter_job_ask_info (job, liststore,
+                                      _("<span weight=\"bold\" foreground=\"darkred\" "
+                                        "stretch=\"semiexpanded\">You must fill all the "
+                                        " fields.</span>"));
           continue;
         }
-      else
-        {
-          TRACE ("All fields were filed");
-          gtk_widget_hide (dialog);
-        }
 
-      while (gtk_events_pending ())
-        gtk_main_iteration_do (FALSE);
-
       encoded_password = g_strdup (g_strreverse (rot13 (password)));
 
       TRACE ("User: %s", user);
@@ -369,11 +310,19 @@
       /* Start the user session */
       TRACE ("Call the login method");
 
+      exo_job_info_message (EXO_JOB (job), _("Login on ZimageZ.com..."));
+
       resultP = xmlrpc_client_call (&env, serverurl, method_login,
                                     "(ss)", user, encoded_password);
 
-      if (warn_if_fault_occurred (&env))
+      if (env.fault_occurred)
         {
+          GError *tmp_error =
+            g_error_new (G_IO_ERROR, G_IO_ERROR_FAILED,
+                         _("An error occurred during the XML exchange: %s (%d).\n "
+                           "The screenshot could not be uploaded."),
+                         env.fault_string, env.fault_code);
+
           xmlrpc_env_clean (&env);
           xmlrpc_client_cleanup ();
 
@@ -383,7 +332,9 @@
           g_free (comment);
           g_free (encoded_password);
 
-          return NULL;
+          g_propagate_error (error, tmp_error);
+
+          return FALSE;
         }
 
       TRACE ("Read the login response");
@@ -393,8 +344,14 @@
         {
           xmlrpc_read_bool (&env, resultP, &response);
 
-          if (warn_if_fault_occurred (&env))
+          if (env.fault_occurred)
             {
+              GError *tmp_error =
+                g_error_new (G_IO_ERROR, G_IO_ERROR_FAILED,
+                             _("An error occurred during the XML exchange: %s (%d).\n "
+                               "The screenshot could not be uploaded."),
+                             env.fault_string, env.fault_code);
+
               xmlrpc_env_clean (&env);
               xmlrpc_client_cleanup ();
 
@@ -404,9 +361,10 @@
               g_free (comment);
               g_free (encoded_password);
 
-              return NULL;
+              g_propagate_error (error, tmp_error);
+
+              return FALSE;
             }
-
         }
       /* Else we read the string response to get the session ID */
       else
@@ -414,35 +372,101 @@
           TRACE ("Read the session ID");
           xmlrpc_read_string (&env, resultP, (const gchar ** const)&login_response);
 
-          if (warn_if_fault_occurred (&env))
-            {
-              xmlrpc_env_clean (&env);
-              xmlrpc_client_cleanup ();
+          if (env.fault_occurred)
+           {
+             GError *tmp_error =
+               g_error_new (G_IO_ERROR, G_IO_ERROR_FAILED,
+                            _("An error occurred during the XML exchange: %s (%d).\n "
+                              "The screenshot could not be uploaded."),
+                            env.fault_string, env.fault_code);
 
-              g_free (user);
-              g_free (password);
-              g_free (title);
-              g_free (comment);
-              g_free (encoded_password);
+             xmlrpc_env_clean (&env);
+             xmlrpc_client_cleanup ();
 
-              return NULL;
-            }
+             g_free (user);
+             g_free (password);
+             g_free (title);
+             g_free (comment);
+             g_free (encoded_password);
 
+             g_propagate_error (error, tmp_error);
+
+             return FALSE;
+           }
+
           response = 1;
         }
 
       if (!response)
-        gtk_label_set_markup (GTK_LABEL (information_label),
-                              _("<span weight=\"bold\" foreground=\"darkred\" "
-                                "stretch=\"semiexpanded\">The user and the password you"
-                                " entered do not match.</span>"));
+        {
+          /* Login failed, erase the password and ask for the correct on to the
+             user */
+          gtk_tree_model_get_iter_first (GTK_TREE_MODEL (liststore), &iter);
 
+          do
+            {
+              gchar *field_name = NULL;
+
+              gtk_tree_model_get (GTK_TREE_MODEL (liststore), &iter, 0, &field_name, -1);
+
+              if (g_str_equal (field_name, "password"))
+                {
+                  gtk_list_store_set (liststore, &iter, 1, g_strdup (""), -1);
+
+                  g_free (field_name);
+
+                  break;
+                }
+
+              g_free (field_name);
+            }
+          while (gtk_tree_model_iter_next (GTK_TREE_MODEL (liststore), &iter));
+
+          screenshooter_job_ask_info (job, liststore,
+                                      _("<span weight=\"bold\" foreground=\"darkred\" "
+                                        "stretch=\"semiexpanded\">The user and the "
+                                        "password you entered do not match. "
+                                        "Please correct this.</span>"));
+
+          gtk_tree_model_get_iter_first (GTK_TREE_MODEL (liststore), &iter);
+
+          do
+            {
+              gchar *field_name = NULL;
+              gchar *field_value = NULL;
+        
+              gtk_tree_model_get (GTK_TREE_MODEL (liststore), &iter,
+                                  0, &field_name,
+                                  1, &field_value,
+                                  -1);
+        
+              if (g_str_equal (field_name, "user"))
+                {
+                  user = g_strdup (field_value);
+                }
+              else if (g_str_equal (field_name, "password"))
+                {
+                  password = g_strdup (field_value);
+                }
+              else if (g_str_equal (field_name, "title"))
+                {
+                  title = g_strdup (field_value);
+                }
+              else if (g_str_equal (field_name, "comment"))
+                {
+                  comment = g_strdup (field_value);
+                }
+        
+              g_free (field_name);
+              g_free (field_value);
+            }
+          while (gtk_tree_model_iter_next (GTK_TREE_MODEL (liststore), &iter));
+        }
     }
 
   xmlrpc_DECREF (resultP);
 
-  gtk_widget_destroy (dialog);
-
+  g_free (user);
   g_free (password);
   g_free (encoded_password);
 
@@ -453,21 +477,34 @@
 
   g_free (data);
 
+  /* Get the basename of the image path */
+  file_name = g_path_get_basename (image_path);
+
+  exo_job_info_message (EXO_JOB (job), _("Upload the screenshot..."));
+
   TRACE ("Call the upload method");
   resultP = xmlrpc_client_call (&env, serverurl, method_upload,
                                 "(sssss)", encoded_data, file_name, title, comment,
                                 login_response);
 
-  g_free (user);
   g_free (title);
   g_free (comment);
+  g_free (file_name);
 
-  if (warn_if_fault_occurred (&env))
+  if (env.fault_occurred)
     {
+      GError *tmp_error =
+        g_error_new (G_IO_ERROR, G_IO_ERROR_FAILED,
+                     _("An error occurred during the XML exchange: %s (%d).\n "
+                       "The screenshot could not be uploaded."),
+                     env.fault_string, env.fault_code);
+
       xmlrpc_env_clean (&env);
       xmlrpc_client_cleanup ();
 
-      return NULL;
+      g_propagate_error (error, tmp_error);
+
+      return FALSE;
     }
 
   /* If the response is a boolean, there was an error */
@@ -477,25 +514,35 @@
 
       xmlrpc_read_bool (&env, resultP, &response_upload);
 
-      if (warn_if_fault_occurred (&env))
+      if (env.fault_occurred)
         {
+          GError *tmp_error =
+            g_error_new (G_IO_ERROR, G_IO_ERROR_FAILED,
+                         _("An error occurred during the XML exchange: %s (%d).\n "
+                           "The screenshot could not be uploaded."),
+                         env.fault_string, env.fault_code);
+
           xmlrpc_env_clean (&env);
           xmlrpc_client_cleanup ();
 
-          return NULL;
+          g_propagate_error (error, tmp_error);
+
+          return FALSE;
         }
 
-       if (!response_upload)
-         {
-           xfce_err (_("An error occurred while uploading the screenshot."));
+      if (!response_upload)
+        {
+          GError *tmp_error =
+            g_error_new (G_IO_ERROR, G_IO_ERROR_FAILED,
+                         _("An error occurred while uploading the screenshot."));
 
-           TRACE ("Error while uploading the screenshot.");
+          xmlrpc_env_clean (&env);
+          xmlrpc_client_cleanup ();
 
-           xmlrpc_env_clean (&env);
-           xmlrpc_client_cleanup ();
+          g_propagate_error (error, tmp_error);
 
-           return NULL;
-         }
+          return FALSE;
+        }
     }
   /* Else we get the file name */
   else
@@ -504,12 +551,20 @@
 
       TRACE ("The screenshot has been uploaded, get the file name.");
 
-      if (warn_if_fault_occurred (&env))
+      if (env.fault_occurred)
         {
+          GError *tmp_error =
+            g_error_new (G_IO_ERROR, G_IO_ERROR_FAILED,
+                         _("An error occurred during the XML exchange: %s (%d).\n "
+                           "The screenshot could not be uploaded."),
+                         env.fault_string, env.fault_code);
+
           xmlrpc_env_clean (&env);
           xmlrpc_client_cleanup ();
 
-          return NULL;
+          g_propagate_error (error, tmp_error);
+
+          return FALSE;
         }
     }
 
@@ -517,6 +572,8 @@
 
   /* End the user session */
 
+  exo_job_info_message (EXO_JOB (job), _("Close the session on ZimageZ.com..."));
+
   TRACE ("Closing the user session");
 
   xmlrpc_client_call (&env, serverurl, method_logout, "(s)", login_response);
@@ -525,29 +582,309 @@
   xmlrpc_env_clean (&env);
   xmlrpc_client_cleanup ();
 
-  return g_strdup (online_file_name);
+  screenshooter_job_image_uploaded (job, online_file_name);
+
+  return TRUE;
 }
 
 
 
-/**
- * screenshooter_display_zimagez_links:
- * @upload_name: the name of the image on ZimageZ.com
- *
- * Shows a dialog linking to the different images hosted on ZimageZ.com:
- * the full size image, the large thumbnail and the small thumbnail.
- * Links can be clicked to open the given page in a browser.
- **/
-void screenshooter_display_zimagez_links (const gchar *upload_name)
+static ScreenshooterJob
+*zimagez_upload_to_zimagez (const gchar *file_path)
 {
+  g_return_val_if_fail (file_path != NULL, NULL);
+
+  return screenshooter_simple_job_launch (zimagez_upload_job, 1,
+                                          G_TYPE_STRING, file_path);
+}
+
+
+
+static void
+cb_ask_for_information (ScreenshooterJob *job,
+                        GtkListStore     *liststore,
+                        const gchar      *message,
+                        gpointer          unused)
+{
   GtkWidget *dialog;
+  GtkWidget *information_label;
+  GtkWidget *vbox, *main_alignment;
+  GtkWidget *table;
+  GtkWidget *user_entry, *password_entry, *title_entry, *comment_entry;
+  GtkWidget *user_label, *password_label, *title_label, *comment_label;
+
+  GtkTreeIter iter;
+  gint response;
+
+  g_return_if_fail (SCREENSHOOTER_IS_JOB (job));
+  g_return_if_fail (GTK_IS_LIST_STORE (liststore));
+  g_return_if_fail (message != NULL);
+
+  TRACE ("Create the dialog to ask for user information.");
+
+  /* Create the information dialog */
+  dialog =
+    xfce_titled_dialog_new_with_buttons (_("Details about the screenshot for ZimageZ©"),
+                                         NULL,
+                                         GTK_DIALOG_NO_SEPARATOR,
+                                         GTK_STOCK_CANCEL,
+                                         GTK_RESPONSE_CANCEL,
+                                         GTK_STOCK_OK,
+                                         GTK_RESPONSE_OK,
+                                         NULL);
+
+  gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER);
+  gtk_box_set_spacing (GTK_BOX (GTK_DIALOG(dialog)->vbox), 12);
+
+  gtk_window_set_icon_name (GTK_WINDOW (dialog), "gtk-info");
+  gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
+
+  gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
+
+  /* Create the main alignment for the dialog */
+  main_alignment = gtk_alignment_new (0, 0, 1, 1);
+
+  gtk_alignment_set_padding (GTK_ALIGNMENT (main_alignment), 6, 0, 12, 12);
+  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), main_alignment, TRUE, TRUE, 0);
+
+  /* Create the main box for the dialog */
+  vbox = gtk_vbox_new (FALSE, 10);
+
+  gtk_container_set_border_width (GTK_CONTAINER (vbox), 12);
+  gtk_container_add (GTK_CONTAINER (main_alignment), vbox);
+
+  /* Create the information label */
+  information_label = sexy_url_label_new ();
+
+  sexy_url_label_set_markup (SEXY_URL_LABEL (information_label), message);
+
+  g_signal_connect_swapped (G_OBJECT (information_label), "url-activated",
+                            G_CALLBACK (open_zimagez_link), NULL);
+
+  gtk_misc_set_alignment (GTK_MISC (information_label), 0, 0);
+  gtk_container_add (GTK_CONTAINER (vbox), information_label);
+
+  /* Create the layout table */
+  table = gtk_table_new (4, 2, FALSE);
+
+  gtk_table_set_col_spacings (GTK_TABLE (table), 6);
+  gtk_table_set_row_spacings (GTK_TABLE (table), 12);
+
+  gtk_container_add (GTK_CONTAINER (vbox), table);
+
+  /* Create the user label */
+  user_label = gtk_label_new (_("User:"));
+
+  gtk_misc_set_alignment (GTK_MISC (user_label), 0, 0.5);
+
+  gtk_table_attach (GTK_TABLE (table), user_label,
+                    0, 1,
+                    0, 1,
+                    GTK_FILL, GTK_FILL,
+                    0, 0);
+
+  /* Create the user entry */
+  user_entry = gtk_entry_new ();
+
+  gtk_widget_set_tooltip_text (user_entry,
+                               _("Your Zimagez user name, if you do not have one yet"
+                                 "please create one on the Web page linked above"));
+
+
+  gtk_table_attach_defaults (GTK_TABLE (table), user_entry, 1, 2, 0, 1);
+
+  /* Create the password label */
+  password_label = gtk_label_new (_("Password:"));
+
+  gtk_misc_set_alignment (GTK_MISC (password_label), 0, 0.5);
+  gtk_table_attach (GTK_TABLE (table), password_label,
+                    0, 1,
+                    1, 2,
+                    GTK_FILL, GTK_FILL,
+                    0, 0);
+
+  /* Create the password entry */
+  password_entry = gtk_entry_new ();
+
+  gtk_widget_set_tooltip_text (password_entry, _("The password for the user above"));
+
+  gtk_entry_set_visibility (GTK_ENTRY (password_entry), FALSE);
+  gtk_table_attach_defaults (GTK_TABLE (table), password_entry, 1, 2, 1, 2);
+
+  /* Create the title label */
+  title_label = gtk_label_new (_("Title:"));
+
+  gtk_misc_set_alignment (GTK_MISC (title_label), 0, 0.5);
+  gtk_table_attach (GTK_TABLE (table), title_label,
+                    0, 1,
+                    2, 3,
+                    GTK_FILL, GTK_FILL,
+                    0, 0);
+
+  /* Create the title entry */
+  title_entry = gtk_entry_new ();
+
+  gtk_widget_set_tooltip_text (title_entry,
+                               _("The title of the screenshot, it will be used when"
+                                 " displaying the screenshot on ZimageZ"));
+
+  gtk_table_attach_defaults (GTK_TABLE (table), title_entry, 1, 2, 2, 3);
+
+  /* Create the comment label */
+  comment_label = gtk_label_new (_("Comment:"));
+
+  gtk_misc_set_alignment (GTK_MISC (comment_label), 0, 0.5);
+  gtk_table_attach (GTK_TABLE (table), comment_label,
+                    0, 1,
+                    3, 4,
+                    GTK_FILL, GTK_FILL,
+                    0, 0);
+
+  /* Create the comment entry */
+  comment_entry = gtk_entry_new ();
+
+  gtk_widget_set_tooltip_text (title_entry,
+                               _("A comment on the screenshot, it will be used when"
+                                 " displaying the screenshot on ZimageZ"));
+
+  gtk_table_attach_defaults (GTK_TABLE (table), comment_entry, 1, 2, 3, 4);
+
+  /* Set the values */
+  gtk_tree_model_get_iter_first (GTK_TREE_MODEL (liststore), &iter);
+
+  do
+    {
+      gchar *field_name = NULL;
+      gchar *field_value = NULL;
+
+      gtk_tree_model_get (GTK_TREE_MODEL (liststore), &iter,
+                          0, &field_name,
+                          1, &field_value,
+                          -1);
+
+      if (g_str_equal (field_name, "user"))
+        {
+          gtk_entry_set_text (GTK_ENTRY (user_entry), field_value);
+        }
+      else if (g_str_equal (field_name, "password"))
+        {
+          gtk_entry_set_text (GTK_ENTRY (password_entry), field_value);
+        }
+      else if (g_str_equal (field_name, "title"))
+        {
+          gtk_entry_set_text (GTK_ENTRY (title_entry), field_value);
+        }
+      else if (g_str_equal (field_name, "comment"))
+        {
+          gtk_entry_set_text (GTK_ENTRY (comment_entry), field_value);
+        }
+
+      g_free (field_name);
+      g_free (field_value);
+    }
+  while (gtk_tree_model_iter_next (GTK_TREE_MODEL (liststore), &iter));
+
+  gtk_widget_show_all (GTK_DIALOG(dialog)->vbox);
+
+  response = gtk_dialog_run (GTK_DIALOG (dialog));
+
+  gtk_widget_hide (dialog);
+
+  if (response == GTK_RESPONSE_CANCEL)
+    {
+      g_signal_handlers_disconnect_matched (job,
+                                            G_SIGNAL_MATCH_FUNC,
+                                            0, 0, NULL,
+                                            cb_image_uploaded,
+                                            NULL);
+    
+      g_signal_handlers_disconnect_matched (job,
+                                            G_SIGNAL_MATCH_FUNC,
+                                            0, 0, NULL,
+                                            cb_error,
+                                            NULL);
+    
+      g_signal_handlers_disconnect_matched (job,
+                                            G_SIGNAL_MATCH_FUNC,
+                                            0, 0, NULL,
+                                            cb_ask_for_information,
+                                            NULL);
+    
+      g_signal_handlers_disconnect_matched (job,
+                                            G_SIGNAL_MATCH_FUNC,
+                                            0, 0, NULL,
+                                            cb_update_info,
+                                            NULL);
+    
+      g_signal_handlers_disconnect_matched (job,
+                                            G_SIGNAL_MATCH_FUNC,
+                                            0, 0, NULL,
+                                            cb_finished,
+                                            NULL);
+
+      exo_job_cancel (EXO_JOB (job));
+    }
+  else if (response == GTK_RESPONSE_OK)
+    {
+      gtk_tree_model_get_iter_first (GTK_TREE_MODEL (liststore), &iter);
+
+      do
+        {
+          gchar *field_name = NULL;
+
+          gtk_tree_model_get (GTK_TREE_MODEL (liststore), &iter,
+                              0, &field_name, -1);
+
+          if (g_str_equal (field_name, "user"))
+            {
+              gtk_list_store_set (liststore, &iter,
+                                  1, gtk_entry_get_text (GTK_ENTRY (user_entry)),
+                                  -1);
+            }
+          else if (g_str_equal (field_name, "password"))
+            {
+              gtk_list_store_set (liststore, &iter,
+                                  1, gtk_entry_get_text (GTK_ENTRY (password_entry)),
+                                  -1);
+            }
+          else if (g_str_equal (field_name, "title"))
+            {
+              gtk_list_store_set (liststore, &iter,
+                                  1, gtk_entry_get_text (GTK_ENTRY (title_entry)),
+                                  -1);
+            }
+          else if (g_str_equal (field_name, "comment"))
+            {
+              gtk_list_store_set (liststore, &iter,
+                                  1, gtk_entry_get_text (GTK_ENTRY (comment_entry)),
+                                  -1);
+            }
+
+          g_free (field_name);
+        }
+      while (gtk_tree_model_iter_next (GTK_TREE_MODEL (liststore), &iter));
+    }
+
+  gtk_widget_destroy (dialog);
+}
+
+
+
+static void cb_image_uploaded (ScreenshooterJob *job, gchar *upload_name, gpointer unused)
+{
+  GtkWidget *dialog;
   GtkWidget *image_link, *thumbnail_link, *small_thumbnail_link;
 
-  gchar *image_url =
-    g_strdup_printf ("http://www.zimagez.com/zimage/%s.php", upload_name);
-  gchar *thumbnail_url =
+  gchar *image_url;
+  gchar *thumbnail_url;
+  gchar *small_thumbnail_url;
+
+  g_return_if_fail (upload_name != NULL);
+
+  image_url = g_strdup_printf ("http://www.zimagez.com/zimage/%s.php", upload_name);
+  thumbnail_url =
     g_strdup_printf ("http://www.zimagez.com/miniature/%s.php", upload_name);
-  gchar *small_thumbnail_url =
+  small_thumbnail_url =
     g_strdup_printf ("http://www.zimagez.com/avatar/%s.php", upload_name);
 
   dialog =
@@ -567,14 +904,12 @@
   gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
 
   /* Create the image link */
-
   image_link =
     gtk_link_button_new_with_label (image_url, _("Link to the full-size screenshot"));
 
   gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), image_link);
 
   /* Create the thumbnail link */
-
   thumbnail_link =
     gtk_link_button_new_with_label (thumbnail_url,
                                     _("Link to a thumbnail of the screenshot"));
@@ -582,7 +917,6 @@
   gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), thumbnail_link);
 
   /* Create the small thumbnail link */
-
   small_thumbnail_link =
     gtk_link_button_new_with_label (small_thumbnail_url,
                                     _("Link to a small thumbnail of the screenshot"));
@@ -590,7 +924,6 @@
   gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), small_thumbnail_link);
 
   /* Set the url hook for the buttons */
-
   gtk_link_button_set_uri_hook ((GtkLinkButtonUriFunc) open_url_hook, NULL, NULL);
 
   /* Show the dialog and run it */
@@ -600,13 +933,133 @@
 
   gtk_widget_destroy (dialog);
 
-  /* Ugly hack to make sure the dialog is not displayed anymore */
-  while (gtk_events_pending ())
-    gtk_main_iteration_do (FALSE);
-
   g_free (image_url);
   g_free (thumbnail_url);
   g_free (small_thumbnail_url);
 }
 
 
+
+static void cb_error (ExoJob *job, GError *error, gpointer unused)
+{
+  GtkWidget *dialog;
+
+  g_return_if_fail (error != NULL);
+
+  dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_NO_SEPARATOR | GTK_DIALOG_MODAL,
+                                   GTK_MESSAGE_ERROR,
+                                   GTK_BUTTONS_CLOSE,
+                                   "%s", error->message);
+
+  gtk_dialog_run (GTK_DIALOG (dialog));
+  gtk_widget_destroy (dialog);
+}
+
+
+
+static void cb_finished (ExoJob *job, GtkWidget *dialog)
+{
+  g_return_if_fail (EXO_IS_JOB (job));
+  g_return_if_fail (GTK_IS_DIALOG (dialog));
+
+  g_signal_handlers_disconnect_matched (job,
+                                        G_SIGNAL_MATCH_FUNC,
+                                        0, 0, NULL,
+                                        cb_image_uploaded,
+                                        NULL);
+
+  g_signal_handlers_disconnect_matched (job,
+                                        G_SIGNAL_MATCH_FUNC,
+                                        0, 0, NULL,
+                                        cb_error,
+                                        NULL);
+
+  g_signal_handlers_disconnect_matched (job,
+                                        G_SIGNAL_MATCH_FUNC,
+                                        0, 0, NULL,
+                                        cb_ask_for_information,
+                                        NULL);
+
+  g_signal_handlers_disconnect_matched (job,
+                                        G_SIGNAL_MATCH_FUNC,
+                                        0, 0, NULL,
+                                        cb_update_info,
+                                        NULL);
+
+  g_signal_handlers_disconnect_matched (job,
+                                        G_SIGNAL_MATCH_FUNC,
+                                        0, 0, NULL,
+                                        cb_finished,
+                                        NULL);
+
+  g_object_unref (G_OBJECT (job));
+
+  gtk_widget_destroy (dialog);
+
+  gtk_main_quit ();
+}
+
+
+
+static void cb_update_info (ExoJob *job, gchar *message, GtkWidget *label)
+{
+  g_return_if_fail (EXO_IS_JOB (job));
+  g_return_if_fail (GTK_IS_LABEL (label));
+
+  gtk_label_set_text (GTK_LABEL (label), message);
+}
+
+
+
+/* Public */
+
+
+
+/**
+ * screenshooter_upload_to_zimagez:
+ * @image_path: the local path of the image that should be uploaded to
+ * ZimageZ.com.
+ *
+ * Uploads the image whose path is @image_path: a dialog asks for the user
+ * login, password, a title for the image and a comment; then the image is
+ * uploaded. The dialog is shown again with a warning is the password did
+ * match the user name. The user can also cancel the upload procedure.
+ *
+ **/
+
+void screenshooter_upload_to_zimagez (const gchar *image_path)
+{
+  ScreenshooterJob *job;
+  GtkWidget *dialog = NULL;
+  GtkWidget *label;
+
+  g_return_if_fail (image_path != NULL);
+
+  dialog =
+    gtk_dialog_new_with_buttons (_("Uploading to ZimageZ..."),
+                                 NULL,
+                                 GTK_DIALOG_NO_SEPARATOR,
+                                 NULL);
+
+  gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER);
+  gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), 20);
+  gtk_box_set_spacing (GTK_BOX (GTK_DIALOG(dialog)->vbox), 12);
+  gtk_window_set_deletable (GTK_WINDOW (dialog), FALSE);
+  gtk_window_set_icon_name (GTK_WINDOW (dialog), "gtk-info");
+
+  label = gtk_label_new ("");
+  gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), label);
+  gtk_widget_show (label);
+
+  job = zimagez_upload_to_zimagez (image_path);
+
+  g_signal_connect (job, "ask", (GCallback) cb_ask_for_information, NULL);
+  g_signal_connect (job, "image-uploaded", (GCallback) cb_image_uploaded, NULL);
+  g_signal_connect (job, "error", (GCallback) cb_error, NULL);
+  g_signal_connect (job, "finished", (GCallback) cb_finished, dialog);
+  g_signal_connect (job, "info-message", (GCallback) cb_update_info, label);
+
+  gtk_widget_show (dialog);
+
+  gtk_main ();
+}

Modified: xfce4-screenshooter/trunk/lib/screenshooter-zimagez.h
===================================================================
--- xfce4-screenshooter/trunk/lib/screenshooter-zimagez.h	2009-05-15 06:58:00 UTC (rev 7339)
+++ xfce4-screenshooter/trunk/lib/screenshooter-zimagez.h	2009-05-15 16:23:26 UTC (rev 7340)
@@ -31,10 +31,11 @@
 #include <xmlrpc-c/client.h>
 
 #include "screenshooter-utils.h"
+#include "screenshooter-simple-job.h"
 #include "sexy-url-label.h"
 
 
-gchar *screenshooter_upload_to_zimagez     (const gchar *image_path);
-void   screenshooter_display_zimagez_links (const gchar *upload_name);
+void screenshooter_upload_to_zimagez (const gchar *image_path);
 
+
 #endif

Modified: xfce4-screenshooter/trunk/src/main.c
===================================================================
--- xfce4-screenshooter/trunk/src/main.c	2009-05-15 06:58:00 UTC (rev 7339)
+++ xfce4-screenshooter/trunk/src/main.c	2009-05-15 16:23:26 UTC (rev 7340)
@@ -22,6 +22,8 @@
 #endif
 
 #include "libscreenshooter.h"
+#include <glib.h>
+#include <stdlib.h>
 
 
 
@@ -194,7 +196,7 @@
 
 
 
-int main(int argc, char **argv)
+int main (int argc, char **argv)
 {
   GError *cli_error = NULL;
   GFile *default_save_dir;
@@ -214,14 +216,15 @@
           g_print (_("%s: %s\nTry %s --help to see a full list of"
                      " available command line options.\n"),
                    PACKAGE, cli_error->message, PACKAGE_NAME);
-				   
+
           g_error_free (cli_error);
-		  
-          return 1;
+
+          return EXIT_FAILURE;
         }
     }
 
-  g_thread_init (NULL);
+  if (!g_thread_supported ())
+    g_thread_init (NULL);
 
   /* Read the preferences */
 
@@ -235,7 +238,7 @@
   /* Check if the directory read from the preferences is valid */
 
   default_save_dir = g_file_new_for_uri (sd->screenshot_dir);
-  
+
   if (G_UNLIKELY (!g_file_query_exists (default_save_dir, NULL)))
     {
       g_free (sd->screenshot_dir);
@@ -249,8 +252,8 @@
   if (version)
     {
       g_print ("%s\n", PACKAGE_STRING);
-	  
-      return 0;
+
+      return EXIT_SUCCESS;
     }
 
   /* If a region cli option is given, take the screenshot accordingly.*/
@@ -269,7 +272,7 @@
         {
           sd->region = SELECT;
         }
-	  
+
       /* Wether to show the save dialog allowing to choose a filename
        * and a save location */
       no_save_dialog ? (sd->show_save_dialog = 0) : (sd->show_save_dialog = 1);
@@ -339,5 +342,7 @@
   g_free (sd->app);
   g_free (sd);
 
-  return 0;
+  TRACE ("Ciao");
+
+  return EXIT_SUCCESS;
 }




More information about the Goodies-commits mailing list