[byzanz] Rework API of ByzanzSession



commit 450c19eab8978cbd9d41dfff7f5874260ab64cd7
Author: Benjamin Otte <otte gnome org>
Date:   Sat Aug 22 00:53:21 2009 +0200

    Rework API of ByzanzSession
    
    - ByzanzSession is now a GObject
    - use notify signalling to update the state of the session. Gets rid of
      polling code
    - signal errors properly

 src/byzanzapplet.c  |  119 +++++++++------------
 src/byzanzsession.c |  296 +++++++++++++++++++++++++++++++++------------------
 src/byzanzsession.h |   48 ++++++++-
 src/record.c        |    2 +-
 4 files changed, 287 insertions(+), 178 deletions(-)
---
diff --git a/src/byzanzapplet.c b/src/byzanzapplet.c
index d6a5313..8c20cde 100644
--- a/src/byzanzapplet.c
+++ b/src/byzanzapplet.c
@@ -56,7 +56,7 @@ typedef struct {
 
 /*** PENDING RECORDING ***/
 
-static void G_GNUC_UNUSED
+static void
 byzanz_applet_show_error (AppletPrivate *priv, const char *error, const char *details, ...)
 {
   GtkWidget *dialog, *parent;
@@ -86,31 +86,31 @@ byzanz_applet_show_error (AppletPrivate *priv, const char *error, const char *de
 /*** APPLET ***/
 
 static gboolean
-byzanz_applet_is_recording (AppletPrivate *priv)
-{
-  return priv->destination != NULL;
-}
-
-static gboolean
 byzanz_applet_update (gpointer data)
 {
   AppletPrivate *priv = data;
 
-  if (byzanz_applet_is_recording (priv)) {
-    /* applet is still actively recording the screen */
-    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->button), TRUE);
-    gtk_image_set_from_icon_name (GTK_IMAGE (priv->image), 
-	GTK_STOCK_MEDIA_RECORD, GTK_ICON_SIZE_LARGE_TOOLBAR);
-    gtk_tooltips_set_tip (priv->tooltips, priv->button,
-	_("Stop current recording"),
-	NULL);
-  } else {
+  if (priv->rec == NULL) {
     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->button), FALSE);
     gtk_image_set_from_icon_name (GTK_IMAGE (priv->image), 
 	GTK_STOCK_MEDIA_RECORD, GTK_ICON_SIZE_LARGE_TOOLBAR);
     gtk_tooltips_set_tip (priv->tooltips, priv->button,
-	_("Start a new recording"),
-	NULL);
+	_("Start a new recording"), NULL);
+  } else {
+    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->button), TRUE);
+    if (byzanz_session_is_recording (priv->rec)) {
+      gtk_image_set_from_icon_name (GTK_IMAGE (priv->image), 
+          GTK_STOCK_MEDIA_STOP, GTK_ICON_SIZE_LARGE_TOOLBAR);
+      gtk_tooltips_set_tip (priv->tooltips, priv->button,
+          _("End current recording"), NULL);
+    } else if (byzanz_session_is_encoding (priv->rec)) {
+      gtk_image_set_from_icon_name (GTK_IMAGE (priv->image), 
+          GTK_STOCK_CANCEL, GTK_ICON_SIZE_LARGE_TOOLBAR);
+      gtk_tooltips_set_tip (priv->tooltips, priv->button,
+          _("Abort encoding process"), NULL);
+    } else {
+      g_assert_not_reached ();
+    }
   }
   
   return TRUE;
@@ -125,12 +125,31 @@ byzanz_applet_set_default_method (AppletPrivate *priv, int id)
     return;
 
   priv->method = id;
-  byzanz_applet_update (priv);
 
   panel_applet_gconf_set_string (priv->applet, "method", 
       byzanz_select_method_get_name (id), NULL);
 }
 
+static void
+byzanz_applet_session_notify (AppletPrivate *priv)
+{
+  const GError *error;
+
+  g_assert (priv->rec != NULL);
+
+  error = byzanz_session_get_error (priv->rec);
+  if (error) {
+    byzanz_applet_show_error (priv, error->message, NULL);
+    g_object_unref (priv->rec);
+    priv->rec = NULL;
+  } else if (!byzanz_session_is_encoding (priv->rec)) {
+    g_object_unref (priv->rec);
+    priv->rec = NULL;
+  }
+
+  byzanz_applet_update (priv);
+}
+
 static int method_response_codes[] = { GTK_RESPONSE_ACCEPT, GTK_RESPONSE_APPLY, GTK_RESPONSE_OK, GTK_RESPONSE_YES };
 
 static void
