1 /* Eye Of Gnome - Jobs
2 *
3 * Copyright (C) 2013 The Free Software Foundation
4 *
5 * Author: Javier Sánchez <jsanchez@deskblue.com>
6 *
7 * Based on code (libview/ev-jobs.h) by:
8 * - Carlos Garcia Campos <carlosgc@gnome.org>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License along
21 * with this program; if not, write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23 */
24
25 #include "eog-debug.h"
26 #include "eog-jobs.h"
27 #include "eog-thumbnail.h"
28 #include "eog-pixbuf-util.h"
29
30 #include <gio/gio.h>
31
32 G_DEFINE_ABSTRACT_TYPE (EogJob, eog_job, G_TYPE_OBJECT);
33 G_DEFINE_TYPE (EogJobCopy, eog_job_copy, EOG_TYPE_JOB);
34 G_DEFINE_TYPE (EogJobLoad, eog_job_load, EOG_TYPE_JOB);
35 G_DEFINE_TYPE (EogJobModel, eog_job_model, EOG_TYPE_JOB);
36 G_DEFINE_TYPE (EogJobSave, eog_job_save, EOG_TYPE_JOB);
37 G_DEFINE_TYPE (EogJobSaveAs, eog_job_save_as, EOG_TYPE_JOB_SAVE);
38 G_DEFINE_TYPE (EogJobThumbnail, eog_job_thumbnail, EOG_TYPE_JOB);
39 G_DEFINE_TYPE (EogJobTransform, eog_job_transform, EOG_TYPE_JOB);
40
41 /* signals */
42 enum {
43 PROGRESS,
44 CANCELLED,
45 FINISHED,
46 LAST_SIGNAL
47 };
48
49 static guint job_signals[LAST_SIGNAL];
50
51 /* notify signal funcs */
52 static gboolean notify_progress (EogJob *job);
53 static gboolean notify_cancelled (EogJob *job);
54 static gboolean notify_finished (EogJob *job);
55
56 /* gobject vfuncs */
57 static void eog_job_class_init (EogJobClass *class);
58 static void eog_job_init (EogJob *job);
59 static void eog_job_dispose (GObject *object);
60
61 static void eog_job_copy_class_init (EogJobCopyClass *class);
62 static void eog_job_copy_init (EogJobCopy *job);
63 static void eog_job_copy_dispose (GObject *object);
64
65 static void eog_job_load_class_init (EogJobLoadClass *class);
66 static void eog_job_load_init (EogJobLoad *job);
67 static void eog_job_load_dispose (GObject *object);
68
69 static void eog_job_model_class_init (EogJobModelClass *class);
70 static void eog_job_model_init (EogJobModel *job);
71 static void eog_job_model_dispose (GObject *object);
72
73 static void eog_job_save_class_init (EogJobSaveClass *class);
74 static void eog_job_save_init (EogJobSave *job);
75 static void eog_job_save_dispose (GObject *object);
76
77 static void eog_job_save_as_class_init (EogJobSaveAsClass *class);
78 static void eog_job_save_as_init (EogJobSaveAs *job);
79 static void eog_job_save_as_dispose (GObject *object);
80
81 static void eog_job_thumbnail_class_init (EogJobThumbnailClass *class);
82 static void eog_job_thumbnail_init (EogJobThumbnail *job);
83 static void eog_job_thumbnail_dispose (GObject *object);
84
85 static void eog_job_transform_class_init (EogJobTransformClass *class);
86 static void eog_job_transform_init (EogJobTransform *job);
87 static void eog_job_transform_dispose (GObject *object);
88
89 /* vfuncs */
90 static void eog_job_run_unimplemented (EogJob *job);
91 static void eog_job_copy_run (EogJob *job);
92 static void eog_job_load_run (EogJob *job);
93 static void eog_job_model_run (EogJob *job);
94 static void eog_job_save_run (EogJob *job);
95 static void eog_job_save_as_run (EogJob *job);
96 static void eog_job_thumbnail_run (EogJob *job);
97 static void eog_job_transform_run (EogJob *job);
98
99 /* callbacks */
100 static void eog_job_copy_progress_callback (goffset current_num_bytes,
101 goffset total_num_bytes,
102 gpointer user_data);
103
104 static void eog_job_save_progress_callback (EogImage *image,
105 gfloat progress,
106 gpointer data);
107
108 /* --------------------------- notify signal funcs --------------------------- */
109 static gboolean
notify_progress(EogJob * job)110 notify_progress (EogJob *job)
111 {
112 /* check if the current job was previously cancelled */
113 if (eog_job_is_cancelled (job))
114 return FALSE;
115
116 /* show info for debugging */
117 eog_debug_message (DEBUG_JOBS,
118 "%s (%p) job update its progress to -> %1.2f",
119 EOG_GET_TYPE_NAME (job),
120 job,
121 job->progress);
122
123 /* notify progress */
124 g_signal_emit (job,
125 job_signals[PROGRESS],
126 0,
127 job->progress);
128 return FALSE;
129 }
130
131 static gboolean
notify_cancelled(EogJob * job)132 notify_cancelled (EogJob *job)
133 {
134 /* show info for debugging */
135 eog_debug_message (DEBUG_JOBS,
136 "%s (%p) job was CANCELLED",
137 EOG_GET_TYPE_NAME (job),
138 job);
139
140 /* notify cancelation */
141 g_signal_emit (job,
142 job_signals[CANCELLED],
143 0);
144
145 return FALSE;
146 }
147
148 static gboolean
notify_finished(EogJob * job)149 notify_finished (EogJob *job)
150 {
151 /* show info for debugging */
152 eog_debug_message (DEBUG_JOBS,
153 "%s (%p) job was FINISHED",
154 EOG_GET_TYPE_NAME (job),
155 job);
156
157 /* notify job finalization */
158 g_signal_emit (job,
159 job_signals[FINISHED],
160 0);
161 return FALSE;
162 }
163
164 /* --------------------------------- EogJob ---------------------------------- */
165 static void
eog_job_class_init(EogJobClass * class)166 eog_job_class_init (EogJobClass *class)
167 {
168 GObjectClass *g_object_class = (GObjectClass *) class;
169
170 g_object_class->dispose = eog_job_dispose;
171 class->run = eog_job_run_unimplemented;
172
173 /* signals */
174 job_signals [PROGRESS] =
175 g_signal_new ("progress",
176 EOG_TYPE_JOB,
177 G_SIGNAL_RUN_LAST,
178 G_STRUCT_OFFSET (EogJobClass, progress),
179 NULL,
180 NULL,
181 g_cclosure_marshal_VOID__FLOAT,
182 G_TYPE_NONE,
183 1,
184 G_TYPE_FLOAT);
185
186 job_signals [CANCELLED] =
187 g_signal_new ("cancelled",
188 EOG_TYPE_JOB,
189 G_SIGNAL_RUN_LAST,
190 G_STRUCT_OFFSET (EogJobClass, cancelled),
191 NULL,
192 NULL,
193 g_cclosure_marshal_VOID__VOID,
194 G_TYPE_NONE,
195 0);
196
197 job_signals [FINISHED] =
198 g_signal_new ("finished",
199 EOG_TYPE_JOB,
200 G_SIGNAL_RUN_LAST,
201 G_STRUCT_OFFSET (EogJobClass, finished),
202 NULL,
203 NULL,
204 g_cclosure_marshal_VOID__VOID,
205 G_TYPE_NONE,
206 0);
207 }
208
209 static
eog_job_init(EogJob * job)210 void eog_job_init (EogJob *job)
211 {
212 /* initialize all public and private members to reasonable
213 default values. */
214 job->cancellable = g_cancellable_new ();
215 job->error = NULL;
216
217 job->progress = 0.0;
218 job->cancelled = FALSE;
219 job->finished = FALSE;
220
221 /* NOTE: we need to allocate the mutex here so the ABI stays
222 the same when it used to use g_mutex_new */
223 job->mutex = g_malloc (sizeof (GMutex));
224 g_mutex_init (job->mutex);
225 }
226
227 static
eog_job_dispose(GObject * object)228 void eog_job_dispose (GObject *object)
229 {
230 EogJob *job;
231
232 g_return_if_fail (EOG_IS_JOB (object));
233
234 job = EOG_JOB (object);
235
236 /* free all public and private members */
237 if (job->cancellable) {
238 g_object_unref (job->cancellable);
239 job->cancellable = NULL;
240 }
241
242 if (job->error) {
243 g_error_free (job->error);
244 job->error = NULL;
245 }
246
247 if (job->mutex) {
248 g_mutex_clear (job->mutex);
249 g_free (job->mutex);
250 }
251
252 /* call parent dispose */
253 G_OBJECT_CLASS (eog_job_parent_class)->dispose (object);
254 }
255
256 static void
eog_job_run_unimplemented(EogJob * job)257 eog_job_run_unimplemented (EogJob *job)
258 {
259 g_critical ("Class \"%s\" does not implement the required run action",
260 G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS (job)));
261 }
262
263 void
eog_job_run(EogJob * job)264 eog_job_run (EogJob *job)
265 {
266 EogJobClass *class;
267
268 g_return_if_fail (EOG_IS_JOB (job));
269
270 class = EOG_JOB_GET_CLASS (job);
271 class->run (job);
272 }
273
274 void
eog_job_cancel(EogJob * job)275 eog_job_cancel (EogJob *job)
276 {
277 g_return_if_fail (EOG_IS_JOB (job));
278
279 g_object_ref (job);
280
281 /* check if job was cancelled previously */
282 if (job->cancelled)
283 return;
284
285 /* check if job finished previously */
286 if (job->finished)
287 return;
288
289 /* show info for debugging */
290 eog_debug_message (DEBUG_JOBS,
291 "CANCELLING a %s (%p)",
292 EOG_GET_TYPE_NAME (job),
293 job);
294
295 /* --- enter critical section --- */
296 g_mutex_lock (job->mutex);
297
298 /* cancel job */
299 job->cancelled = TRUE;
300 g_cancellable_cancel (job->cancellable);
301
302 /* --- leave critical section --- */
303 g_mutex_unlock (job->mutex);
304
305 /* notify job cancellation */
306 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
307 (GSourceFunc) notify_cancelled,
308 job,
309 g_object_unref);
310 }
311
312 gfloat
eog_job_get_progress(EogJob * job)313 eog_job_get_progress (EogJob *job)
314 {
315 g_return_val_if_fail (EOG_IS_JOB (job), 0.0);
316
317 return job->progress;
318 }
319
320 void
eog_job_set_progress(EogJob * job,gfloat progress)321 eog_job_set_progress (EogJob *job,
322 gfloat progress)
323 {
324 g_return_if_fail (EOG_IS_JOB (job));
325 g_return_if_fail (progress >= 0.0 && progress <= 1.0);
326
327 g_object_ref (job);
328
329 /* --- enter critical section --- */
330 g_mutex_lock (job->mutex);
331
332 job->progress = progress;
333
334 /* --- leave critical section --- */
335 g_mutex_unlock (job->mutex);
336
337 /* notify progress */
338 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
339 (GSourceFunc) notify_progress,
340 job,
341 g_object_unref);
342 }
343
344 gboolean
eog_job_is_cancelled(EogJob * job)345 eog_job_is_cancelled (EogJob *job)
346 {
347 g_return_val_if_fail (EOG_IS_JOB (job), TRUE);
348
349 return job->cancelled;
350 }
351
352 gboolean
eog_job_is_finished(EogJob * job)353 eog_job_is_finished (EogJob *job)
354 {
355 g_return_val_if_fail (EOG_IS_JOB (job), TRUE);
356
357 return job->finished;
358 }
359
360 /* ------------------------------- EogJobCopy -------------------------------- */
361 static void
eog_job_copy_class_init(EogJobCopyClass * class)362 eog_job_copy_class_init (EogJobCopyClass *class)
363 {
364 GObjectClass *g_object_class = (GObjectClass *) class;
365 EogJobClass *eog_job_class = (EogJobClass *) class;
366
367 g_object_class->dispose = eog_job_copy_dispose;
368 eog_job_class->run = eog_job_copy_run;
369 }
370
371 static
eog_job_copy_init(EogJobCopy * job)372 void eog_job_copy_init (EogJobCopy *job)
373 {
374 /* initialize all public and private members to reasonable
375 default values. */
376 job->images = NULL;
377 job->destination = NULL;
378 job->current_position = 0;
379 }
380
381 static
eog_job_copy_dispose(GObject * object)382 void eog_job_copy_dispose (GObject *object)
383 {
384 EogJobCopy *job;
385
386 g_return_if_fail (EOG_IS_JOB_COPY (object));
387
388 job = EOG_JOB_COPY (object);
389
390 /* free all public and private members */
391 if (job->images) {
392 g_list_foreach (job->images, (GFunc) g_object_unref, NULL);
393 g_list_free (job->images);
394 job->images = NULL;
395 }
396
397 if (job->destination) {
398 g_free (job->destination);
399 job->destination = NULL;
400 }
401
402 /* call parent dispose */
403 G_OBJECT_CLASS (eog_job_copy_parent_class)->dispose (object);
404 }
405
406 static void
eog_job_copy_progress_callback(goffset current_num_bytes,goffset total_num_bytes,gpointer user_data)407 eog_job_copy_progress_callback (goffset current_num_bytes,
408 goffset total_num_bytes,
409 gpointer user_data)
410 {
411 gfloat progress;
412 guint n_images;
413 EogJobCopy *job;
414
415 job = EOG_JOB_COPY (user_data);
416
417 n_images = g_list_length (job->images);
418
419 progress = ((current_num_bytes / (gfloat) total_num_bytes) + job->current_position) / n_images;
420
421 eog_job_set_progress (EOG_JOB (job), progress);
422 }
423
424 static void
eog_job_copy_run(EogJob * job)425 eog_job_copy_run (EogJob *job)
426 {
427 EogJobCopy *copyjob;
428 GList *it;
429
430 /* initialization */
431 g_return_if_fail (EOG_IS_JOB_COPY (job));
432
433 copyjob = EOG_JOB_COPY (g_object_ref (job));
434
435 /* clean previous errors */
436 if (job->error) {
437 g_error_free (job->error);
438 job->error = NULL;
439 }
440
441 /* check if the current job was previously cancelled */
442 if (eog_job_is_cancelled (job))
443 {
444 g_object_unref (job);
445 return;
446 }
447
448 copyjob->current_position = 0;
449
450 for (it = copyjob->images; it != NULL; it = g_list_next (it), copyjob->current_position++) {
451 GFile *src, *dest;
452 gchar *filename, *dest_filename;
453
454 src = (GFile *) it->data;
455 filename = g_file_get_basename (src);
456 dest_filename = g_build_filename (copyjob->destination, filename, NULL);
457 dest = g_file_new_for_path (dest_filename);
458
459 g_file_copy (src, dest,
460 G_FILE_COPY_OVERWRITE, NULL,
461 eog_job_copy_progress_callback, job,
462 &job->error);
463 g_object_unref (dest);
464 g_free (filename);
465 g_free (dest_filename);
466 }
467
468 /* --- enter critical section --- */
469 g_mutex_lock (job->mutex);
470
471 /* job finished */
472 job->finished = TRUE;
473
474 /* --- leave critical section --- */
475 g_mutex_unlock (job->mutex);
476
477 /* notify job finalization */
478 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
479 (GSourceFunc) notify_finished,
480 job,
481 g_object_unref);
482 }
483
484 /**
485 * eog_job_copy_new:
486 * @images: (element-type EogImage) (transfer full): a #EogImage list
487 * @destination: destination path for the copy
488 *
489 * Creates a new #EogJob.
490 *
491 * Returns: A #EogJob.
492 */
493
494 EogJob *
eog_job_copy_new(GList * images,const gchar * destination)495 eog_job_copy_new (GList *images,
496 const gchar *destination)
497 {
498 EogJobCopy *job;
499
500 job = g_object_new (EOG_TYPE_JOB_COPY, NULL);
501
502 if (images)
503 job->images = images;
504
505 if (destination)
506 job->destination = g_strdup (destination);
507
508 /* show info for debugging */
509 eog_debug_message (DEBUG_JOBS,
510 "%s (%p) job was CREATED",
511 EOG_GET_TYPE_NAME (job),
512 job);
513
514 return EOG_JOB (job);
515 }
516
517 /* ------------------------------- EogJobLoad -------------------------------- */
518 static void
eog_job_load_class_init(EogJobLoadClass * class)519 eog_job_load_class_init (EogJobLoadClass *class)
520 {
521 GObjectClass *g_object_class = (GObjectClass *) class;
522 EogJobClass *eog_job_class = (EogJobClass *) class;
523
524 g_object_class->dispose = eog_job_load_dispose;
525 eog_job_class->run = eog_job_load_run;
526 }
527
528 static
eog_job_load_init(EogJobLoad * job)529 void eog_job_load_init (EogJobLoad *job)
530 {
531 /* initialize all public and private members to reasonable
532 default values. */
533 job->image = NULL;
534 job->data = EOG_IMAGE_DATA_ALL;
535 }
536
537 static
eog_job_load_dispose(GObject * object)538 void eog_job_load_dispose (GObject *object)
539 {
540 EogJobLoad *job;
541
542 g_return_if_fail (EOG_IS_JOB_LOAD (object));
543
544 job = EOG_JOB_LOAD (object);
545
546 /* free all public and private members */
547 if (job->image) {
548 g_object_unref (job->image);
549 job->image = NULL;
550 }
551
552 /* call parent dispose */
553 G_OBJECT_CLASS (eog_job_load_parent_class)->dispose (object);
554 }
555
556 static void
eog_job_load_run(EogJob * job)557 eog_job_load_run (EogJob *job)
558 {
559 EogJobLoad *job_load;
560
561 /* initialization */
562 g_return_if_fail (EOG_IS_JOB_LOAD (job));
563
564 job_load = EOG_JOB_LOAD (g_object_ref (job));
565
566 /* clean previous errors */
567 if (job->error) {
568 g_error_free (job->error);
569 job->error = NULL;
570 }
571
572 /* load image from file */
573 eog_image_load (job_load->image,
574 job_load->data,
575 job,
576 &job->error);
577
578 /* check if the current job was previously cancelled */
579 if (eog_job_is_cancelled (job))
580 return;
581
582 /* --- enter critical section --- */
583 g_mutex_lock (job->mutex);
584
585 /* job finished */
586 job->finished = TRUE;
587
588 /* --- leave critical section --- */
589 g_mutex_unlock (job->mutex);
590
591 /* notify job finalization */
592 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
593 (GSourceFunc) notify_finished,
594 job,
595 g_object_unref);
596 }
597
598 EogJob *
eog_job_load_new(EogImage * image,EogImageData data)599 eog_job_load_new (EogImage *image,
600 EogImageData data)
601 {
602 EogJobLoad *job;
603
604 job = g_object_new (EOG_TYPE_JOB_LOAD, NULL);
605
606 if (image)
607 job->image = g_object_ref (image);
608
609 job->data = data;
610
611 /* show info for debugging */
612 eog_debug_message (DEBUG_JOBS,
613 "%s (%p) job was CREATED",
614 EOG_GET_TYPE_NAME (job),
615 job);
616
617 return EOG_JOB (job);
618 }
619
620 /* ------------------------------- EogJobModel -------------------------------- */
621 static void
eog_job_model_class_init(EogJobModelClass * class)622 eog_job_model_class_init (EogJobModelClass *class)
623 {
624 GObjectClass *g_object_class = (GObjectClass *) class;
625 EogJobClass *eog_job_class = (EogJobClass *) class;
626
627 g_object_class->dispose = eog_job_model_dispose;
628 eog_job_class->run = eog_job_model_run;
629 }
630
631 static
eog_job_model_init(EogJobModel * job)632 void eog_job_model_init (EogJobModel *job)
633 {
634 /* initialize all public and private members to reasonable
635 default values. */
636 job->store = NULL;
637 job->file_list = NULL;
638 }
639
640 static
eog_job_model_dispose(GObject * object)641 void eog_job_model_dispose (GObject *object)
642 {
643 EogJobModel *job;
644
645 g_return_if_fail (EOG_IS_JOB_MODEL (object));
646
647 job = EOG_JOB_MODEL (object);
648
649 /* free all public and private members */
650 if (job->store) {
651 g_object_unref (job->store);
652 job->store = NULL;
653 }
654
655 if (job->file_list) {
656 // g_slist_foreach (job->file_list, (GFunc) g_object_unref, NULL);
657 // g_slist_free (job->file_list);
658 job->file_list = NULL;
659 }
660
661 /* call parent dispose */
662 G_OBJECT_CLASS (eog_job_model_parent_class)->dispose (object);
663 }
664
665 typedef struct
666 {
667 GMutex mutex;
668 GCond cond;
669 GAsyncResult *result;
670 } MountData;
671
672 static void
_g_file_mount_enclosing_volume_sync_cb(GObject * source,GAsyncResult * result,gpointer user_data)673 _g_file_mount_enclosing_volume_sync_cb (GObject *source,
674 GAsyncResult *result,
675 gpointer user_data)
676 {
677 MountData *data = (MountData *) user_data;
678
679 data->result = g_object_ref (result);
680
681 g_mutex_lock (&data->mutex);
682 g_cond_signal (&data->cond);
683 g_mutex_unlock (&data->mutex);
684 }
685
686 static gboolean
_g_file_mount_enclosing_volume_sync(GFile * location,GMountMountFlags flags,GMountOperation * mount_operation,GError ** error)687 _g_file_mount_enclosing_volume_sync (GFile *location,
688 GMountMountFlags flags,
689 GMountOperation *mount_operation,
690 GError **error)
691 {
692 MountData *data;
693 gboolean retval;
694
695 data = g_new0 (MountData, 1);
696
697 g_mutex_lock (&data->mutex);
698 g_file_mount_enclosing_volume (location,
699 flags,
700 mount_operation,
701 NULL,
702 _g_file_mount_enclosing_volume_sync_cb,
703 data);
704 while (data->result == NULL)
705 g_cond_wait (&data->cond, &data->mutex);
706 g_mutex_unlock (&data->mutex);
707
708 retval = g_file_mount_enclosing_volume_finish (location, data->result, error);
709
710 g_object_unref (data->result);
711 g_free (data);
712
713 return retval;
714 }
715
716 static void
filter_files(GSList * files,GList ** file_list,GList ** error_list)717 filter_files (GSList *files, GList **file_list, GList **error_list)
718 {
719 GSList *it;
720 GFileInfo *file_info;
721
722 for (it = files; it != NULL; it = it->next) {
723 GFile *file;
724 GFileType type = G_FILE_TYPE_UNKNOWN;
725
726 file = (GFile *) it->data;
727
728 if (file != NULL) {
729 GError *error = NULL;
730
731 file_info = g_file_query_info (file,
732 G_FILE_ATTRIBUTE_STANDARD_TYPE","G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
733 0, NULL, &error);
734 if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_MOUNTED)) {
735 GMountOperation *operation;
736
737 operation = gtk_mount_operation_new (NULL);
738 if (_g_file_mount_enclosing_volume_sync (file,
739 G_MOUNT_MOUNT_NONE,
740 operation,
741 NULL))
742 file_info = g_file_query_info (file,
743 G_FILE_ATTRIBUTE_STANDARD_TYPE","G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
744 0, NULL, NULL);
745
746 g_object_unref (operation);
747 }
748 g_clear_error (&error);
749
750 if (file_info == NULL) {
751 type = G_FILE_TYPE_UNKNOWN;
752 } else {
753 type = g_file_info_get_file_type (file_info);
754
755 /* Workaround for gvfs backends that
756 don't set the GFileType. */
757 if (G_UNLIKELY (type == G_FILE_TYPE_UNKNOWN)) {
758 const gchar *ctype;
759
760 ctype = g_file_info_get_content_type (file_info);
761
762 /* If the content type is supported
763 adjust the file_type */
764 if (eog_image_is_supported_mime_type (ctype))
765 type = G_FILE_TYPE_REGULAR;
766 }
767
768 g_object_unref (file_info);
769 }
770 }
771
772 switch (type) {
773 case G_FILE_TYPE_REGULAR:
774 case G_FILE_TYPE_DIRECTORY:
775 *file_list = g_list_prepend (*file_list, g_object_ref (file));
776 break;
777 default:
778 *error_list = g_list_prepend (*error_list,
779 g_file_get_uri (file));
780 break;
781 }
782 }
783
784 *file_list = g_list_reverse (*file_list);
785 *error_list = g_list_reverse (*error_list);
786 }
787
788 static void
eog_job_model_run(EogJob * job)789 eog_job_model_run (EogJob *job)
790 {
791 EogJobModel *job_model;
792 GList *filtered_list;
793 GList *error_list;
794
795 /* initialization */
796 g_return_if_fail (EOG_IS_JOB_MODEL (job));
797
798 job_model = EOG_JOB_MODEL (g_object_ref (job));
799 filtered_list = NULL;
800 error_list = NULL;
801
802 filter_files (job_model->file_list,
803 &filtered_list,
804 &error_list);
805
806 /* --- enter critical section --- */
807 g_mutex_lock (job->mutex);
808
809 /* create a list store */
810 job_model->store = EOG_LIST_STORE (eog_list_store_new ());
811 eog_list_store_add_files (job_model->store, filtered_list);
812
813 /* --- leave critical section --- */
814 g_mutex_unlock (job->mutex);
815
816 /* free lists*/
817 g_list_foreach (filtered_list, (GFunc) g_object_unref, NULL);
818 g_list_free (filtered_list);
819
820 g_list_foreach (error_list, (GFunc) g_free, NULL);
821 g_list_free (error_list);
822
823 /* --- enter critical section --- */
824 g_mutex_lock (job->mutex);
825
826 /* job finished */
827 job->finished = TRUE;
828
829 /* --- leave critical section --- */
830 g_mutex_unlock (job->mutex);
831
832 /* notify job finalization */
833 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
834 (GSourceFunc) notify_finished,
835 job,
836 g_object_unref);
837 }
838
839 /**
840 * eog_job_model_new:
841 * @file_list: (element-type GFile): a #GFile list
842 *
843 * Creates a new #EogJob model.
844 *
845 * Returns: A #EogJob.
846 */
847
848 EogJob *
eog_job_model_new(GSList * file_list)849 eog_job_model_new (GSList *file_list)
850 {
851 EogJobModel *job;
852
853 job = g_object_new (EOG_TYPE_JOB_MODEL, NULL);
854
855 if (file_list != NULL)
856 job->file_list = file_list;
857
858 /* show info for debugging */
859 eog_debug_message (DEBUG_JOBS,
860 "%s (%p) job was CREATED",
861 EOG_GET_TYPE_NAME (job),
862 job);
863
864 return EOG_JOB (job);
865 }
866
867 /* ------------------------------- EogJobSave -------------------------------- */
868 static void
eog_job_save_class_init(EogJobSaveClass * class)869 eog_job_save_class_init (EogJobSaveClass *class)
870 {
871 GObjectClass *g_object_class = (GObjectClass *) class;
872 EogJobClass *eog_job_class = (EogJobClass *) class;
873
874 g_object_class->dispose = eog_job_save_dispose;
875 eog_job_class->run = eog_job_save_run;
876 }
877
878 static
eog_job_save_init(EogJobSave * job)879 void eog_job_save_init (EogJobSave *job)
880 {
881 /* initialize all public and private members to reasonable
882 default values. */
883 job->images = NULL;
884 job->current_position = 0;
885 job->current_image = NULL;
886 }
887
888 static
eog_job_save_dispose(GObject * object)889 void eog_job_save_dispose (GObject *object)
890 {
891 EogJobSave *job;
892
893 g_return_if_fail (EOG_IS_JOB_SAVE (object));
894
895 job = EOG_JOB_SAVE (object);
896
897 job->current_image = NULL;
898
899 /* free all public and private members */
900 if (job->images) {
901 g_list_foreach (job->images, (GFunc) g_object_unref, NULL);
902 g_list_free (job->images);
903 job->images = NULL;
904 }
905
906 /* call parent dispose */
907 G_OBJECT_CLASS (eog_job_save_parent_class)->dispose (object);
908 }
909
910 static void
eog_job_save_progress_callback(EogImage * image,gfloat progress,gpointer data)911 eog_job_save_progress_callback (EogImage *image,
912 gfloat progress,
913 gpointer data)
914 {
915 EogJobSave *job;
916 guint n_images;
917 gfloat job_progress;
918
919 job = EOG_JOB_SAVE (data);
920
921 n_images = g_list_length (job->images);
922 job_progress = (job->current_position / (gfloat) n_images) + (progress / n_images);
923
924 eog_job_set_progress (EOG_JOB (job), job_progress);
925 }
926
927 static void
eog_job_save_run(EogJob * job)928 eog_job_save_run (EogJob *job)
929 {
930 EogJobSave *save_job;
931 GList *it;
932
933 /* initialization */
934 g_return_if_fail (EOG_IS_JOB_SAVE (job));
935
936 g_object_ref (job);
937
938 /* clean previous errors */
939 if (job->error) {
940 g_error_free (job->error);
941 job->error = NULL;
942 }
943
944 /* check if the current job was previously cancelled */
945 if (eog_job_is_cancelled (job))
946 return;
947
948 save_job = EOG_JOB_SAVE (job);
949
950 save_job->current_position = 0;
951
952 for (it = save_job->images; it != NULL; it = it->next, save_job->current_position++) {
953 EogImage *image = EOG_IMAGE (it->data);
954 EogImageSaveInfo *save_info = NULL;
955 gulong handler_id = 0;
956 gboolean success = FALSE;
957
958 save_job->current_image = image;
959
960 /* Make sure the image doesn't go away while saving */
961 eog_image_data_ref (image);
962
963 if (!eog_image_has_data (image, EOG_IMAGE_DATA_ALL)) {
964 EogImageMetadataStatus m_status;
965 gint data2load = 0;
966
967 m_status = eog_image_get_metadata_status (image);
968 if (!eog_image_has_data (image, EOG_IMAGE_DATA_IMAGE)) {
969 // Queue full read in this case
970 data2load = EOG_IMAGE_DATA_ALL;
971 } else if (m_status == EOG_IMAGE_METADATA_NOT_READ)
972 {
973 // Load only if we haven't read it yet
974 data2load = EOG_IMAGE_DATA_EXIF
975 | EOG_IMAGE_DATA_XMP;
976 }
977
978 if (data2load != 0) {
979 eog_image_load (image,
980 data2load,
981 NULL,
982 &job->error);
983 }
984 }
985
986 handler_id = g_signal_connect (G_OBJECT (image),
987 "save-progress",
988 G_CALLBACK (eog_job_save_progress_callback),
989 job);
990
991 save_info = eog_image_save_info_new_from_image (image);
992
993 success = eog_image_save_by_info (image,
994 save_info,
995 &job->error);
996
997 if (save_info)
998 g_object_unref (save_info);
999
1000 if (handler_id != 0)
1001 g_signal_handler_disconnect (G_OBJECT (image), handler_id);
1002
1003 eog_image_data_unref (image);
1004
1005 if (!success)
1006 break;
1007 }
1008
1009 /* --- enter critical section --- */
1010 g_mutex_lock (job->mutex);
1011
1012 /* job finished */
1013 job->finished = TRUE;
1014
1015 /* --- leave critical section --- */
1016 g_mutex_unlock (job->mutex);
1017
1018 /* notify job finalization */
1019 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
1020 (GSourceFunc) notify_finished,
1021 job,
1022 g_object_unref);
1023 }
1024
1025 /**
1026 * eog_job_save_new:
1027 * @images: (element-type EogImage) (transfer full): a #EogImage list
1028 *
1029 * Creates a new #EogJob for image saving.
1030 *
1031 * Returns: A #EogJob.
1032 */
1033
1034 EogJob *
eog_job_save_new(GList * images)1035 eog_job_save_new (GList *images)
1036 {
1037 EogJobSave *job;
1038
1039 job = g_object_new (EOG_TYPE_JOB_SAVE, NULL);
1040
1041 if (images)
1042 job->images = images;
1043
1044 /* show info for debugging */
1045 eog_debug_message (DEBUG_JOBS,
1046 "%s (%p) job was CREATED",
1047 EOG_GET_TYPE_NAME (job),
1048 job);
1049
1050 return EOG_JOB (job);
1051 }
1052
1053 /* ------------------------------- EogJobSaveAs -------------------------------- */
1054 static void
eog_job_save_as_class_init(EogJobSaveAsClass * class)1055 eog_job_save_as_class_init (EogJobSaveAsClass *class)
1056 {
1057 GObjectClass *g_object_class = (GObjectClass *) class;
1058 EogJobClass *eog_job_class = (EogJobClass *) class;
1059
1060 g_object_class->dispose = eog_job_save_as_dispose;
1061 eog_job_class->run = eog_job_save_as_run;
1062 }
1063
1064 static
eog_job_save_as_init(EogJobSaveAs * job)1065 void eog_job_save_as_init (EogJobSaveAs *job)
1066 {
1067 /* initialize all public and private members to reasonable
1068 default values. */
1069 job->converter = NULL;
1070 job->file = NULL;
1071 }
1072
1073 static
eog_job_save_as_dispose(GObject * object)1074 void eog_job_save_as_dispose (GObject *object)
1075 {
1076 EogJobSaveAs *job;
1077
1078 g_return_if_fail (EOG_IS_JOB_SAVE_AS (object));
1079
1080 job = EOG_JOB_SAVE_AS (object);
1081
1082 /* free all public and private members */
1083 if (job->converter != NULL) {
1084 g_object_unref (job->converter);
1085 job->converter = NULL;
1086 }
1087
1088 if (job->file != NULL) {
1089 g_object_unref (job->file);
1090 job->file = NULL;
1091 }
1092
1093 /* call parent dispose */
1094 G_OBJECT_CLASS (eog_job_save_as_parent_class)->dispose (object);
1095 }
1096
1097 static void
eog_job_save_as_run(EogJob * job)1098 eog_job_save_as_run (EogJob *job)
1099 {
1100 EogJobSave *save_job;
1101 EogJobSaveAs *saveas_job;
1102 GList *it;
1103 guint n_images;
1104
1105 /* initialization */
1106 g_return_if_fail (EOG_IS_JOB_SAVE_AS (job));
1107
1108 /* clean previous errors */
1109 if (job->error) {
1110 g_error_free (job->error);
1111 job->error = NULL;
1112 }
1113
1114 /* check if the current job was previously cancelled */
1115 if (eog_job_is_cancelled (job))
1116 return;
1117
1118 save_job = EOG_JOB_SAVE (g_object_ref (job));
1119 saveas_job = EOG_JOB_SAVE_AS (job);
1120
1121 save_job->current_position = 0;
1122 n_images = g_list_length (save_job->images);
1123
1124 for (it = save_job->images; it != NULL; it = it->next, save_job->current_position++) {
1125 GdkPixbufFormat *format;
1126 EogImageSaveInfo *src_info, *dest_info;
1127 EogImage *image = EOG_IMAGE (it->data);
1128 gboolean success = FALSE;
1129 gulong handler_id = 0;
1130
1131 save_job->current_image = image;
1132
1133 eog_image_data_ref (image);
1134
1135 if (!eog_image_has_data (image, EOG_IMAGE_DATA_ALL)) {
1136 EogImageMetadataStatus m_status;
1137 gint data2load = 0;
1138
1139 m_status = eog_image_get_metadata_status (image);
1140 if (!eog_image_has_data (image, EOG_IMAGE_DATA_IMAGE)) {
1141 // Queue full read in this case
1142 data2load = EOG_IMAGE_DATA_ALL;
1143 } else if (m_status == EOG_IMAGE_METADATA_NOT_READ)
1144 {
1145 // Load only if we haven't read it yet
1146 data2load = EOG_IMAGE_DATA_EXIF
1147 | EOG_IMAGE_DATA_XMP;
1148 }
1149
1150 if (data2load != 0) {
1151 eog_image_load (image,
1152 data2load,
1153 NULL,
1154 &job->error);
1155 }
1156 }
1157
1158
1159 g_assert (job->error == NULL);
1160
1161 handler_id = g_signal_connect (G_OBJECT (image),
1162 "save-progress",
1163 G_CALLBACK (eog_job_save_progress_callback),
1164 job);
1165
1166 src_info = eog_image_save_info_new_from_image (image);
1167
1168 if (n_images == 1) {
1169 g_assert (saveas_job->file != NULL);
1170
1171 format = eog_pixbuf_get_format (saveas_job->file);
1172
1173 dest_info = eog_image_save_info_new_from_file (saveas_job->file,
1174 format);
1175
1176 /* SaveAsDialog has already secured permission to overwrite */
1177 if (dest_info->exists) {
1178 dest_info->overwrite = TRUE;
1179 }
1180 } else {
1181 GFile *dest_file;
1182 gboolean result;
1183
1184 result = eog_uri_converter_do (saveas_job->converter,
1185 image,
1186 &dest_file,
1187 &format,
1188 NULL);
1189
1190 g_assert (result);
1191
1192 dest_info = eog_image_save_info_new_from_file (dest_file,
1193 format);
1194 }
1195
1196 success = eog_image_save_as_by_info (image,
1197 src_info,
1198 dest_info,
1199 &job->error);
1200
1201 if (src_info)
1202 g_object_unref (src_info);
1203
1204 if (dest_info)
1205 g_object_unref (dest_info);
1206
1207 if (handler_id != 0)
1208 g_signal_handler_disconnect (G_OBJECT (image), handler_id);
1209
1210 eog_image_data_unref (image);
1211
1212 if (!success)
1213 break;
1214 }
1215
1216 /* --- enter critical section --- */
1217 g_mutex_lock (job->mutex);
1218
1219 /* job finished */
1220 job->finished = TRUE;
1221
1222 /* --- leave critical section --- */
1223 g_mutex_unlock (job->mutex);
1224
1225 /* notify job finalization */
1226 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
1227 (GSourceFunc) notify_finished,
1228 job,
1229 g_object_unref);
1230 }
1231
1232 /**
1233 * eog_job_save_as_new:
1234 * @images: (element-type EogImage) (transfer full): a #EogImage list
1235 * @converter: a URI converter
1236 * file: a #GFile
1237 *
1238 * Creates a new #EogJog for save as.
1239 *
1240 * Returns: A #EogJob.
1241 */
1242
1243 EogJob *
eog_job_save_as_new(GList * images,EogURIConverter * converter,GFile * file)1244 eog_job_save_as_new (GList *images,
1245 EogURIConverter *converter,
1246 GFile *file)
1247 {
1248 EogJobSaveAs *job;
1249
1250 job = g_object_new (EOG_TYPE_JOB_SAVE_AS, NULL);
1251
1252 if (images)
1253 EOG_JOB_SAVE(job)->images = images;
1254
1255 if (converter)
1256 job->converter = g_object_ref (converter);
1257
1258 if (file)
1259 job->file = g_object_ref (file);
1260
1261 /* show info for debugging */
1262 eog_debug_message (DEBUG_JOBS,
1263 "%s (%p) job was CREATED",
1264 EOG_GET_TYPE_NAME (job),
1265 job);
1266
1267 return EOG_JOB (job);
1268 }
1269
1270 /* ------------------------------- EogJobThumbnail -------------------------------- */
1271 static void
eog_job_thumbnail_class_init(EogJobThumbnailClass * class)1272 eog_job_thumbnail_class_init (EogJobThumbnailClass *class)
1273 {
1274 GObjectClass *g_object_class = (GObjectClass *) class;
1275 EogJobClass *eog_job_class = (EogJobClass *) class;
1276
1277 g_object_class->dispose = eog_job_thumbnail_dispose;
1278 eog_job_class->run = eog_job_thumbnail_run;
1279 }
1280
1281 static
eog_job_thumbnail_init(EogJobThumbnail * job)1282 void eog_job_thumbnail_init (EogJobThumbnail *job)
1283 {
1284 /* initialize all public and private members to reasonable
1285 default values. */
1286 job->image = NULL;
1287 job->thumbnail = NULL;
1288 }
1289
1290 static
eog_job_thumbnail_dispose(GObject * object)1291 void eog_job_thumbnail_dispose (GObject *object)
1292 {
1293 EogJobThumbnail *job;
1294
1295 g_return_if_fail (EOG_IS_JOB_THUMBNAIL (object));
1296
1297 job = EOG_JOB_THUMBNAIL (object);
1298
1299 /* free all public and private members */
1300 if (job->image) {
1301 g_object_unref (job->image);
1302 job->image = NULL;
1303 }
1304
1305 if (job->thumbnail) {
1306 g_object_unref (job->thumbnail);
1307 job->thumbnail = NULL;
1308 }
1309
1310 /* call parent dispose */
1311 G_OBJECT_CLASS (eog_job_thumbnail_parent_class)->dispose (object);
1312 }
1313
1314 static void
eog_job_thumbnail_run(EogJob * job)1315 eog_job_thumbnail_run (EogJob *job)
1316 {
1317 EogJobThumbnail *job_thumbnail;
1318
1319 /* initialization */
1320 g_return_if_fail (EOG_IS_JOB_THUMBNAIL (job));
1321
1322 job_thumbnail = EOG_JOB_THUMBNAIL (g_object_ref (job));
1323
1324 /* clean previous errors */
1325 if (job->error) {
1326 g_error_free (job->error);
1327 job->error = NULL;
1328 }
1329
1330 /* try to load the image thumbnail from cache */
1331 job_thumbnail->thumbnail = eog_thumbnail_load (job_thumbnail->image,
1332 &job->error);
1333
1334 if (job_thumbnail->thumbnail) {
1335 GdkPixbuf *pixbuf;
1336 gchar *original_width;
1337 gchar *original_height;
1338 gint width;
1339 gint height;
1340
1341 /* create the image thumbnail */
1342 original_width = g_strdup (gdk_pixbuf_get_option
1343 (job_thumbnail->thumbnail,
1344 "tEXt::Thumb::Image::Width"));
1345 original_height = g_strdup (gdk_pixbuf_get_option
1346 (job_thumbnail->thumbnail,
1347 "tEXt::Thumb::Image::Height"));
1348
1349 pixbuf = eog_thumbnail_fit_to_size (job_thumbnail->thumbnail,
1350 EOG_LIST_STORE_THUMB_SIZE);
1351
1352 g_object_unref (job_thumbnail->thumbnail);
1353 job_thumbnail->thumbnail = eog_thumbnail_add_frame (pixbuf);
1354 g_object_unref (pixbuf);
1355
1356 if (original_width) {
1357 sscanf (original_width, "%i", &width);
1358 g_object_set_data (G_OBJECT (job_thumbnail->thumbnail),
1359 EOG_THUMBNAIL_ORIGINAL_WIDTH,
1360 GINT_TO_POINTER (width));
1361 g_free (original_width);
1362 }
1363
1364 if (original_height) {
1365 sscanf (original_height, "%i", &height);
1366 g_object_set_data (G_OBJECT (job_thumbnail->thumbnail),
1367 EOG_THUMBNAIL_ORIGINAL_HEIGHT,
1368 GINT_TO_POINTER (height));
1369 g_free (original_height);
1370 }
1371 }
1372
1373 /* show info for debugging */
1374 if (job->error)
1375 g_warning ("%s", job->error->message);
1376
1377 /* --- enter critical section --- */
1378 g_mutex_lock (job->mutex);
1379
1380 /* job finished */
1381 job->finished = TRUE;
1382
1383 /* --- leave critical section --- */
1384 g_mutex_unlock (job->mutex);
1385
1386 /* notify job finalization */
1387 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
1388 (GSourceFunc) notify_finished,
1389 job,
1390 g_object_unref);
1391 }
1392
1393 EogJob *
eog_job_thumbnail_new(EogImage * image)1394 eog_job_thumbnail_new (EogImage *image)
1395 {
1396 EogJobThumbnail *job;
1397
1398 job = g_object_new (EOG_TYPE_JOB_THUMBNAIL, NULL);
1399
1400 if (image)
1401 job->image = g_object_ref (image);
1402
1403 /* show info for debugging */
1404 eog_debug_message (DEBUG_JOBS,
1405 "%s (%p) job was CREATED",
1406 EOG_GET_TYPE_NAME (job),
1407 job);
1408
1409 return EOG_JOB (job);
1410 }
1411
1412 /* ------------------------------- EogJobTransform -------------------------------- */
1413 static void
eog_job_transform_class_init(EogJobTransformClass * class)1414 eog_job_transform_class_init (EogJobTransformClass *class)
1415 {
1416 GObjectClass *g_object_class = (GObjectClass *) class;
1417 EogJobClass *eog_job_class = (EogJobClass *) class;
1418
1419 g_object_class->dispose = eog_job_transform_dispose;
1420 eog_job_class->run = eog_job_transform_run;
1421 }
1422
1423 static
eog_job_transform_init(EogJobTransform * job)1424 void eog_job_transform_init (EogJobTransform *job)
1425 {
1426 /* initialize all public and private members to reasonable
1427 default values. */
1428 job->images = NULL;
1429 job->transform = NULL;
1430 }
1431
1432 static
eog_job_transform_dispose(GObject * object)1433 void eog_job_transform_dispose (GObject *object)
1434 {
1435 EogJobTransform *job;
1436
1437 g_return_if_fail (EOG_IS_JOB_TRANSFORM (object));
1438
1439 job = EOG_JOB_TRANSFORM (object);
1440
1441 /* free all public and private members */
1442 if (job->transform) {
1443 g_object_unref (job->transform);
1444 job->transform = NULL;
1445 }
1446
1447 if (job->images) {
1448 g_list_foreach (job->images, (GFunc) g_object_unref, NULL);
1449 g_list_free (job->images);
1450 }
1451
1452 /* call parent dispose */
1453 G_OBJECT_CLASS (eog_job_transform_parent_class)->dispose (object);
1454 }
1455
1456 static gboolean
eog_job_transform_image_modified(gpointer data)1457 eog_job_transform_image_modified (gpointer data)
1458 {
1459 g_return_val_if_fail (EOG_IS_IMAGE (data), FALSE);
1460
1461 eog_image_modified (EOG_IMAGE (data));
1462 g_object_unref (G_OBJECT (data));
1463
1464 return FALSE;
1465 }
1466
1467 static void
eog_job_transform_run(EogJob * job)1468 eog_job_transform_run (EogJob *job)
1469 {
1470 EogJobTransform *transjob;
1471 GList *it;
1472
1473 /* initialization */
1474 g_return_if_fail (EOG_IS_JOB_TRANSFORM (job));
1475
1476 transjob = EOG_JOB_TRANSFORM (g_object_ref (job));
1477
1478 /* clean previous errors */
1479 if (job->error) {
1480 g_error_free (job->error);
1481 job->error = NULL;
1482 }
1483
1484 /* check if the current job was previously cancelled */
1485 if (eog_job_is_cancelled (job))
1486 {
1487 g_object_unref (transjob);
1488 return;
1489 }
1490
1491 for (it = transjob->images; it != NULL; it = it->next) {
1492 EogImage *image = EOG_IMAGE (it->data);
1493
1494 if (transjob->transform == NULL) {
1495 eog_image_undo (image);
1496 } else {
1497 eog_image_transform (image, transjob->transform, job);
1498 }
1499
1500 if (eog_image_is_modified (image) || transjob->transform == NULL) {
1501 g_object_ref (image);
1502 g_idle_add (eog_job_transform_image_modified, image);
1503 }
1504
1505 if (G_UNLIKELY (eog_job_is_cancelled (job)))
1506 {
1507 g_object_unref (transjob);
1508 return;
1509 }
1510 }
1511
1512 /* --- enter critical section --- */
1513 g_mutex_lock (job->mutex);
1514
1515 /* job finished */
1516 job->finished = TRUE;
1517
1518 /* --- leave critical section --- */
1519 g_mutex_unlock (job->mutex);
1520
1521 /* notify job finalization */
1522 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
1523 (GSourceFunc) notify_finished,
1524 job,
1525 g_object_unref);
1526 }
1527
1528 /**
1529 * eog_job_transform_new:
1530 * @images: (element-type EogImage) (transfer full): a #EogImage list
1531 * @transform: a #EogTransform
1532 *
1533 * Create a new #EogJob for image transformation.
1534 *
1535 * Returns: A #EogJob.
1536 */
1537
1538 EogJob *
eog_job_transform_new(GList * images,EogTransform * transform)1539 eog_job_transform_new (GList *images,
1540 EogTransform *transform)
1541 {
1542 EogJobTransform *job;
1543
1544 job = g_object_new (EOG_TYPE_JOB_TRANSFORM, NULL);
1545
1546 if (images)
1547 job->images = images;
1548
1549 if (transform)
1550 job->transform = g_object_ref (transform);
1551
1552 /* show info for debugging */
1553 eog_debug_message (DEBUG_JOBS,
1554 "%s (%p) job was CREATED",
1555 EOG_GET_TYPE_NAME (job),
1556 job);
1557
1558 return EOG_JOB (job);
1559 }
1560