Updated Spanish translation
[evolution.git] / e-util / e-data-capture.c
blobf51e682f0743e904ae4c299681b03b309be2429f
1 /*
2 * e-data-capture.c
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
11 * for more details.
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program; if not, see <http://www.gnu.org/licenses/>.
18 /**
19 * SECTION: e-data-capture
20 * @include: e-util/e-util.h
21 * @short_description: Capture data from streams
23 * #EDataCapture is a #GConverter that captures data until the end of
24 * the input data is seen, then emits a #EDataCapture:finished signal
25 * with the captured data in a #GBytes instance.
27 * When used with #GConverterInputStream or #GConverterOutputStream,
28 * an #EDataCapture can discreetly capture the stream content for the
29 * purpose of caching.
30 **/
32 #include "e-data-capture.h"
34 #include <string.h>
36 #define E_DATA_CAPTURE_GET_PRIVATE(obj) \
37 (G_TYPE_INSTANCE_GET_PRIVATE \
38 ((obj), E_TYPE_DATA_CAPTURE, EDataCapturePrivate))
40 typedef struct _SignalClosure SignalClosure;
42 struct _EDataCapturePrivate {
43 GMainContext *main_context;
44 GByteArray *byte_array;
45 GMutex byte_array_lock;
48 struct _SignalClosure {
49 GWeakRef data_capture;
50 GBytes *data;
53 enum {
54 PROP_0,
55 PROP_MAIN_CONTEXT
58 enum {
59 FINISHED,
60 LAST_SIGNAL
63 static guint signals[LAST_SIGNAL];
65 /* Forward Declarations */
66 static void e_data_capture_converter_init (GConverterIface *iface);
68 G_DEFINE_TYPE_WITH_CODE (
69 EDataCapture,
70 e_data_capture,
71 G_TYPE_OBJECT,
72 G_IMPLEMENT_INTERFACE (
73 G_TYPE_CONVERTER,
74 e_data_capture_converter_init))
76 static void
77 signal_closure_free (SignalClosure *signal_closure)
79 g_weak_ref_set (&signal_closure->data_capture, NULL);
80 g_bytes_unref (signal_closure->data);
82 g_slice_free (SignalClosure, signal_closure);
85 static gboolean
86 data_capture_emit_finished_idle_cb (gpointer user_data)
88 SignalClosure *signal_closure = user_data;
89 EDataCapture *data_capture;
91 data_capture = g_weak_ref_get (&signal_closure->data_capture);
93 if (data_capture != NULL) {
94 g_signal_emit (
95 data_capture,
96 signals[FINISHED], 0,
97 signal_closure->data);
98 g_object_unref (data_capture);
101 return FALSE;
104 static void
105 data_capture_set_main_context (EDataCapture *data_capture,
106 GMainContext *main_context)
108 g_return_if_fail (data_capture->priv->main_context == NULL);
110 if (main_context != NULL)
111 g_main_context_ref (main_context);
112 else
113 main_context = g_main_context_ref_thread_default ();
115 data_capture->priv->main_context = main_context;
118 static void
119 data_capture_set_property (GObject *object,
120 guint property_id,
121 const GValue *value,
122 GParamSpec *pspec)
124 switch (property_id) {
125 case PROP_MAIN_CONTEXT:
126 data_capture_set_main_context (
127 E_DATA_CAPTURE (object),
128 g_value_get_boxed (value));
129 return;
132 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
135 static void
136 data_capture_get_property (GObject *object,
137 guint property_id,
138 GValue *value,
139 GParamSpec *pspec)
141 switch (property_id) {
142 case PROP_MAIN_CONTEXT:
143 g_value_take_boxed (
144 value,
145 e_data_capture_ref_main_context (
146 E_DATA_CAPTURE (object)));
147 return;
150 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
153 static void
154 data_capture_finalize (GObject *object)
156 EDataCapturePrivate *priv;
158 priv = E_DATA_CAPTURE_GET_PRIVATE (object);
160 g_main_context_unref (priv->main_context);
162 g_byte_array_free (priv->byte_array, TRUE);
163 g_mutex_clear (&priv->byte_array_lock);
165 /* Chain up to parent's finalize() method. */
166 G_OBJECT_CLASS (e_data_capture_parent_class)->finalize (object);
169 static GConverterResult
170 data_capture_convert (GConverter *converter,
171 gconstpointer inbuf,
172 gsize inbuf_size,
173 gpointer outbuf,
174 gsize outbuf_size,
175 GConverterFlags flags,
176 gsize *bytes_read,
177 gsize *bytes_written,
178 GError **error)
180 EDataCapture *data_capture;
181 GConverterResult result;
183 data_capture = E_DATA_CAPTURE (converter);
185 /* Output buffer needs to be at least as large as the input buffer.
186 * The error message should never make it to the user interface so
187 * no need to translate. */
188 if (outbuf_size < inbuf_size) {
189 g_set_error_literal (
190 error, G_IO_ERROR,
191 G_IO_ERROR_NO_SPACE,
192 "EDataCapture needs more space");
193 return G_CONVERTER_ERROR;
196 memcpy (outbuf, inbuf, inbuf_size);
197 *bytes_read = *bytes_written = inbuf_size;
199 g_mutex_lock (&data_capture->priv->byte_array_lock);
201 g_byte_array_append (
202 data_capture->priv->byte_array, inbuf, inbuf_size);
204 if ((flags & G_CONVERTER_INPUT_AT_END) != 0) {
205 GSource *idle_source;
206 GMainContext *main_context;
207 SignalClosure *signal_closure;
209 signal_closure = g_slice_new0 (SignalClosure);
210 g_weak_ref_set (&signal_closure->data_capture, data_capture);
211 signal_closure->data = g_bytes_new (
212 data_capture->priv->byte_array->data,
213 data_capture->priv->byte_array->len);
215 main_context = e_data_capture_ref_main_context (data_capture);
217 idle_source = g_idle_source_new ();
218 g_source_set_callback (
219 idle_source,
220 data_capture_emit_finished_idle_cb,
221 signal_closure,
222 (GDestroyNotify) signal_closure_free);
223 g_source_set_priority (idle_source, G_PRIORITY_HIGH_IDLE);
224 g_source_attach (idle_source, main_context);
225 g_source_unref (idle_source);
227 g_main_context_unref (main_context);
230 g_mutex_unlock (&data_capture->priv->byte_array_lock);
232 if ((flags & G_CONVERTER_INPUT_AT_END) != 0)
233 result = G_CONVERTER_FINISHED;
234 else if ((flags & G_CONVERTER_FLUSH) != 0)
235 result = G_CONVERTER_FLUSHED;
236 else
237 result = G_CONVERTER_CONVERTED;
239 return result;
242 static void
243 data_capture_reset (GConverter *converter)
245 EDataCapture *data_capture;
247 data_capture = E_DATA_CAPTURE (converter);
249 g_mutex_lock (&data_capture->priv->byte_array_lock);
251 g_byte_array_set_size (data_capture->priv->byte_array, 0);
253 g_mutex_unlock (&data_capture->priv->byte_array_lock);
256 static void
257 e_data_capture_class_init (EDataCaptureClass *class)
259 GObjectClass *object_class;
261 g_type_class_add_private (class, sizeof (EDataCapturePrivate));
263 object_class = G_OBJECT_CLASS (class);
264 object_class->set_property = data_capture_set_property;
265 object_class->get_property = data_capture_get_property;
266 object_class->finalize = data_capture_finalize;
269 * EDataCapture:main-context:
271 * The #GMainContext from which to emit the #EDataCapture::finished
272 * signal.
274 g_object_class_install_property (
275 object_class,
276 PROP_MAIN_CONTEXT,
277 g_param_spec_boxed (
278 "main-context",
279 "Main Context",
280 "The main loop context from "
281 "which to emit the 'finished' signal",
282 G_TYPE_MAIN_CONTEXT,
283 G_PARAM_READWRITE |
284 G_PARAM_CONSTRUCT_ONLY |
285 G_PARAM_STATIC_STRINGS));
288 * EDataCapture::finished:
289 * @data_capture: the #EDataCapture that received the signal
290 * @data: the captured data
292 * The ::finished signal is emitted when there is no more input
293 * data to be captured.
295 signals[FINISHED] = g_signal_new (
296 "finished",
297 G_TYPE_FROM_CLASS (class),
298 G_SIGNAL_RUN_FIRST,
299 G_STRUCT_OFFSET (EDataCaptureClass, finished),
300 NULL, NULL, NULL,
301 G_TYPE_NONE, 1,
302 G_TYPE_BYTES);
305 static void
306 e_data_capture_converter_init (GConverterIface *iface)
308 iface->convert = data_capture_convert;
309 iface->reset = data_capture_reset;
312 static void
313 e_data_capture_init (EDataCapture *data_capture)
315 data_capture->priv = E_DATA_CAPTURE_GET_PRIVATE (data_capture);
317 data_capture->priv->byte_array = g_byte_array_new ();
318 g_mutex_init (&data_capture->priv->byte_array_lock);
322 * e_data_capture_new:
323 * @main_context: a #GMainContext, or %NULL
325 * Creates a new #EDataCapture. If @main_context is %NULL, then the
326 * #EDataCapture:finished signal will be emitted from the thread-default
327 * #GMainContext for this thread.
329 * Returns: an #EDataCapture
331 EDataCapture *
332 e_data_capture_new (GMainContext *main_context)
334 return g_object_new (
335 E_TYPE_DATA_CAPTURE,
336 "main-context", main_context, NULL);
340 * e_data_capture_ref_main_context:
341 * @data_capture: an #EDataCapture
343 * Returns the #GMainContext from which the #EDataCapture:finished signal
344 * is emitted.
346 * The returned #GMainContext is referenced for thread-safety and must be
347 * unreferenced with g_main_context_unref() when finished with it.
349 * Returns: a #GMainContext
351 GMainContext *
352 e_data_capture_ref_main_context (EDataCapture *data_capture)
354 g_return_val_if_fail (E_IS_DATA_CAPTURE (data_capture), NULL);
356 return g_main_context_ref (data_capture->priv->main_context);