@@ -169,10 +188,7 @@ panel_applet_start_response (GtkWidget *dialog, int response, AppletPrivate *pri
     goto out2;
 
   priv->rec = byzanz_session_new (priv->destination, window, &area, TRUE, TRUE);
-  if (!priv->rec) {
-    g_file_delete (priv->destination, NULL, NULL);
-    goto out2;
-  }
+  g_signal_connect_swapped (priv->rec, "notify", G_CALLBACK (byzanz_applet_session_notify), priv);
   
   byzanz_session_start (priv->rec);
   return;
@@ -185,22 +201,17 @@ out2:
     g_object_unref (priv->destination);
     priv->destination = NULL;
   }
-  byzanz_applet_update (priv);
+  if (priv->rec)
+    byzanz_applet_session_notify (priv);
+  else
+    byzanz_applet_update (priv);
 }
 
 static void
 byzanz_applet_start_recording (AppletPrivate *priv)
 {
-  g_assert (!byzanz_applet_is_recording (priv));
-  
-  if (byzanz_applet_is_recording (priv))
+  if (priv->rec)
     goto out;
-  if (priv->rec) {
-    if (byzanz_session_is_active (priv->rec))
-      goto out;
-    byzanz_session_destroy (priv->rec);
-    priv->rec = NULL;
-  }
   
   if (priv->dialog == NULL) {
     char *uri;
@@ -242,42 +253,17 @@ out:
   byzanz_applet_update (priv);
 }
 
-static gboolean
-check_done_saving_cb (gpointer data)
-{
-  AppletPrivate *priv = data;
-
-  if (byzanz_session_is_active (priv->rec))
-    return TRUE;
-  byzanz_session_destroy (priv->rec);
-  priv->rec = NULL;
-
-  g_object_unref (priv->destination);
-  priv->destination = NULL;
-
-  byzanz_applet_update (priv);
-
-  return FALSE;
-}
-
-static void
-byzanz_applet_stop_recording (AppletPrivate *priv)
-{
-  g_assert (byzanz_applet_is_recording (priv));
-  
-  byzanz_session_stop (priv->rec);
-  byzanz_applet_update (priv);
-  gdk_threads_add_timeout_seconds (1, check_done_saving_cb, priv);
-}
-
 static void
 button_clicked_cb (GtkToggleButton *button, AppletPrivate *priv)
 {
   gboolean active = gtk_toggle_button_get_active (button);
   
-  if (byzanz_applet_is_recording (priv) && !active) {
-    byzanz_applet_stop_recording (priv);
-  } else if (!byzanz_applet_is_recording (priv) && active) {
+  if (priv->rec && !active) {
+    if (byzanz_session_is_recording (priv->rec))
+      byzanz_session_stop (priv->rec);
+    else
+      byzanz_session_abort (priv->rec);
+  } else if (priv->rec == NULL && active) {
     byzanz_applet_start_recording (priv);
   }
 }
@@ -285,9 +271,8 @@ button_clicked_cb (GtkToggleButton *button, AppletPrivate *priv)
 static void
 destroy_applet (GtkWidget *widget, AppletPrivate *priv)
 {
-  if (byzanz_applet_is_recording (priv))
-    byzanz_applet_stop_recording (priv);
-  g_assert (!priv->rec); 
+  if (priv->rec)
+    g_object_unref (priv->rec);
   g_free (priv);
 }
 
diff --git a/src/byzanzsession.c b/src/byzanzsession.c
index fba9aa0..2d4010e 100644
--- a/src/byzanzsession.c
+++ b/src/byzanzsession.c
@@ -41,13 +41,6 @@
 #include "gifenc.h"
 
 typedef enum {
-  SESSION_STATE_ERROR,
-  SESSION_STATE_CREATED,
-  SESSION_STATE_RECORDING,
-  SESSION_STATE_STOPPED
-} SessionState;
-
-typedef enum {
   SESSION_JOB_QUIT,
   SESSION_JOB_ENCODE,
 } SessionJobType;
@@ -59,27 +52,6 @@ typedef struct {
   GdkRegion *		region;		/* relevant region of image */
 } SessionJob;
 
-struct _ByzanzSession {
-  /*< private >*/
-  /* set by user - accessed ALSO by thread */
-  gboolean		loop;		/* wether the resulting gif should loop */
-  guint			frame_duration;	/* minimum frame duration in msecs */
-  /* state */
-  SessionState		state;		/* state the session is in */
-  ByzanzRecorder *      recorder;       /* the recorder in use */
-  GThread *		encoder;	/* encoding thread */
-  /* accessed ALSO by thread */
-  gint			encoder_running;/* TRUE while the encoder is running */
-  GAsyncQueue *		jobs;		/* jobs the encoding thread has to do */
-  /* accessed ONLY by thread */
-  GOutputStream *       stream;         /* stream we write to */
-  Gifenc *		gifenc;		/* encoder used to encode the image */
-  GTimeVal		current;	/* timestamp of last encoded picture */
-  guint8 *		data;		/* data used to hold palettized data */
-  guint8 *		data_full;    	/* palettized data of full image to compare additions to */
-  GdkRectangle		relevant_data;	/* relevant area to encode */
-};
-
 /*** JOB FUNCTIONS ***/
 
 static void
@@ -221,6 +193,21 @@ byzanz_session_encode (ByzanzSession *rec, cairo_surface_t *image, GdkRegion *re
   byzanz_session_dither_region (rec, region, image);
 }
 
+static gboolean
+encoding_finished (gpointer data)
+{
+  ByzanzSession *session = data;
+
+  if (g_thread_join (session->encoder) != session)
+    g_assert_not_reached ();
+  session->encoder = NULL;
+  g_object_unref (session);
+
+  g_object_notify (data, "encoding");
+
+  return FALSE;
+}
+
 static gpointer
 byzanz_session_run_encoder (gpointer data)
 {
@@ -253,38 +240,157 @@ byzanz_session_run_encoder (gpointer data)
     session_job_free (job);
   }
   
-  byzanz_session_add_image (rec, &quit_tv);
-  gifenc_close (rec->gifenc, NULL);
+  if (has_quantized) {
+    byzanz_session_add_image (rec, &quit_tv);
+    gifenc_close (rec->gifenc, NULL);
+  }
 
   g_free (rec->data);
   rec->data = NULL;
   g_free (rec->data_full);
   rec->data_full = NULL;
-  g_atomic_int_add (&rec->encoder_running, -1);
 
+  g_idle_add (encoding_finished, rec);
   return rec;
 }
 
 /*** MAIN FUNCTIONS ***/
 
+enum {
+  PROP_0,
+  PROP_RECORDING,
+  PROP_ENCODING,
+  PROP_ERROR
+};
+
+G_DEFINE_TYPE (ByzanzSession, byzanz_session, G_TYPE_OBJECT)
+
 static void
-byzanz_session_state_advance (ByzanzSession *session)
+byzanz_session_get_property (GObject *object, guint param_id, GValue *value, 
+    GParamSpec * pspec)
 {
-  switch (session->state) {
-    case SESSION_STATE_CREATED:
-      byzanz_session_start (session);
+  ByzanzSession *session = BYZANZ_SESSION (object);
+
+  switch (param_id) {
+    case PROP_ERROR:
+      g_value_set_pointer (value, session->error);
+      break;
+    case PROP_RECORDING:
+      g_value_set_boolean (value, byzanz_session_is_recording (session));
       break;
-    case SESSION_STATE_RECORDING:
-      byzanz_session_stop (session);
+    case PROP_ENCODING:
+      g_value_set_boolean (value, byzanz_session_is_encoding (session));
       break;
-    case SESSION_STATE_STOPPED:
-    case SESSION_STATE_ERROR:
     default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
       break;
   }
 }
 
 static void
+byzanz_session_set_property (GObject *object, guint param_id, const GValue *value, 
+    GParamSpec * pspec)
+{
+  //ByzanzSession *session = BYZANZ_SESSION (object);
+
+  switch (param_id) {
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+      break;
+  }
+}
+
+static void
+byzanz_session_dispose (GObject *object)
+{
+  ByzanzSession *session = BYZANZ_SESSION (object);
+
+  if (byzanz_recorder_get_recording (session->recorder)) {
+    byzanz_session_stop (session);
+    return;
+  }
+
+  G_OBJECT_CLASS (byzanz_session_parent_class)->dispose (object);
+}
+
+static void
+byzanz_session_finalize (GObject *object)
+{
+  ByzanzSession *session = BYZANZ_SESSION (object);
+
+  g_assert (session->encoder == NULL);
+
+  gifenc_free (session->gifenc);
+  g_object_unref (session->recorder);
+  g_object_unref (session->stream);
+
+  g_assert (g_async_queue_length (session->jobs) == 0);
+  g_async_queue_unref (session->jobs);
+
+  if (session->error)
+    g_error_free (session->error);
+
+  G_OBJECT_CLASS (byzanz_session_parent_class)->finalize (object);
+}
+
+#if 0
+static void
+byzanz_session_set_error (ByzanzSession *session, const GError *error)
+{
+  GObject *object = G_OBJECT (session);
+
+  if (session->error != NULL)
+    return;
+
+  session->error = g_error_copy (error);
+  g_object_freeze_notify (object);
+  g_object_notify (object, "error");
+  if (session->encoder != NULL)
+    g_object_notify (object, "encoding");
+  if (byzanz_recorder_get_recording (session->recorder))
+    byzanz_session_stop (session);
+  g_object_thaw_notify (object);
+}
+#endif
+
+static void
+byzanz_session_constructed (GObject *object)
+{
+  //ByzanzSession *session = BYZANZ_SESSION (object);
+
+  if (G_OBJECT_CLASS (byzanz_session_parent_class)->constructed)
+    G_OBJECT_CLASS (byzanz_session_parent_class)->constructed (object);
+}
+
+static void
+byzanz_session_class_init (ByzanzSessionClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->get_property = byzanz_session_get_property;
+  object_class->set_property = byzanz_session_set_property;
+  object_class->dispose = byzanz_session_dispose;
+  object_class->finalize = byzanz_session_finalize;
+  object_class->constructed = byzanz_session_constructed;
+
+  g_object_class_install_property (object_class, PROP_ERROR,
+      g_param_spec_pointer ("error", "error", "error that happened on the thread",
+	  G_PARAM_READABLE));
+  g_object_class_install_property (object_class, PROP_RECORDING,
+      g_param_spec_boolean ("recording", "recording", "TRUE while the recorder is running",
+	  FALSE, G_PARAM_READABLE));
+  g_object_class_install_property (object_class, PROP_ENCODING,
+      g_param_spec_boolean ("encoding", "encoding", "TRUE while the encoder is running",
+	  TRUE, G_PARAM_READABLE));
+}
+
+static void
+byzanz_session_init (ByzanzSession *session)
+{
+  session->jobs = g_async_queue_new ();
+}
+
+static void
 byzanz_session_recorder_image_cb (ByzanzRecorder *  recorder,
                                   cairo_surface_t * surface,
                                   const GdkRegion * region,
@@ -300,7 +406,7 @@ session_gifenc_write (gpointer closure, const guchar *data, gsize len, GError **
 {
   ByzanzSession *session = closure;
 
-  return g_output_stream_write_all (session->stream, data, len, NULL, NULL, error);
+  return g_output_stream_write_all (session->stream, data, len, NULL, session->cancellable, error);
 }
 
 /**
@@ -333,19 +439,16 @@ byzanz_session_new (GFile *destination, GdkWindow *window, GdkRectangle *area,
   g_return_val_if_fail (area->width > 0, NULL);
   g_return_val_if_fail (area->height > 0, NULL);
   
-  session = g_new0 (ByzanzSession, 1);
+  session = g_object_new (BYZANZ_TYPE_SESSION, NULL);
 
   /* set user properties */
   session->loop = loop;
-  session->frame_duration = 1000 / 25;
   
   /* open file for writing */
   session->stream = G_OUTPUT_STREAM (g_file_replace (destination, NULL, 
-        FALSE, G_FILE_CREATE_REPLACE_DESTINATION, NULL, NULL));
-  if (session->stream == NULL) {
-    g_free (session);
-    return NULL;
-  }
+        FALSE, G_FILE_CREATE_REPLACE_DESTINATION, session->cancellable, &session->error));
+  if (session->stream == NULL)
+    return session;
 
   /* prepare thread first, so we can easily error out on failure */
   root_rect.x = root_rect.y = 0;
@@ -354,97 +457,78 @@ byzanz_session_new (GFile *destination, GdkWindow *window, GdkRectangle *area,
   gdk_rectangle_intersect (area, &root_rect, &root_rect);
   session->gifenc = gifenc_new (root_rect.width, root_rect.height, 
       session_gifenc_write, session, NULL);
-  if (!session->gifenc) {
-    g_object_unref (session->stream);
-    g_free (session);
-    return NULL;
-  }
-  session->jobs = g_async_queue_new ();
-  session->encoder_running = 1;
+
   session->encoder = g_thread_create (byzanz_session_run_encoder, session, 
-      TRUE, NULL);
-  if (!session->encoder) {
-    gifenc_free (session->gifenc);
-    g_async_queue_unref (session->jobs);
-    g_free (session);
-    return NULL;
-  }
+      TRUE, &session->error);
+  if (!session->encoder)
+    return session;
 
   session->recorder = byzanz_recorder_new (window, &root_rect);
   g_signal_connect (session->recorder, "image", 
       G_CALLBACK (byzanz_session_recorder_image_cb), session);
 
-  session->state = SESSION_STATE_CREATED;
   return session;
 }
 
 void
-byzanz_session_start (ByzanzSession *rec)
+byzanz_session_start (ByzanzSession *session)
 {
-  g_return_if_fail (BYZANZ_IS_SESSION (rec));
-  g_return_if_fail (rec->state == SESSION_STATE_CREATED);
+  g_return_if_fail (BYZANZ_IS_SESSION (session));
 
-  byzanz_recorder_set_recording (rec->recorder, TRUE);
-  
-  rec->state = SESSION_STATE_RECORDING;
+  byzanz_recorder_set_recording (session->recorder, TRUE);
+  g_object_notify (G_OBJECT (session), "recording");
 }
 
 void
-byzanz_session_stop (ByzanzSession *rec)
+byzanz_session_stop (ByzanzSession *session)
 {
   GTimeVal tv;
   SessionJob *job;
 
-  g_return_if_fail (BYZANZ_IS_SESSION (rec));
-  g_return_if_fail (rec->state == SESSION_STATE_RECORDING);
+  g_return_if_fail (BYZANZ_IS_SESSION (session));
+
+  g_object_ref (session);
 
-  /* byzanz_session_queue_image (rec); - useless because last image would have a 0 time */
+  /* byzanz_session_queue_image (session); - useless because last image would have a 0 time */
   g_get_current_time (&tv);
-  job = session_job_new (rec, SESSION_JOB_QUIT, NULL, &tv, NULL);
-  g_async_queue_push (rec->jobs, job);
+  job = session_job_new (session, SESSION_JOB_QUIT, NULL, &tv, NULL);
+  g_async_queue_push (session->jobs, job);
   
-  byzanz_recorder_set_recording (rec->recorder, FALSE);
-
-  rec->state = SESSION_STATE_STOPPED;
+  byzanz_recorder_set_recording (session->recorder, FALSE);
+  g_object_notify (G_OBJECT (session), "recording");
 }
 
 void
-byzanz_session_destroy (ByzanzSession *rec)
+byzanz_session_abort (ByzanzSession *session)
 {
-  g_return_if_fail (BYZANZ_IS_SESSION (rec));
-
-  while (rec->state != SESSION_STATE_ERROR &&
-         rec->state != SESSION_STATE_STOPPED)
-    byzanz_session_state_advance (rec);
+  g_return_if_fail (BYZANZ_IS_SESSION (session));
 
-  if (g_thread_join (rec->encoder) != rec)
-    g_assert_not_reached ();
+  g_cancellable_cancel (session->cancellable);
+}
 
-  gifenc_free (rec->gifenc);
-  g_object_unref (rec->recorder);
-  g_object_unref (rec->stream);
+gboolean
+byzanz_session_is_recording (ByzanzSession *session)
+{
+  g_return_val_if_fail (BYZANZ_IS_SESSION (session), FALSE);
 
-  g_assert (g_async_queue_length (rec->jobs) == 0);
-  g_async_queue_unref (rec->jobs);
-  
-  g_free (rec);
+  return session->error == NULL &&
+    byzanz_recorder_get_recording (session->recorder);
 }
 
-/**
- * byzanz_session_is_active:
- * @session: ia recording session
- *
- * Checks if the session is currently running or - after being stopped - if 
- * the encoder is still actively processing cached data.
- * Note that byzanz_session_destroy() will block until all cached data has been 
- * processed, so it might take a long time.
- *
- * Returns: TRUE if the recording session is still active.
- **/
 gboolean
-byzanz_session_is_active (ByzanzSession *session)
+byzanz_session_is_encoding (ByzanzSession *session)
 {
-  g_return_val_if_fail (BYZANZ_IS_SESSION (session), 0);
+  g_return_val_if_fail (BYZANZ_IS_SESSION (session), FALSE);
+
+  return session->error == NULL &&
+    session->encoder != NULL;
+}
+
+const GError *
+byzanz_session_get_error (ByzanzSession *session)
+{
+  g_return_val_if_fail (BYZANZ_IS_SESSION (session), NULL);
   
-  return g_atomic_int_get (&session->encoder_running) > 0;
+  return session->error;
 }
+
diff --git a/src/byzanzsession.h b/src/byzanzsession.h
index 212c2db..9cc1830 100644
--- a/src/byzanzsession.h
+++ b/src/byzanzsession.h
@@ -1,5 +1,5 @@
 /* desktop session recorder
- * Copyright (C) 2005 Benjamin Otte <otte gnome org
+ * Copyright (C) 2005,2009 Benjamin Otte <otte gnome org
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
@@ -20,11 +20,48 @@
 #include <glib.h>
 #include <gtk/gtk.h>
 
+#include "byzanzrecorder.h"
+#include "gifenc.h"
+
 #ifndef __HAVE_BYZANZ_SESSION_H__
 #define __HAVE_BYZANZ_SESSION_H__
 
 typedef struct _ByzanzSession ByzanzSession;
-#define BYZANZ_IS_SESSION(obj) ((obj) != NULL)
+typedef struct _ByzanzSessionClass ByzanzSessionClass;
+
+#define BYZANZ_TYPE_SESSION                    (byzanz_session_get_type())
+#define BYZANZ_IS_SESSION(obj)                 (G_TYPE_CHECK_INSTANCE_TYPE ((obj), BYZANZ_TYPE_SESSION))
+#define BYZANZ_IS_SESSION_CLASS(klass)         (G_TYPE_CHECK_CLASS_TYPE ((klass), BYZANZ_TYPE_SESSION))
+#define BYZANZ_SESSION(obj)                    (G_TYPE_CHECK_INSTANCE_CAST ((obj), BYZANZ_TYPE_SESSION, ByzanzSession))
+#define BYZANZ_SESSION_CLASS(klass)            (G_TYPE_CHECK_CLASS_CAST ((klass), BYZANZ_TYPE_SESSION, ByzanzSessionClass))
+#define BYZANZ_SESSION_GET_CLASS(obj)          (G_TYPE_INSTANCE_GET_CLASS ((obj), BYZANZ_TYPE_SESSION, ByzanzSessionClass))
+
+struct _ByzanzSession {
+  GObject		object;
+  
+  /* set by user - accessed ALSO by thread */
+  gboolean		loop;		/* wether the resulting gif should loop */
+  ByzanzRecorder *      recorder;       /* the recorder in use */
+  GThread *		encoder;	/* encoding thread */
+  GError *              error;          /* NULL or the recording error */
+  GCancellable *        cancellable;    /* cancellable to use for aborting the session */
+  /* accessed ALSO by thread */
+  GAsyncQueue *		jobs;		/* jobs the encoding thread has to do */
+  /* accessed ONLY by thread */
+  GOutputStream *       stream;         /* stream we write to */
+  Gifenc *		gifenc;		/* encoder used to encode the image */
+  GTimeVal		current;	/* timestamp of last encoded picture */
+  guint8 *		data;		/* data used to hold palettized data */
+  guint8 *		data_full;    	/* palettized data of full image to compare additions to */
+  GdkRectangle		relevant_data;	/* relevant area to encode */
+};
+
+struct _ByzanzSessionClass {
+  GObjectClass		object_class;
+};
+
+GType		        byzanz_session_get_type		(void) G_GNUC_CONST;
+
 
 ByzanzSession * 	byzanz_session_new		(GFile *                destination,
 							 GdkWindow *		window,
@@ -33,8 +70,11 @@ ByzanzSession * 	byzanz_session_new		(GFile *                destination,
 							 gboolean		record_cursor);
 void			byzanz_session_start		(ByzanzSession *	session);
 void			byzanz_session_stop		(ByzanzSession *	session);
-void			byzanz_session_destroy		(ByzanzSession *	session);
-gboolean		byzanz_session_is_active	(ByzanzSession *	session);
+void			byzanz_session_abort            (ByzanzSession *	session);
+
+gboolean                byzanz_session_is_recording     (ByzanzSession *        session);
+gboolean                byzanz_session_is_encoding      (ByzanzSession *        session);
+const GError *          byzanz_session_get_error        (ByzanzSession *        session);
 					
 
 #endif /* __HAVE_BYZANZ_SESSION_H__ */
diff --git a/src/record.c b/src/record.c
index a585bc8..f8fecfa 100644
--- a/src/record.c
+++ b/src/record.c
@@ -139,6 +139,6 @@ main (int argc, char **argv)
   
   gtk_main ();
 
-  byzanz_session_destroy (rec);
+  g_object_unref (rec);
   return 0;
 }



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