1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2 /*
3 * Libbrasero-burn
4 * Copyright (C) Philippe Rouquier 2005-2009 <bonfire-app@wanadoo.fr>
5 *
6 * Libbrasero-burn is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * The Libbrasero-burn authors hereby grant permission for non-GPL compatible
12 * GStreamer plugins to be used and distributed together with GStreamer
13 * and Libbrasero-burn. This permission is above and beyond the permissions granted
14 * by the GPL license by which Libbrasero-burn is covered. If you modify this code
15 * you may extend this exception to your version of the code, but you are not
16 * obligated to do so. If you do not wish to do so, delete this exception
17 * statement from your version.
18 *
19 * Libbrasero-burn is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU Library General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to:
26 * The Free Software Foundation, Inc.,
27 * 51 Franklin Street, Fifth Floor
28 * Boston, MA 02110-1301, USA.
29 */
30
31 #ifdef HAVE_CONFIG_H
32 # include <config.h>
33 #endif
34
35 #include <string.h>
36
37 #include <glib.h>
38 #include <glib-object.h>
39 #include <glib/gi18n-lib.h>
40
41 #include <gtk/gtk.h>
42
43 #include "burn-basics.h"
44 #include "burn-plugin-manager.h"
45 #include "brasero-medium-selection-priv.h"
46 #include "brasero-session-helper.h"
47
48 #include "brasero-dest-selection.h"
49
50 #include "brasero-drive.h"
51 #include "brasero-medium.h"
52 #include "brasero-volume.h"
53
54 #include "brasero-burn-lib.h"
55 #include "brasero-tags.h"
56 #include "brasero-track.h"
57 #include "brasero-session.h"
58 #include "brasero-session-cfg.h"
59
60 typedef struct _BraseroDestSelectionPrivate BraseroDestSelectionPrivate;
61 struct _BraseroDestSelectionPrivate
62 {
63 BraseroBurnSession *session;
64
65 BraseroDrive *locked_drive;
66
67 guint user_changed:1;
68 };
69
70 #define BRASERO_DEST_SELECTION_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), BRASERO_TYPE_DEST_SELECTION, BraseroDestSelectionPrivate))
71
72 enum {
73 PROP_0,
74 PROP_SESSION
75 };
76
77 G_DEFINE_TYPE (BraseroDestSelection, brasero_dest_selection, BRASERO_TYPE_MEDIUM_SELECTION);
78
79 static void
brasero_dest_selection_lock(BraseroDestSelection * self,gboolean locked)80 brasero_dest_selection_lock (BraseroDestSelection *self,
81 gboolean locked)
82 {
83 BraseroDestSelectionPrivate *priv;
84
85 priv = BRASERO_DEST_SELECTION_PRIVATE (self);
86
87 if (locked == (priv->locked_drive != NULL))
88 return;
89
90 gtk_widget_set_sensitive (GTK_WIDGET (self), (locked != TRUE));
91 gtk_widget_queue_draw (GTK_WIDGET (self));
92
93 if (priv->locked_drive) {
94 brasero_drive_unlock (priv->locked_drive);
95 g_object_unref (priv->locked_drive);
96 priv->locked_drive = NULL;
97 }
98
99 if (locked) {
100 BraseroMedium *medium;
101
102 medium = brasero_medium_selection_get_active (BRASERO_MEDIUM_SELECTION (self));
103 priv->locked_drive = brasero_medium_get_drive (medium);
104
105 if (priv->locked_drive) {
106 g_object_ref (priv->locked_drive);
107 brasero_drive_lock (priv->locked_drive,
108 _("Ongoing burning process"),
109 NULL);
110 }
111
112 if (medium)
113 g_object_unref (medium);
114 }
115 }
116
117 static void
brasero_dest_selection_valid_session(BraseroSessionCfg * session,BraseroDestSelection * self)118 brasero_dest_selection_valid_session (BraseroSessionCfg *session,
119 BraseroDestSelection *self)
120 {
121 brasero_medium_selection_update_media_string (BRASERO_MEDIUM_SELECTION (self));
122 }
123
124 static void
brasero_dest_selection_output_changed(BraseroSessionCfg * session,BraseroMedium * former,BraseroDestSelection * self)125 brasero_dest_selection_output_changed (BraseroSessionCfg *session,
126 BraseroMedium *former,
127 BraseroDestSelection *self)
128 {
129 BraseroDestSelectionPrivate *priv;
130 BraseroMedium *medium;
131 BraseroDrive *burner;
132
133 priv = BRASERO_DEST_SELECTION_PRIVATE (self);
134
135 /* make sure the current displayed drive reflects that */
136 burner = brasero_burn_session_get_burner (priv->session);
137 medium = brasero_medium_selection_get_active (BRASERO_MEDIUM_SELECTION (self));
138 if (burner != brasero_medium_get_drive (medium))
139 brasero_medium_selection_set_active (BRASERO_MEDIUM_SELECTION (self),
140 brasero_drive_get_medium (burner));
141
142 if (medium)
143 g_object_unref (medium);
144 }
145
146 static void
brasero_dest_selection_flags_changed(BraseroBurnSession * session,GParamSpec * pspec,BraseroDestSelection * self)147 brasero_dest_selection_flags_changed (BraseroBurnSession *session,
148 GParamSpec *pspec,
149 BraseroDestSelection *self)
150 {
151 BraseroDestSelectionPrivate *priv;
152
153 priv = BRASERO_DEST_SELECTION_PRIVATE (self);
154
155 brasero_dest_selection_lock (self, (brasero_burn_session_get_flags (BRASERO_BURN_SESSION (priv->session)) & BRASERO_BURN_FLAG_MERGE) != 0);
156 }
157
158 static void
brasero_dest_selection_medium_changed(BraseroMediumSelection * selection,BraseroMedium * medium)159 brasero_dest_selection_medium_changed (BraseroMediumSelection *selection,
160 BraseroMedium *medium)
161 {
162 BraseroDestSelectionPrivate *priv;
163
164 priv = BRASERO_DEST_SELECTION_PRIVATE (selection);
165
166 if (!priv->session)
167 goto chain;
168
169 if (!medium) {
170 gtk_widget_set_sensitive (GTK_WIDGET (selection), FALSE);
171 goto chain;
172 }
173
174 if (brasero_medium_get_drive (medium) == brasero_burn_session_get_burner (priv->session))
175 goto chain;
176
177 if (priv->locked_drive && priv->locked_drive != brasero_medium_get_drive (medium)) {
178 brasero_medium_selection_set_active (selection, medium);
179 goto chain;
180 }
181
182 brasero_burn_session_set_burner (priv->session, brasero_medium_get_drive (medium));
183 gtk_widget_set_sensitive (GTK_WIDGET (selection), (priv->locked_drive == NULL));
184
185 chain:
186
187 if (BRASERO_MEDIUM_SELECTION_CLASS (brasero_dest_selection_parent_class)->medium_changed)
188 BRASERO_MEDIUM_SELECTION_CLASS (brasero_dest_selection_parent_class)->medium_changed (selection, medium);
189 }
190
191 static void
brasero_dest_selection_user_change(BraseroDestSelection * selection,GParamSpec * pspec,gpointer NULL_data)192 brasero_dest_selection_user_change (BraseroDestSelection *selection,
193 GParamSpec *pspec,
194 gpointer NULL_data)
195 {
196 gboolean shown = FALSE;
197 BraseroDestSelectionPrivate *priv;
198
199 /* we are only interested when the menu is shown */
200 g_object_get (selection,
201 "popup-shown", &shown,
202 NULL);
203
204 if (!shown)
205 return;
206
207 priv = BRASERO_DEST_SELECTION_PRIVATE (selection);
208 priv->user_changed = TRUE;
209 }
210
211 static void
brasero_dest_selection_medium_removed(GtkTreeModel * model,GtkTreePath * path,gpointer user_data)212 brasero_dest_selection_medium_removed (GtkTreeModel *model,
213 GtkTreePath *path,
214 gpointer user_data)
215 {
216 BraseroDestSelectionPrivate *priv;
217
218 priv = BRASERO_DEST_SELECTION_PRIVATE (user_data);
219 if (priv->user_changed)
220 return;
221
222 if (gtk_combo_box_get_active (GTK_COMBO_BOX (user_data)) == -1)
223 brasero_dest_selection_choose_best (BRASERO_DEST_SELECTION (user_data));
224 }
225
226 static void
brasero_dest_selection_medium_added(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,gpointer user_data)227 brasero_dest_selection_medium_added (GtkTreeModel *model,
228 GtkTreePath *path,
229 GtkTreeIter *iter,
230 gpointer user_data)
231 {
232 BraseroDestSelectionPrivate *priv;
233
234 priv = BRASERO_DEST_SELECTION_PRIVATE (user_data);
235 if (priv->user_changed)
236 return;
237
238 brasero_dest_selection_choose_best (BRASERO_DEST_SELECTION (user_data));
239 }
240
241 static void
brasero_dest_selection_constructed(GObject * object)242 brasero_dest_selection_constructed (GObject *object)
243 {
244 G_OBJECT_CLASS (brasero_dest_selection_parent_class)->constructed (object);
245
246 /* Only show media on which we can write and which are in a burner.
247 * There is one exception though, when we're copying media and when the
248 * burning device is the same as the dest device. */
249 brasero_medium_selection_show_media_type (BRASERO_MEDIUM_SELECTION (object),
250 BRASERO_MEDIA_TYPE_WRITABLE|
251 BRASERO_MEDIA_TYPE_FILE);
252 }
253
254 static void
brasero_dest_selection_init(BraseroDestSelection * object)255 brasero_dest_selection_init (BraseroDestSelection *object)
256 {
257 GtkTreeModel *model;
258
259 model = gtk_combo_box_get_model (GTK_COMBO_BOX (object));
260 g_signal_connect (model,
261 "row-inserted",
262 G_CALLBACK (brasero_dest_selection_medium_added),
263 object);
264 g_signal_connect (model,
265 "row-deleted",
266 G_CALLBACK (brasero_dest_selection_medium_removed),
267 object);
268
269 /* This is to know when the user changed it on purpose */
270 g_signal_connect (object,
271 "notify::popup-shown",
272 G_CALLBACK (brasero_dest_selection_user_change),
273 NULL);
274 }
275
276 static void
brasero_dest_selection_clean(BraseroDestSelection * self)277 brasero_dest_selection_clean (BraseroDestSelection *self)
278 {
279 BraseroDestSelectionPrivate *priv;
280
281 priv = BRASERO_DEST_SELECTION_PRIVATE (self);
282
283 if (priv->session) {
284 g_signal_handlers_disconnect_by_func (priv->session,
285 brasero_dest_selection_valid_session,
286 self);
287 g_signal_handlers_disconnect_by_func (priv->session,
288 brasero_dest_selection_output_changed,
289 self);
290 g_signal_handlers_disconnect_by_func (priv->session,
291 brasero_dest_selection_flags_changed,
292 self);
293
294 g_object_unref (priv->session);
295 priv->session = NULL;
296 }
297
298 if (priv->locked_drive) {
299 brasero_drive_unlock (priv->locked_drive);
300 g_object_unref (priv->locked_drive);
301 priv->locked_drive = NULL;
302 }
303 }
304
305 static void
brasero_dest_selection_finalize(GObject * object)306 brasero_dest_selection_finalize (GObject *object)
307 {
308 brasero_dest_selection_clean (BRASERO_DEST_SELECTION (object));
309 G_OBJECT_CLASS (brasero_dest_selection_parent_class)->finalize (object);
310 }
311
312 static goffset
_get_medium_free_space(BraseroMedium * medium,goffset session_blocks)313 _get_medium_free_space (BraseroMedium *medium,
314 goffset session_blocks)
315 {
316 BraseroMedia media;
317 goffset blocks = 0;
318
319 media = brasero_medium_get_status (medium);
320 media = brasero_burn_library_get_media_capabilities (media);
321
322 /* NOTE: we always try to blank a medium when we can */
323 brasero_medium_get_free_space (medium,
324 NULL,
325 &blocks);
326
327 if ((media & BRASERO_MEDIUM_REWRITABLE)
328 && blocks < session_blocks)
329 brasero_medium_get_capacity (medium,
330 NULL,
331 &blocks);
332
333 return blocks;
334 }
335
336 static gboolean
brasero_dest_selection_foreach_medium(BraseroMedium * medium,gpointer callback_data)337 brasero_dest_selection_foreach_medium (BraseroMedium *medium,
338 gpointer callback_data)
339 {
340 BraseroBurnSession *session;
341 goffset session_blocks = 0;
342 goffset burner_blocks = 0;
343 goffset medium_blocks;
344 BraseroDrive *burner;
345
346 session = callback_data;
347 burner = brasero_burn_session_get_burner (session);
348 if (!burner) {
349 brasero_burn_session_set_burner (session, brasero_medium_get_drive (medium));
350 return TRUE;
351 }
352
353 /* no need to deal with this case */
354 if (brasero_drive_get_medium (burner) == medium)
355 return TRUE;
356
357 /* The rule is:
358 * - blank media are our favourite since it avoids hiding/blanking data
359 * - take the medium that is closest to the size we need to burn
360 * - try to avoid a medium that is already our source for copying */
361 /* NOTE: we could check if medium is bigger */
362 if ((brasero_burn_session_get_dest_media (session) & BRASERO_MEDIUM_BLANK)
363 && (brasero_medium_get_status (medium) & BRASERO_MEDIUM_BLANK))
364 goto choose_closest_size;
365
366 if (brasero_burn_session_get_dest_media (session) & BRASERO_MEDIUM_BLANK)
367 return TRUE;
368
369 if (brasero_medium_get_status (medium) & BRASERO_MEDIUM_BLANK) {
370 brasero_burn_session_set_burner (session, brasero_medium_get_drive (medium));
371 return TRUE;
372 }
373
374 /* In case it is the same source/same destination, choose it this new
375 * medium except if the medium is a file. */
376 if (brasero_burn_session_same_src_dest_drive (session)
377 && (brasero_medium_get_status (medium) & BRASERO_MEDIUM_FILE) == 0) {
378 brasero_burn_session_set_burner (session, brasero_medium_get_drive (medium));
379 return TRUE;
380 }
381
382 /* Any possible medium is better than file even if it means copying to
383 * the same drive with a new medium later. */
384 if (brasero_drive_is_fake (burner)
385 && (brasero_medium_get_status (medium) & BRASERO_MEDIUM_FILE) == 0) {
386 brasero_burn_session_set_burner (session, brasero_medium_get_drive (medium));
387 return TRUE;
388 }
389
390
391 choose_closest_size:
392
393 brasero_burn_session_get_size (session, &session_blocks, NULL);
394 medium_blocks = _get_medium_free_space (medium, session_blocks);
395
396 if (medium_blocks - session_blocks <= 0)
397 return TRUE;
398
399 burner_blocks = _get_medium_free_space (brasero_drive_get_medium (burner), session_blocks);
400 if (burner_blocks - session_blocks <= 0)
401 brasero_burn_session_set_burner (session, brasero_medium_get_drive (medium));
402 else if (burner_blocks - session_blocks > medium_blocks - session_blocks)
403 brasero_burn_session_set_burner (session, brasero_medium_get_drive (medium));
404
405 return TRUE;
406 }
407
408 void
brasero_dest_selection_choose_best(BraseroDestSelection * self)409 brasero_dest_selection_choose_best (BraseroDestSelection *self)
410 {
411 BraseroDestSelectionPrivate *priv;
412
413 priv = BRASERO_DEST_SELECTION_PRIVATE (self);
414
415 priv->user_changed = FALSE;
416 if (!priv->session)
417 return;
418
419 if (!(brasero_burn_session_get_flags (priv->session) & BRASERO_BURN_FLAG_MERGE)) {
420 BraseroDrive *drive;
421
422 /* Select the best fitting media */
423 brasero_medium_selection_foreach (BRASERO_MEDIUM_SELECTION (self),
424 brasero_dest_selection_foreach_medium,
425 priv->session);
426
427 drive = brasero_burn_session_get_burner (BRASERO_BURN_SESSION (priv->session));
428 if (drive)
429 brasero_medium_selection_set_active (BRASERO_MEDIUM_SELECTION (self),
430 brasero_drive_get_medium (drive));
431 }
432 }
433
434 void
brasero_dest_selection_set_session(BraseroDestSelection * selection,BraseroBurnSession * session)435 brasero_dest_selection_set_session (BraseroDestSelection *selection,
436 BraseroBurnSession *session)
437 {
438 BraseroDestSelectionPrivate *priv;
439
440 priv = BRASERO_DEST_SELECTION_PRIVATE (selection);
441
442 if (priv->session)
443 brasero_dest_selection_clean (selection);
444
445 if (!session)
446 return;
447
448 priv->session = g_object_ref (session);
449 if (brasero_burn_session_get_flags (session) & BRASERO_BURN_FLAG_MERGE) {
450 BraseroDrive *drive;
451
452 /* Prevent automatic resetting since a drive was set */
453 priv->user_changed = TRUE;
454
455 drive = brasero_burn_session_get_burner (session);
456 brasero_medium_selection_set_active (BRASERO_MEDIUM_SELECTION (selection),
457 brasero_drive_get_medium (drive));
458 }
459 else {
460 BraseroDrive *burner;
461
462 /* Only try to set a better drive if there isn't one already set */
463 burner = brasero_burn_session_get_burner (BRASERO_BURN_SESSION (priv->session));
464 if (burner) {
465 BraseroMedium *medium;
466
467 /* Prevent automatic resetting since a drive was set */
468 priv->user_changed = TRUE;
469
470 medium = brasero_drive_get_medium (burner);
471 brasero_medium_selection_set_active (BRASERO_MEDIUM_SELECTION (selection), medium);
472 }
473 else
474 brasero_dest_selection_choose_best (BRASERO_DEST_SELECTION (selection));
475 }
476
477 g_signal_connect (session,
478 "is-valid",
479 G_CALLBACK (brasero_dest_selection_valid_session),
480 selection);
481 g_signal_connect (session,
482 "output-changed",
483 G_CALLBACK (brasero_dest_selection_output_changed),
484 selection);
485 g_signal_connect (session,
486 "notify::flags",
487 G_CALLBACK (brasero_dest_selection_flags_changed),
488 selection);
489
490 brasero_medium_selection_update_media_string (BRASERO_MEDIUM_SELECTION (selection));
491 }
492
493 static void
brasero_dest_selection_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)494 brasero_dest_selection_set_property (GObject *object,
495 guint property_id,
496 const GValue *value,
497 GParamSpec *pspec)
498 {
499 BraseroBurnSession *session;
500
501 switch (property_id) {
502 case PROP_SESSION: /* Readable and only writable at creation time */
503 /* NOTE: no need to unref a potential previous session since
504 * it's only set at construct time */
505 session = g_value_get_object (value);
506 brasero_dest_selection_set_session (BRASERO_DEST_SELECTION (object), session);
507 break;
508
509 default:
510 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
511 }
512 }
513
514 static void
brasero_dest_selection_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)515 brasero_dest_selection_get_property (GObject *object,
516 guint property_id,
517 GValue *value,
518 GParamSpec *pspec)
519 {
520 BraseroDestSelectionPrivate *priv;
521
522 priv = BRASERO_DEST_SELECTION_PRIVATE (object);
523
524 switch (property_id) {
525 case PROP_SESSION:
526 g_object_ref (priv->session);
527 g_value_set_object (value, priv->session);
528 break;
529
530 default:
531 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
532 }
533 }
534
535 static gchar *
brasero_dest_selection_get_output_path(BraseroDestSelection * self)536 brasero_dest_selection_get_output_path (BraseroDestSelection *self)
537 {
538 gchar *path = NULL;
539 BraseroImageFormat format;
540 BraseroDestSelectionPrivate *priv;
541
542 priv = BRASERO_DEST_SELECTION_PRIVATE (self);
543
544 format = brasero_burn_session_get_output_format (priv->session);
545 switch (format) {
546 case BRASERO_IMAGE_FORMAT_BIN:
547 brasero_burn_session_get_output (priv->session,
548 &path,
549 NULL);
550 break;
551
552 case BRASERO_IMAGE_FORMAT_CLONE:
553 case BRASERO_IMAGE_FORMAT_CDRDAO:
554 case BRASERO_IMAGE_FORMAT_CUE:
555 brasero_burn_session_get_output (priv->session,
556 NULL,
557 &path);
558 break;
559
560 default:
561 break;
562 }
563
564 return path;
565 }
566
567 static gchar *
brasero_dest_selection_format_medium_string(BraseroMediumSelection * selection,BraseroMedium * medium)568 brasero_dest_selection_format_medium_string (BraseroMediumSelection *selection,
569 BraseroMedium *medium)
570 {
571 guint used;
572 gchar *label;
573 goffset blocks = 0;
574 gchar *medium_name;
575 gchar *size_string;
576 BraseroMedia media;
577 BraseroBurnFlag flags;
578 goffset size_bytes = 0;
579 goffset data_blocks = 0;
580 goffset session_bytes = 0;
581 BraseroTrackType *input = NULL;
582 BraseroDestSelectionPrivate *priv;
583
584 priv = BRASERO_DEST_SELECTION_PRIVATE (selection);
585
586 if (!priv->session)
587 return NULL;
588
589 medium_name = brasero_volume_get_name (BRASERO_VOLUME (medium));
590 if (brasero_medium_get_status (medium) & BRASERO_MEDIUM_FILE) {
591 gchar *path;
592
593 input = brasero_track_type_new ();
594 brasero_burn_session_get_input_type (priv->session, input);
595
596 /* There should be a special name for image in video context */
597 if (brasero_track_type_get_has_stream (input)
598 && BRASERO_STREAM_FORMAT_HAS_VIDEO (brasero_track_type_get_stream_format (input))) {
599 BraseroImageFormat format;
600
601 format = brasero_burn_session_get_output_format (priv->session);
602 if (format == BRASERO_IMAGE_FORMAT_CUE) {
603 g_free (medium_name);
604 if (brasero_burn_session_tag_lookup_int (priv->session, BRASERO_VCD_TYPE) == BRASERO_SVCD)
605 medium_name = g_strdup (_("SVCD image"));
606 else
607 medium_name = g_strdup (_("VCD image"));
608 }
609 else if (format == BRASERO_IMAGE_FORMAT_BIN) {
610 g_free (medium_name);
611 medium_name = g_strdup (_("Video DVD image"));
612 }
613 }
614 brasero_track_type_free (input);
615
616 /* get the set path for the image file */
617 path = brasero_dest_selection_get_output_path (BRASERO_DEST_SELECTION (selection));
618 if (!path)
619 return medium_name;
620
621 /* NOTE for translators: the first %s is medium_name ("File
622 * Image") and the second the path for the image file */
623 label = g_strdup_printf (_("%s: \"%s\""),
624 medium_name,
625 path);
626 g_free (medium_name);
627 g_free (path);
628
629 brasero_medium_selection_update_used_space (BRASERO_MEDIUM_SELECTION (selection),
630 medium,
631 0);
632 return label;
633 }
634
635 if (!priv->session) {
636 g_free (medium_name);
637 return NULL;
638 }
639
640 input = brasero_track_type_new ();
641 brasero_burn_session_get_input_type (priv->session, input);
642 if (brasero_track_type_get_has_medium (input)) {
643 BraseroMedium *src_medium;
644
645 src_medium = brasero_burn_session_get_src_medium (priv->session);
646 if (src_medium == medium) {
647 brasero_track_type_free (input);
648
649 /* Translators: this string is only used when the user
650 * wants to copy a disc using the same destination and
651 * source drive. It tells him that brasero will use as
652 * destination disc a new one (once the source has been
653 * copied) which is to be inserted in the drive currently
654 * holding the source disc */
655 label = g_strdup_printf (_("New disc in the burner holding the source disc"));
656 g_free (medium_name);
657
658 brasero_medium_selection_update_used_space (BRASERO_MEDIUM_SELECTION (selection),
659 medium,
660 0);
661 return label;
662 }
663 }
664
665 media = brasero_medium_get_status (medium);
666 flags = brasero_burn_session_get_flags (priv->session);
667 brasero_burn_session_get_size (priv->session,
668 &data_blocks,
669 &session_bytes);
670
671 if (flags & (BRASERO_BURN_FLAG_MERGE|BRASERO_BURN_FLAG_APPEND))
672 brasero_medium_get_free_space (medium, &size_bytes, &blocks);
673 else if (brasero_burn_library_get_media_capabilities (media) & BRASERO_MEDIUM_REWRITABLE)
674 brasero_medium_get_capacity (medium, &size_bytes, &blocks);
675 else
676 brasero_medium_get_free_space (medium, &size_bytes, &blocks);
677
678 if (blocks) {
679 used = data_blocks * 100 / blocks;
680 if (data_blocks && !used)
681 used = 1;
682
683 used = MIN (100, used);
684 }
685 else
686 used = 0;
687
688 brasero_medium_selection_update_used_space (BRASERO_MEDIUM_SELECTION (selection),
689 medium,
690 used);
691 blocks -= data_blocks;
692 if (blocks <= 0) {
693 brasero_track_type_free (input);
694
695 /* NOTE for translators, the first %s is the medium name */
696 label = g_strdup_printf (_("%s: not enough free space"), medium_name);
697 g_free (medium_name);
698 return label;
699 }
700
701 /* format the size */
702 if (brasero_track_type_get_has_stream (input)
703 && BRASERO_STREAM_FORMAT_HAS_VIDEO (brasero_track_type_get_stream_format (input))) {
704 guint64 free_time;
705
706 /* This is an embarassing problem: this is an approximation
707 * based on the fact that 2 hours = 4.3GiB */
708 free_time = size_bytes - session_bytes;
709 free_time = free_time * 72000LL / 47LL;
710 size_string = brasero_units_get_time_string (free_time,
711 TRUE,
712 TRUE);
713 }
714 else if (brasero_track_type_get_has_stream (input)
715 || (brasero_track_type_get_has_medium (input)
716 && (brasero_track_type_get_medium_type (input) & BRASERO_MEDIUM_HAS_AUDIO)))
717 size_string = brasero_units_get_time_string (BRASERO_SECTORS_TO_DURATION (blocks),
718 TRUE,
719 TRUE);
720 else
721 size_string = g_format_size (size_bytes - session_bytes);
722
723 brasero_track_type_free (input);
724
725 /* NOTE for translators: the first %s is the medium name, the second %s
726 * is its available free space. "Free" here is the free space available. */
727 label = g_strdup_printf (_("%s: %s of free space"), medium_name, size_string);
728 g_free (medium_name);
729 g_free (size_string);
730
731 return label;
732 }
733
734 static void
brasero_dest_selection_class_init(BraseroDestSelectionClass * klass)735 brasero_dest_selection_class_init (BraseroDestSelectionClass *klass)
736 {
737 GObjectClass* object_class = G_OBJECT_CLASS (klass);
738 BraseroMediumSelectionClass *medium_selection_class = BRASERO_MEDIUM_SELECTION_CLASS (klass);
739
740 g_type_class_add_private (klass, sizeof (BraseroDestSelectionPrivate));
741
742 object_class->finalize = brasero_dest_selection_finalize;
743 object_class->set_property = brasero_dest_selection_set_property;
744 object_class->get_property = brasero_dest_selection_get_property;
745 object_class->constructed = brasero_dest_selection_constructed;
746
747 medium_selection_class->format_medium_string = brasero_dest_selection_format_medium_string;
748 medium_selection_class->medium_changed = brasero_dest_selection_medium_changed;
749 g_object_class_install_property (object_class,
750 PROP_SESSION,
751 g_param_spec_object ("session",
752 "The session",
753 "The session to work with",
754 BRASERO_TYPE_BURN_SESSION,
755 G_PARAM_READWRITE));
756 }
757
758 GtkWidget *
brasero_dest_selection_new(BraseroBurnSession * session)759 brasero_dest_selection_new (BraseroBurnSession *session)
760 {
761 return g_object_new (BRASERO_TYPE_DEST_SELECTION,
762 "session", session,
763 NULL);
764 }
765