]> www.fi.muni.cz Git - evince.git/blob - libdocument/ev-attachment.c
[dualscreen] fix crash on ctrl+w and fix control window closing
[evince.git] / libdocument / ev-attachment.c
1 /* this file is part of evince, a gnome document viewer
2  *
3  *  Copyright (C) 2006 Carlos Garcia Campos <carlosgc@gnome.org>
4  *
5  * Evince is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * Evince is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18  */
19
20 #include <config.h>
21 #include <glib/gi18n-lib.h>
22 #include <glib/gstdio.h>
23 #include <gtk/gtk.h>
24 #include "ev-file-helpers.h"
25 #include "ev-attachment.h"
26
27 enum
28 {
29         PROP_0,
30         PROP_NAME,
31         PROP_DESCRIPTION,
32         PROP_MTIME,
33         PROP_CTIME,
34         PROP_SIZE,
35         PROP_DATA
36 };
37
38 struct _EvAttachmentPrivate {
39         gchar                   *name;
40         gchar                   *description;
41         GTime                    mtime;
42         GTime                    ctime;
43         gsize                    size;
44         gchar                   *data;
45         gchar                   *mime_type;
46
47         GAppInfo                *app;
48         GFile                   *tmp_file;
49 };
50
51 #define EV_ATTACHMENT_GET_PRIVATE(object) \
52                 (G_TYPE_INSTANCE_GET_PRIVATE ((object), EV_TYPE_ATTACHMENT, EvAttachmentPrivate))
53
54 G_DEFINE_TYPE (EvAttachment, ev_attachment, G_TYPE_OBJECT)
55
56 GQuark
57 ev_attachment_error_quark (void)
58 {
59         static GQuark error_quark = 0;
60         
61         if (error_quark == 0)
62                 error_quark =
63                         g_quark_from_static_string ("ev-attachment-error-quark");
64         
65         return error_quark;
66 }
67
68 static void
69 ev_attachment_finalize (GObject *object)
70 {
71         EvAttachment *attachment = EV_ATTACHMENT (object);
72
73         if (attachment->priv->name) {
74                 g_free (attachment->priv->name);
75                 attachment->priv->name = NULL;
76         }
77
78         if (attachment->priv->description) {
79                 g_free (attachment->priv->description);
80                 attachment->priv->description = NULL;
81         }
82
83         if (attachment->priv->data) {
84                 g_free (attachment->priv->data);
85                 attachment->priv->data = NULL;
86         }
87
88         if (attachment->priv->mime_type) {
89                 g_free (attachment->priv->mime_type);
90                 attachment->priv->mime_type = NULL;
91         }
92
93         if (attachment->priv->app) {
94                 g_object_unref (attachment->priv->app);
95                 attachment->priv->app = NULL;
96         }
97
98         if (attachment->priv->tmp_file) {
99                 ev_tmp_file_unlink (attachment->priv->tmp_file);
100                 g_object_unref (attachment->priv->tmp_file);
101                 attachment->priv->tmp_file = NULL;
102         }
103
104         G_OBJECT_CLASS (ev_attachment_parent_class)->finalize (object);
105 }
106
107 static void
108 ev_attachment_set_property (GObject      *object,
109                             guint         prop_id,
110                             const GValue *value,
111                             GParamSpec   *param_spec)
112 {
113         EvAttachment *attachment = EV_ATTACHMENT (object);
114
115         switch (prop_id) {
116         case PROP_NAME:
117                 attachment->priv->name = g_value_dup_string (value);
118                 break;
119         case PROP_DESCRIPTION:
120                 attachment->priv->description = g_value_dup_string (value);
121                 break;
122         case PROP_MTIME:
123                 attachment->priv->mtime = g_value_get_ulong (value);
124                 break;
125         case PROP_CTIME:
126                 attachment->priv->ctime = g_value_get_ulong (value);
127                 break;
128         case PROP_SIZE:
129                 attachment->priv->size = g_value_get_uint (value);
130                 break;
131         case PROP_DATA:
132                 attachment->priv->data = g_value_get_pointer (value);
133                 attachment->priv->mime_type = g_content_type_guess (attachment->priv->name,
134                                                                     (guchar *) attachment->priv->data,
135                                                                     attachment->priv->size,
136                                                                     NULL);
137                 break;
138         default:
139                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object,
140                                                    prop_id,
141                                                    param_spec);
142                 break;
143         }
144 }
145
146 static void
147 ev_attachment_class_init (EvAttachmentClass *klass)
148 {
149         GObjectClass *g_object_class;
150
151         g_object_class = G_OBJECT_CLASS (klass);
152
153         g_object_class->set_property = ev_attachment_set_property;
154
155         g_type_class_add_private (g_object_class, sizeof (EvAttachmentPrivate));
156
157         /* Properties */
158         g_object_class_install_property (g_object_class,
159                                          PROP_NAME,
160                                          g_param_spec_string ("name",
161                                                               "Name",
162                                                               "The attachment name",
163                                                               NULL,
164                                                               G_PARAM_WRITABLE |
165                                                               G_PARAM_CONSTRUCT_ONLY));
166         g_object_class_install_property (g_object_class,
167                                          PROP_DESCRIPTION,
168                                          g_param_spec_string ("description",
169                                                               "Description",
170                                                               "The attachment description",
171                                                               NULL,
172                                                               G_PARAM_WRITABLE |
173                                                               G_PARAM_CONSTRUCT_ONLY));
174         g_object_class_install_property (g_object_class,
175                                          PROP_MTIME,
176                                          g_param_spec_ulong ("mtime",
177                                                              "ModifiedTime", 
178                                                              "The attachment modification date",
179                                                              0, G_MAXULONG, 0,
180                                                              G_PARAM_WRITABLE |
181                                                              G_PARAM_CONSTRUCT_ONLY));
182         g_object_class_install_property (g_object_class,
183                                          PROP_CTIME,
184                                          g_param_spec_ulong ("ctime",
185                                                              "CreationTime",
186                                                              "The attachment creation date",
187                                                              0, G_MAXULONG, 0,
188                                                              G_PARAM_WRITABLE |
189                                                              G_PARAM_CONSTRUCT_ONLY));
190         g_object_class_install_property (g_object_class,
191                                          PROP_SIZE,
192                                          g_param_spec_uint ("size",
193                                                             "Size",
194                                                             "The attachment size",
195                                                             0, G_MAXUINT, 0,
196                                                             G_PARAM_WRITABLE |
197                                                             G_PARAM_CONSTRUCT_ONLY));
198         g_object_class_install_property (g_object_class,
199                                          PROP_DATA,
200                                          g_param_spec_pointer ("data",
201                                                                "Data",
202                                                                "The attachment data",
203                                                                G_PARAM_WRITABLE |
204                                                                G_PARAM_CONSTRUCT_ONLY));
205         
206         g_object_class->finalize = ev_attachment_finalize;
207 }
208
209 static void
210 ev_attachment_init (EvAttachment *attachment)
211 {
212         attachment->priv = EV_ATTACHMENT_GET_PRIVATE (attachment);
213
214         attachment->priv->name = NULL;
215         attachment->priv->description = NULL;
216         attachment->priv->data = NULL;
217         attachment->priv->mime_type = NULL;
218
219         attachment->priv->tmp_file = NULL;
220 }
221
222 EvAttachment *
223 ev_attachment_new (const gchar *name,
224                    const gchar *description,
225                    GTime        mtime,
226                    GTime        ctime,
227                    gsize        size,
228                    gpointer     data)
229 {
230         EvAttachment *attachment;
231
232         attachment = g_object_new (EV_TYPE_ATTACHMENT,
233                                    "name", name,
234                                    "description", description,
235                                    "mtime", mtime,
236                                    "ctime", ctime,
237                                    "size", size,
238                                    "data", data,
239                                    NULL);
240
241         return attachment;
242 }
243
244 const gchar *
245 ev_attachment_get_name (EvAttachment *attachment)
246 {
247         g_return_val_if_fail (EV_IS_ATTACHMENT (attachment), NULL);
248
249         return attachment->priv->name;
250 }
251
252 const gchar *
253 ev_attachment_get_description (EvAttachment *attachment)
254 {
255         g_return_val_if_fail (EV_IS_ATTACHMENT (attachment), NULL);
256
257         return attachment->priv->description;
258 }
259
260 GTime
261 ev_attachment_get_modification_date (EvAttachment *attachment)
262 {
263         g_return_val_if_fail (EV_IS_ATTACHMENT (attachment), 0);
264
265         return attachment->priv->mtime;
266 }
267
268 GTime
269 ev_attachment_get_creation_date (EvAttachment *attachment)
270 {
271         g_return_val_if_fail (EV_IS_ATTACHMENT (attachment), 0);
272
273         return attachment->priv->ctime;
274 }
275
276 const gchar *
277 ev_attachment_get_mime_type (EvAttachment *attachment)
278 {
279         g_return_val_if_fail (EV_IS_ATTACHMENT (attachment), NULL);
280
281         return attachment->priv->mime_type;
282 }
283
284 gboolean
285 ev_attachment_save (EvAttachment *attachment,
286                     GFile        *file,
287                     GError      **error)
288 {
289         GFileOutputStream *output_stream;
290         GError *ioerror = NULL;
291         gssize  written_bytes;
292
293         g_return_val_if_fail (EV_IS_ATTACHMENT (attachment), FALSE);
294         g_return_val_if_fail (G_IS_FILE (file), FALSE);
295
296         output_stream = g_file_replace (file, NULL, FALSE, 0, NULL, &ioerror);
297         if (output_stream == NULL) {
298                 char *uri;
299                 
300                 uri = g_file_get_uri (file);
301                 g_set_error (error,
302                              EV_ATTACHMENT_ERROR, 
303                              ioerror->code,
304                              _("Couldn't save attachment “%s”: %s"),
305                              uri, 
306                              ioerror->message);
307
308                 g_error_free (ioerror);
309                 g_free (uri);
310                 
311                 return FALSE;
312         }
313         
314         written_bytes = g_output_stream_write (G_OUTPUT_STREAM (output_stream),
315                                                attachment->priv->data,
316                                                attachment->priv->size,
317                                                NULL, &ioerror);
318         if (written_bytes == -1) {
319                 char *uri;
320                 
321                 uri = g_file_get_uri (file);
322                 g_set_error (error,
323                              EV_ATTACHMENT_ERROR,
324                              ioerror->code,
325                              _("Couldn't save attachment “%s”: %s"),
326                              uri,
327                              ioerror->message);
328                 
329                 g_output_stream_close (G_OUTPUT_STREAM (output_stream), NULL, NULL);
330                 g_error_free (ioerror);
331                 g_free (uri);
332
333                 return FALSE;
334         }
335
336         g_output_stream_close (G_OUTPUT_STREAM (output_stream), NULL, NULL);
337
338         return TRUE;
339         
340 }
341
342 static gboolean
343 ev_attachment_launch_app (EvAttachment *attachment,
344                           GdkScreen    *screen,
345                           guint32       timestamp,
346                           GError      **error)
347 {
348         gboolean           result;
349         GList             *files = NULL;
350         GAppLaunchContext *context = NULL;
351         GError            *ioerror = NULL;
352
353         g_assert (G_IS_FILE (attachment->priv->tmp_file));
354         g_assert (G_IS_APP_INFO (attachment->priv->app));
355
356         files = g_list_prepend (files, attachment->priv->tmp_file);
357
358         context = G_APP_LAUNCH_CONTEXT (gdk_app_launch_context_new ());
359         gdk_app_launch_context_set_screen (GDK_APP_LAUNCH_CONTEXT (context), screen);
360         gdk_app_launch_context_set_timestamp (GDK_APP_LAUNCH_CONTEXT (context), timestamp);
361
362         result = g_app_info_launch (attachment->priv->app, files,
363                                     context, &ioerror);
364         
365         if (context)
366                 g_object_unref (context);
367
368         if (!result) {
369                 g_set_error (error,
370                              EV_ATTACHMENT_ERROR,
371                              (gint) result,
372                              _("Couldn't open attachment “%s”: %s"),
373                              attachment->priv->name,
374                              ioerror->message);
375
376                 g_list_free (files);
377                 g_error_free (ioerror);
378                 
379                 return FALSE;
380         }
381
382         g_list_free (files);
383         
384         return TRUE;
385 }
386
387 gboolean
388 ev_attachment_open (EvAttachment *attachment,
389                     GdkScreen    *screen,
390                     guint32       timestamp,
391                     GError      **error)
392 {
393         GAppInfo *app_info;
394         gboolean  retval = FALSE;
395
396         g_return_val_if_fail (EV_IS_ATTACHMENT (attachment), FALSE);
397         
398         if (!attachment->priv->app) {
399                 app_info = g_app_info_get_default_for_type (attachment->priv->mime_type, FALSE);
400                 attachment->priv->app = app_info;
401         }
402
403         if (!attachment->priv->app) {
404                 g_set_error (error,
405                              EV_ATTACHMENT_ERROR,
406                              0,
407                              _("Couldn't open attachment “%s”"),
408                              attachment->priv->name);
409                 
410                 return FALSE;
411         }
412
413         if (attachment->priv->tmp_file) {
414                 retval = ev_attachment_launch_app (attachment, screen,
415                                                    timestamp, error);
416         } else {
417                 char *template;
418                 GFile *file;
419
420                 /* FIXMEchpe: convert to filename encoding first! */
421                 template = g_strdup_printf ("%s.XXXXXX", ev_attachment_get_name (attachment));
422                 file = ev_mkstemp_file (template, error);
423                 g_free (template);
424
425                 if (file != NULL && ev_attachment_save (attachment, file, error)) {
426                         if (attachment->priv->tmp_file)
427                                 g_object_unref (attachment->priv->tmp_file);
428                         attachment->priv->tmp_file = g_object_ref (file);
429
430                         retval = ev_attachment_launch_app (attachment, screen,
431                                                            timestamp, error);
432                 }
433
434                 g_object_unref (file);
435         }
436
437         return retval;
438 }
439