~mfisch/brasero/update-to-3.8.0

« back to all changes in this revision

Viewing changes to src/brasero-project-size.c

  • Committer: Bazaar Package Importer
  • Author(s): Pedro Fragoso
  • Date: 2008-11-18 11:30:50 UTC
  • mto: (1.4.1 experimental)
  • mto: This revision was merged to the branch mainline in revision 29.
  • Revision ID: james.westby@ubuntu.com-20081118113050-yhrskmatlel0gzfm
Tags: upstream-0.8.3
ImportĀ upstreamĀ versionĀ 0.8.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/***************************************************************************
2
 
 *            brasero-project-size.c
3
 
 *
4
 
 *  jeu jui 27 11:54:52 2006
5
 
 *  Copyright  2006  Rouquier Philippe
6
 
 *  brasero-app@wanadoo.fr
7
 
 ***************************************************************************/
8
 
 
9
 
/*
10
 
 *  Brasero 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
 
 *  Brasero 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 Library General Public License for more details.
19
 
 *
20
 
 *  You should have received a copy of the GNU General Public License
21
 
 *  along with this program; if not, write to:
22
 
 *      The Free Software Foundation, Inc.,
23
 
 *      51 Franklin Street, Fifth Floor
24
 
 *      Boston, MA  02110-1301, USA.
25
 
 */
26
 
 
27
 
#ifdef HAVE_CONFIG_H
28
 
#  include <config.h>
29
 
#endif
30
 
 
31
 
#include <string.h>
32
 
 
33
 
#include <glib.h>
34
 
#include <glib-object.h>
35
 
#include <glib/gi18n-lib.h>
36
 
 
37
 
#include <gtk/gtkwidget.h>
38
 
#include <gtk/gtkmenu.h>
39
 
#include <gtk/gtkcontainer.h>
40
 
 
41
 
#include "brasero-project-type-chooser.h"
42
 
#include "brasero-project-size.h"
43
 
#include "burn-caps.h"
44
 
#include "burn-volume-obj.h"
45
 
#include "brasero-utils.h"
46
 
#include "burn-medium-monitor.h"
47
 
#include "burn-medium.h"
48
 
 
49
 
static void brasero_project_size_class_init (BraseroProjectSizeClass *klass);
50
 
static void brasero_project_size_init (BraseroProjectSize *sp);
51
 
static void brasero_project_size_finalize (GObject *object);
52
 
 
53
 
static void brasero_project_size_realize (GtkWidget *widget);
54
 
static void brasero_project_size_unrealize (GtkWidget *widget);
55
 
 
56
 
static void
57
 
brasero_project_size_size_request (GtkWidget *widget,
58
 
                                   GtkRequisition *requisition);
59
 
static void
60
 
brasero_project_size_size_allocate (GtkWidget *widget,
61
 
                                    GtkAllocation *allocation);
62
 
 
63
 
static gboolean
64
 
brasero_project_size_expose (GtkWidget *widget,
65
 
                             GdkEventExpose *event);
66
 
 
67
 
static void
68
 
brasero_project_size_button_toggled_cb (GtkToggleButton *button,
69
 
                                        BraseroProjectSize *self);
70
 
 
71
 
static gboolean
72
 
brasero_project_size_scroll_event (GtkWidget *widget,
73
 
                                   GdkEventScroll *event);
74
 
 
75
 
static void
76
 
brasero_project_size_add_real_medias (BraseroProjectSize *self);
77
 
 
78
 
static void
79
 
brasero_project_size_disc_changed_cb (GtkMenuItem *item,
80
 
                                      BraseroProjectSize *self);
81
 
 
82
 
static void
83
 
brasero_project_size_forall_children (GtkContainer *container,
84
 
                                      gboolean include_internals,
85
 
                                      GtkCallback callback,
86
 
                                      gpointer callback_data);
87
 
 
88
 
struct _BraseroDriveSize {
89
 
        gint64 sectors;
90
 
        gint64 free_space;
91
 
        BraseroMedia media;
92
 
        BraseroMedium *medium;
93
 
};
94
 
typedef struct _BraseroDriveSize BraseroDriveSize;
95
 
 
96
 
struct _BraseroProjectSizePrivate {
97
 
        GtkWidget *menu;
98
 
        
99
 
        GtkWidget *frame;
100
 
        GtkWidget *arrow;
101
 
        GtkWidget *button;
102
 
 
103
 
        gint ruler_height;
104
 
 
105
 
        gint refresh_id;
106
 
 
107
 
        PangoLayout *text_layout;
108
 
 
109
 
        gint64 sectors;
110
 
        GList *drives;
111
 
        BraseroDriveSize *current;
112
 
 
113
 
        BraseroProjectType context;
114
 
 
115
 
        guint was_chosen:1;
116
 
        guint is_loaded:1;
117
 
        guint multi:1;
118
 
};
119
 
 
120
 
 
121
 
enum _BraseroProjectSizeSignalType {
122
 
        DISC_CHANGED_SIGNAL,
123
 
        LAST_SIGNAL
124
 
};
125
 
 
126
 
#define BRASERO_PROJECT_SIZE_HEIGHT     42
127
 
 
128
 
#define BRASERO_PROJECT_SIZE_SPACE      12
129
 
 
130
 
#define BRASERO_ARROW_NUM       4
131
 
#define ARROW_WIDTH     6
132
 
#define ARROW_HEIGHT    8
133
 
 
134
 
#define AUDIO_SECTOR_SIZE 2352
135
 
#define DATA_SECTOR_SIZE 2048
136
 
 
137
 
#define AUDIO_INTERVAL_CD       67500
138
 
#define DATA_INTERVAL_CD        51200
139
 
#define DATA_INTERVAL_DVD       262144
140
 
#define MAX_INTERVAL            9
141
 
#define MIN_INTERVAL            5
142
 
 
143
 
#define DRIVE_STRUCT    "drive-struct"
144
 
 
145
 
static guint brasero_project_size_signals [LAST_SIGNAL] = { 0 };
146
 
static GtkWidgetClass *parent_class = NULL;
147
 
 
148
 
GType
149
 
brasero_project_size_get_type ()
150
 
{
151
 
        static GType type = 0;
152
 
 
153
 
        if(type == 0) {
154
 
                static const GTypeInfo our_info = {
155
 
                        sizeof (BraseroProjectSizeClass),
156
 
                        NULL,
157
 
                        NULL,
158
 
                        (GClassInitFunc)brasero_project_size_class_init,
159
 
                        NULL,
160
 
                        NULL,
161
 
                        sizeof (BraseroProjectSize),
162
 
                        0,
163
 
                        (GInstanceInitFunc)brasero_project_size_init,
164
 
                };
165
 
 
166
 
                type = g_type_register_static (GTK_TYPE_CONTAINER, 
167
 
                                               "BraseroProjectSize",
168
 
                                               &our_info,
169
 
                                               0);
170
 
        }
171
 
 
172
 
        return type;
173
 
}
174
 
 
175
 
static void
176
 
brasero_project_size_class_init (BraseroProjectSizeClass *klass)
177
 
{
178
 
        GObjectClass *object_class = G_OBJECT_CLASS (klass);
179
 
        GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
180
 
        GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
181
 
 
182
 
        parent_class = g_type_class_peek_parent(klass);
183
 
        object_class->finalize = brasero_project_size_finalize;
184
 
 
185
 
        widget_class->scroll_event = brasero_project_size_scroll_event;
186
 
 
187
 
        widget_class->size_request = brasero_project_size_size_request;
188
 
        widget_class->size_allocate = brasero_project_size_size_allocate;
189
 
        widget_class->expose_event = brasero_project_size_expose;
190
 
        widget_class->realize = brasero_project_size_realize;
191
 
        widget_class->unrealize = brasero_project_size_unrealize;
192
 
 
193
 
        container_class->forall = brasero_project_size_forall_children;
194
 
 
195
 
        brasero_project_size_signals [DISC_CHANGED_SIGNAL] =
196
 
            g_signal_new ("disc_changed",
197
 
                          G_OBJECT_CLASS_TYPE (object_class),
198
 
                          G_SIGNAL_ACTION|G_SIGNAL_NO_RECURSE|G_SIGNAL_RUN_FIRST,
199
 
                          G_STRUCT_OFFSET (BraseroProjectSizeClass, disc_changed),
200
 
                          NULL, NULL,
201
 
                          g_cclosure_marshal_VOID__VOID,
202
 
                          G_TYPE_NONE,
203
 
                          0);
204
 
}
205
 
 
206
 
static void
207
 
brasero_project_size_add_default_medias (BraseroProjectSize *self)
208
 
{
209
 
        const BraseroDriveSize drives [] =  { {333000, 333000, BRASERO_MEDIUM_CDR|BRASERO_MEDIUM_BLANK, NULL},
210
 
                                          {360000, 360000, BRASERO_MEDIUM_CDR|BRASERO_MEDIUM_BLANK, NULL},
211
 
                                          {405000, 405000, BRASERO_MEDIUM_CDR|BRASERO_MEDIUM_BLANK, NULL},
212
 
                                          {450000, 450000, BRASERO_MEDIUM_CDR|BRASERO_MEDIUM_BLANK, NULL},
213
 
                                          {2295104, 2295104, BRASERO_MEDIUM_DVDR|BRASERO_MEDIUM_BLANK, NULL},
214
 
                                          {4150390, 4150390, BRASERO_MEDIUM_DVDR_DL|BRASERO_MEDIUM_BLANK, NULL},
215
 
                                          { 0 } };
216
 
        const BraseroDriveSize *iter;
217
 
 
218
 
        for (iter = drives; iter->sectors; iter ++) {
219
 
                BraseroDriveSize *drive;
220
 
 
221
 
                drive = g_new0 (BraseroDriveSize, 1);
222
 
                memcpy (drive, iter, sizeof (BraseroDriveSize));
223
 
                self->priv->drives = g_list_prepend (self->priv->drives, drive);
224
 
        }
225
 
}
226
 
 
227
 
static void
228
 
brasero_project_size_init (BraseroProjectSize *obj)
229
 
{
230
 
        GtkWidget *image;
231
 
 
232
 
        GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (obj), GTK_NO_WINDOW);
233
 
 
234
 
        obj->priv = g_new0 (BraseroProjectSizePrivate, 1);
235
 
        obj->priv->text_layout = gtk_widget_create_pango_layout (GTK_WIDGET (obj), "");
236
 
 
237
 
        brasero_project_size_add_default_medias (obj);
238
 
 
239
 
        obj->priv->button = gtk_toggle_button_new ();
240
 
        gtk_widget_set_tooltip_text (obj->priv->button,
241
 
                              _("Show the available media to be burnt"));
242
 
        gtk_container_set_border_width (GTK_CONTAINER (obj->priv->button), 0);
243
 
        g_signal_connect (obj->priv->button,
244
 
                          "toggled",
245
 
                          G_CALLBACK (brasero_project_size_button_toggled_cb),
246
 
                          obj);
247
 
        gtk_button_set_focus_on_click (GTK_BUTTON (obj->priv->button), FALSE);
248
 
        GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (obj->priv->button), GTK_CAN_DEFAULT);
249
 
        GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (obj->priv->button), GTK_CAN_FOCUS);
250
 
 
251
 
        image = gtk_image_new_from_stock (GTK_STOCK_CDROM, GTK_ICON_SIZE_BUTTON);
252
 
        gtk_button_set_image (GTK_BUTTON (obj->priv->button), image);
253
 
 
254
 
        gtk_widget_set_parent (obj->priv->button, GTK_WIDGET (obj));
255
 
        gtk_widget_show_all (obj->priv->button);
256
 
 
257
 
        obj->priv->arrow = gtk_arrow_new (GTK_ARROW_UP, GTK_SHADOW_NONE);
258
 
        gtk_widget_set_parent (obj->priv->arrow, GTK_WIDGET (obj));
259
 
        gtk_widget_show_all (obj->priv->arrow);
260
 
 
261
 
        obj->priv->frame = gtk_frame_new (NULL);
262
 
        gtk_frame_set_shadow_type (GTK_FRAME (obj->priv->frame), GTK_SHADOW_IN);
263
 
 
264
 
        gtk_widget_set_parent (obj->priv->frame, GTK_WIDGET (obj));
265
 
        gtk_widget_show_all (obj->priv->frame);
266
 
}
267
 
 
268
 
static void
269
 
brasero_project_size_finalize (GObject *object)
270
 
{
271
 
        BraseroProjectSize *cobj;
272
 
        GList *iter;
273
 
 
274
 
        cobj = BRASERO_PROJECT_SIZE (object);
275
 
 
276
 
        if (cobj->priv->frame) {
277
 
                gtk_widget_unparent (cobj->priv->frame);
278
 
                cobj->priv->frame = NULL;
279
 
        }
280
 
 
281
 
        if (cobj->priv->button) {
282
 
                gtk_widget_unparent (cobj->priv->button);
283
 
                cobj->priv->button = NULL;
284
 
        }
285
 
 
286
 
        if (cobj->priv->arrow) {
287
 
                gtk_widget_unparent (cobj->priv->arrow);
288
 
                cobj->priv->arrow = NULL;
289
 
        }
290
 
 
291
 
        if (cobj->priv->refresh_id) {
292
 
                g_source_remove (cobj->priv->refresh_id);
293
 
                cobj->priv->refresh_id = 0;
294
 
        }
295
 
 
296
 
        if (cobj->priv->menu) {
297
 
                gtk_widget_destroy (cobj->priv->menu);
298
 
                cobj->priv->menu = NULL;
299
 
        }
300
 
 
301
 
        if (cobj->priv->text_layout) {
302
 
                g_object_unref (cobj->priv->text_layout);
303
 
                cobj->priv->text_layout = NULL;
304
 
        }
305
 
 
306
 
        for (iter = cobj->priv->drives; iter; iter = iter->next) {
307
 
                BraseroDriveSize *drive;
308
 
 
309
 
                drive = iter->data;
310
 
 
311
 
                if (drive->medium)
312
 
                        g_object_unref (drive->medium);
313
 
 
314
 
                g_free (drive);
315
 
        }
316
 
        g_list_free (cobj->priv->drives);
317
 
 
318
 
        g_free (cobj->priv);
319
 
        G_OBJECT_CLASS (parent_class)->finalize(object);
320
 
}
321
 
 
322
 
GtkWidget *
323
 
brasero_project_size_new ()
324
 
{
325
 
        GtkWidget *obj;
326
 
        
327
 
        obj = GTK_WIDGET (g_object_new (BRASERO_TYPE_PROJECT_SIZE, NULL));
328
 
 
329
 
        return obj;
330
 
}
331
 
 
332
 
static void
333
 
brasero_project_size_forall_children (GtkContainer *container,
334
 
                                      gboolean include_internals,
335
 
                                      GtkCallback callback,
336
 
                                      gpointer callback_data)
337
 
{
338
 
        if (include_internals) {
339
 
                BraseroProjectSize *self;
340
 
 
341
 
                self = BRASERO_PROJECT_SIZE (container);
342
 
 
343
 
                if (self->priv->frame)
344
 
                        (*callback) (self->priv->frame, callback_data);
345
 
                if (self->priv->button)
346
 
                        (*callback) (self->priv->button, callback_data);
347
 
                if (self->priv->arrow)
348
 
                        (*callback) (self->priv->arrow, callback_data);
349
 
        }
350
 
}
351
 
 
352
 
static void
353
 
brasero_project_size_realize (GtkWidget *widget)
354
 
{
355
 
        GdkWindowAttr attributes;
356
 
        gint attributes_mask;
357
 
        GdkColor color;
358
 
 
359
 
        attributes.window_type = GDK_WINDOW_CHILD;
360
 
        attributes.x = widget->allocation.x;
361
 
        attributes.y = widget->allocation.y;
362
 
        attributes.width = widget->allocation.width;
363
 
        attributes.height = widget->allocation.height;
364
 
        attributes.wclass = GDK_INPUT_OUTPUT;
365
 
        attributes.visual = gtk_widget_get_visual (widget);
366
 
        attributes.colormap = gtk_widget_get_colormap (widget);
367
 
        attributes.event_mask = gtk_widget_get_events (widget);
368
 
        attributes.event_mask |= GDK_EXPOSURE_MASK|
369
 
                                 GDK_BUTTON_RELEASE_MASK|
370
 
                                 GDK_SCROLL_MASK;
371
 
        attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_COLORMAP | GDK_WA_COLORMAP;
372
 
 
373
 
        widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
374
 
                                         &attributes,
375
 
                                         attributes_mask);
376
 
        gdk_window_set_user_data (widget->window, widget);
377
 
 
378
 
        gdk_color_parse ("DarkOliveGreen2", &color);
379
 
        gtk_widget_modify_bg (widget, GTK_STATE_INSENSITIVE, &color);
380
 
        gdk_color_parse ("LightGoldenrod2", &color);
381
 
        gtk_widget_modify_bg (widget, GTK_STATE_ACTIVE, &color);
382
 
        gdk_color_parse ("IndianRed2", &color);
383
 
        gtk_widget_modify_bg (widget, GTK_STATE_PRELIGHT, &color);
384
 
        gdk_color_parse ("White", &color);
385
 
        gtk_widget_modify_bg (widget, GTK_STATE_SELECTED, &color);
386
 
 
387
 
        widget->style = gtk_style_attach (widget->style, widget->window);
388
 
        gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
389
 
 
390
 
        GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
391
 
}
392
 
 
393
 
static void
394
 
brasero_project_size_unrealize (GtkWidget *widget)
395
 
{
396
 
        GTK_WIDGET_UNSET_FLAGS (widget, GTK_REALIZED);
397
 
 
398
 
        if (GTK_WIDGET_CLASS (parent_class)->unrealize)
399
 
                GTK_WIDGET_CLASS (parent_class)->unrealize (widget);
400
 
}
401
 
 
402
 
static void
403
 
brasero_project_size_get_ruler_min_width (BraseroProjectSize *self,
404
 
                                          gint *ruler_width,
405
 
                                          gint *ruler_height)
406
 
{
407
 
        PangoRectangle extents = { 0 };
408
 
        PangoLayout *layout;
409
 
 
410
 
        BraseroDriveSize *drive;
411
 
 
412
 
        gint max_width, max_height, total;
413
 
        gint interval_size;
414
 
        gdouble num, i;
415
 
 
416
 
        drive = self->priv->current;
417
 
        if (!drive) {
418
 
                *ruler_width = 0;
419
 
                *ruler_height = 0;
420
 
                return;
421
 
        }
422
 
 
423
 
        /* the number of interval needs to be reasonable, not over 8 not under 5 */
424
 
        if (self->priv->context != BRASERO_PROJECT_TYPE_DATA)
425
 
                interval_size = AUDIO_INTERVAL_CD;
426
 
        else if (self->priv->current->media & (BRASERO_MEDIUM_DVD|BRASERO_MEDIUM_DVD_DL))
427
 
                interval_size = DATA_INTERVAL_DVD;
428
 
        else
429
 
                interval_size = DATA_INTERVAL_CD;
430
 
 
431
 
        /* Here is the rule for the displaying of sizes:
432
 
         * if the disc is rewritable and multisession is on, then show the
433
 
         * remaining space
434
 
         * if the disc is rewritable and multisession is off, then show the
435
 
         * capacity
436
 
         * if the disc is just writable show the remaining free space whether
437
 
         * multisession is on or off. If multisession is not on then we'll only
438
 
         * use APPEND flag.
439
 
         * Basically the rule is display disc capacity only when the medium is 
440
 
         * rewritable and multisession is off. That also applies to the widget
441
 
         * to select recorders.  
442
 
         */
443
 
        if (drive->medium
444
 
        && (brasero_medium_get_status (drive->medium) & BRASERO_MEDIUM_REWRITABLE)
445
 
        && !self->priv->multi)
446
 
                total = drive->sectors > self->priv->sectors ? drive->sectors:self->priv->sectors;
447
 
        else
448
 
                total = drive->free_space > self->priv->sectors ? drive->free_space:self->priv->sectors;
449
 
 
450
 
        do {
451
 
                num = (gdouble) total / (gdouble) interval_size;
452
 
                if (num > MAX_INTERVAL)
453
 
                        interval_size *= 10;
454
 
                else if (num < MIN_INTERVAL)
455
 
                        interval_size /= 2;
456
 
        } while (num > MAX_INTERVAL || num < MIN_INTERVAL);
457
 
 
458
 
        max_width = 0;
459
 
        max_height = ARROW_HEIGHT;
460
 
 
461
 
        layout = gtk_widget_create_pango_layout (GTK_WIDGET (self), NULL);
462
 
        for (i = 1.0; i < num; i ++) {
463
 
                gchar *markup, *string;
464
 
 
465
 
                string = brasero_utils_get_sectors_string (i * interval_size,
466
 
                                                           (self->priv->context != BRASERO_PROJECT_TYPE_DATA),
467
 
                                                           TRUE,
468
 
                                                           TRUE);
469
 
 
470
 
                markup = g_strdup_printf ("<span size='x-small' foreground='grey10'>%s</span>", string);
471
 
                g_free (string);
472
 
 
473
 
                pango_layout_set_markup (layout, markup, -1);
474
 
                g_free (markup);
475
 
 
476
 
                pango_layout_get_pixel_extents (layout, NULL, &extents);
477
 
                max_width = MAX (max_width, extents.width);
478
 
                max_height = MAX (max_height, extents.height);
479
 
        }
480
 
        g_object_unref (layout);
481
 
 
482
 
        *ruler_width = (max_width + GTK_WIDGET (self)->style->xthickness * 2 + ARROW_WIDTH) * num;
483
 
        *ruler_height = max_height;
484
 
}
485
 
 
486
 
static gchar *
487
 
brasero_project_size_get_media_string (BraseroProjectSize *self)
488
 
{
489
 
        gint64 disc_size;
490
 
        gchar *text = NULL;
491
 
        BraseroDriveSize *drive;
492
 
        BraseroMedia status;
493
 
        gchar *drive_name = NULL;
494
 
        gchar *disc_sectors_str = NULL;
495
 
        gchar *selection_size_str = NULL;
496
 
 
497
 
        drive = self->priv->current;
498
 
        if (!drive)
499
 
                return NULL;
500
 
 
501
 
        status = brasero_medium_get_status (drive->medium);
502
 
        if (drive->medium
503
 
        && (status & BRASERO_MEDIUM_REWRITABLE)
504
 
        && !self->priv->multi)
505
 
                disc_size = drive->sectors;
506
 
        else
507
 
                disc_size = drive->free_space;
508
 
 
509
 
        /* we should round the disc sizes / length */
510
 
        if (drive->sectors == -2) {
511
 
                /* this is an empty drive */
512
 
                return NULL;
513
 
        }
514
 
 
515
 
        if (status == BRASERO_MEDIUM_BUSY) {
516
 
                gchar *name;
517
 
 
518
 
                /* this is a busy drive */
519
 
                name = brasero_volume_get_display_label (BRASERO_VOLUME (drive->medium), FALSE);
520
 
                disc_sectors_str = g_strdup_printf (_("<i>%s</i> is busy"), name);
521
 
                g_free (name);
522
 
 
523
 
                return disc_sectors_str;
524
 
        }
525
 
 
526
 
        if (drive->sectors == -1) {
527
 
                gchar *name;
528
 
 
529
 
                /* this is a drive probably not fully supported by brasero */
530
 
                name = brasero_volume_get_display_label (BRASERO_VOLUME (drive->medium), FALSE);
531
 
                disc_sectors_str = g_strdup_printf (_("<i>%s</i> not properly supported"), name);
532
 
                g_free (name);
533
 
 
534
 
                return disc_sectors_str;
535
 
        }
536
 
 
537
 
        if (status == BRASERO_MEDIUM_UNSUPPORTED) {
538
 
                gchar *name;
539
 
 
540
 
                /* this is an unsupported medium */
541
 
                name = brasero_volume_get_display_label (BRASERO_VOLUME (drive->medium), FALSE);
542
 
                disc_sectors_str = g_strdup_printf (_("The disc in <i>%s</i> is not supported"), name);
543
 
                g_free (name);
544
 
 
545
 
                return disc_sectors_str;
546
 
        }
547
 
 
548
 
        disc_sectors_str = brasero_utils_get_sectors_string (disc_size,
549
 
                                                             (self->priv->context != BRASERO_PROJECT_TYPE_DATA),
550
 
                                                             TRUE,
551
 
                                                             TRUE);
552
 
 
553
 
        if (drive->medium) {
554
 
                /* we ellipsize to max characters to avoid having
555
 
                 * a too long string with the drive full name. */
556
 
                drive_name = brasero_volume_get_display_label (BRASERO_VOLUME (drive->medium), TRUE);
557
 
/*              if (strlen (drive_name) > 19) {
558
 
                        gchar *tmp;
559
 
 
560
 
                        tmp = g_strdup_printf ("%.16s...", drive_name);
561
 
                        g_free (drive_name);
562
 
                        drive_name = tmp;
563
 
                }
564
 
*/      }
565
 
 
566
 
        selection_size_str = brasero_utils_get_sectors_string (self->priv->sectors,
567
 
                                                               (self->priv->context != BRASERO_PROJECT_TYPE_DATA),
568
 
                                                               TRUE,
569
 
                                                               FALSE);
570
 
 
571
 
        if (self->priv->sectors > disc_size) {
572
 
                if (drive_name)
573
 
                        text = g_strdup_printf (_("<b>Oversized</b> (%s / %s in <i>%s</i>)"),
574
 
                                                selection_size_str,
575
 
                                                disc_sectors_str,
576
 
                                                drive_name);
577
 
                else
578
 
                        text = g_strdup_printf (_("<b>Oversized</b> (%s / %s)"),
579
 
                                                selection_size_str,
580
 
                                                disc_sectors_str);
581
 
        }
582
 
        else if (self->priv->sectors == 0) {
583
 
                if (drive_name)
584
 
                        text = g_strdup_printf (_("<b>Empty</b> (%s free for <i>%s</i>)"),
585
 
                                                disc_sectors_str,
586
 
                                                drive_name);
587
 
                else
588
 
                        text = g_strdup_printf (_("<b>Empty</b> (%s free)"),
589
 
                                                disc_sectors_str);
590
 
        }
591
 
        else if (drive_name)
592
 
                /* To translators:
593
 
                 * - %s is the size of the project
594
 
                 * - %s is the size available (on disc)
595
 
                 * - %s is the name of the drive */
596
 
                text = g_strdup_printf (_("%s / %s (for <i>%s</i>)"),
597
 
                                        selection_size_str,
598
 
                                        disc_sectors_str,
599
 
                                        drive_name);
600
 
        else
601
 
                /* To translators:
602
 
                 * - %s is the size of the project
603
 
                 * - %s is the size available (on disc) */
604
 
                text = g_strdup_printf (_("%s / %s"),
605
 
                                        selection_size_str,
606
 
                                        disc_sectors_str);
607
 
 
608
 
        g_free (selection_size_str);
609
 
        g_free (disc_sectors_str);
610
 
        g_free (drive_name);
611
 
 
612
 
        return text;
613
 
}
614
 
 
615
 
static void
616
 
brasero_project_size_size_request (GtkWidget *widget,
617
 
                                   GtkRequisition *requisition)
618
 
{
619
 
        gint width, height, ruler_width, ruler_height;
620
 
        PangoRectangle extents = { 0 };
621
 
        BraseroProjectSize *self;
622
 
        GtkRequisition req;
623
 
        gchar *text;
624
 
 
625
 
        self = BRASERO_PROJECT_SIZE (widget);
626
 
 
627
 
        /* Set markup every time a size change this function is called */
628
 
        text = brasero_project_size_get_media_string (self);
629
 
        if (text) {
630
 
                pango_layout_set_markup (self->priv->text_layout, text, -1);
631
 
                g_free (text);
632
 
        }
633
 
 
634
 
        brasero_project_size_get_ruler_min_width (self, &ruler_width, &ruler_height);
635
 
        gtk_widget_size_request (self->priv->button, &req);
636
 
 
637
 
        width = self->priv->frame->style->xthickness * 2 + req.width * 2;
638
 
 
639
 
        height = extents.height + self->priv->frame->style->ythickness * 2;
640
 
        height = MAX (height, req.height);
641
 
        height += ruler_height;
642
 
 
643
 
        requisition->height = height;
644
 
        requisition->width = width;
645
 
 
646
 
        self->priv->ruler_height = ruler_height;
647
 
}
648
 
 
649
 
static void
650
 
brasero_project_size_size_allocate (GtkWidget *widget,
651
 
                                    GtkAllocation *allocation)
652
 
{
653
 
        BraseroProjectSize *self;
654
 
        GtkAllocation alloc;
655
 
        GtkRequisition req;
656
 
 
657
 
        gboolean is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
658
 
 
659
 
        widget->allocation = *allocation;
660
 
        if (GTK_WIDGET_REALIZED (widget) && !GTK_WIDGET_NO_WINDOW (widget)) {
661
 
                gdk_window_move_resize (widget->window,
662
 
                                        allocation->x,
663
 
                                        allocation->y,
664
 
                                        allocation->width,
665
 
                                        allocation->height);
666
 
        }
667
 
 
668
 
        /* allocate the size for the button */
669
 
        self = BRASERO_PROJECT_SIZE (widget);
670
 
        gtk_widget_size_request (self->priv->button, &req);
671
 
 
672
 
        /* NOTE: since we've got our own window, we don't need to take into
673
 
         * account alloc.x and alloc.y */
674
 
        if (is_rtl)
675
 
                alloc.x = allocation->width - req.width - 1;
676
 
        else
677
 
                alloc.x = - 1;
678
 
 
679
 
        alloc.y = - 1;
680
 
        alloc.width = MAX (1, req.width + self->priv->frame->style->xthickness * 2 - 2);
681
 
        alloc.height = MAX (req.height - 2, allocation->height - self->priv->ruler_height);
682
 
        gtk_widget_size_allocate (self->priv->button, &alloc);
683
 
 
684
 
        /* allocate the size for the arrow we want to draw on the button */
685
 
        if (is_rtl)
686
 
                alloc.x += alloc.width / 2;
687
 
        else
688
 
                alloc.x = alloc.width / 2;
689
 
 
690
 
        alloc.y = self->priv->button->style->ythickness;
691
 
        alloc.width /= 2.5;
692
 
        alloc.height /= 2.5;
693
 
        gtk_widget_size_allocate (self->priv->arrow, &alloc);
694
 
}
695
 
 
696
 
static gboolean
697
 
brasero_project_size_expose (GtkWidget *widget, GdkEventExpose *event)
698
 
{
699
 
        PangoRectangle extents = { 0 };
700
 
        PangoLayout *layout;
701
 
 
702
 
        gint interval_size, interval_width;
703
 
        gint x, y, width, total;
704
 
        gint button_width;
705
 
        gdouble num, i;
706
 
        guint next_possible = 0;
707
 
 
708
 
        BraseroProjectSize *self;
709
 
        gdouble fraction = 0.0;
710
 
        gint text_height = 0;
711
 
        BraseroDriveSize *drive;
712
 
 
713
 
        gint bar_width, bar_height;
714
 
        gchar *markup;
715
 
 
716
 
        GtkAllocation alloc;
717
 
 
718
 
        gint64 disc_size;
719
 
 
720
 
        gboolean is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
721
 
 
722
 
        if (!GTK_WIDGET_DRAWABLE (widget))
723
 
                return TRUE;
724
 
 
725
 
        self = BRASERO_PROJECT_SIZE (widget);
726
 
 
727
 
        /* paint the button and arrow */
728
 
        gtk_container_propagate_expose (GTK_CONTAINER (widget),
729
 
                                        self->priv->button,
730
 
                                        event);
731
 
        gtk_container_propagate_expose (GTK_CONTAINER (widget),
732
 
                                        self->priv->arrow,
733
 
                                        event);
734
 
 
735
 
        button_width = self->priv->button->allocation.width;
736
 
 
737
 
        drive = self->priv->current;
738
 
        if (!drive)
739
 
                return FALSE;
740
 
 
741
 
        /* The number of interval needs to be reasonable, not over 8 not under 5
742
 
         * They should also depend on the available space for the bar. */
743
 
        
744
 
        if (self->priv->context != BRASERO_PROJECT_TYPE_DATA)
745
 
                interval_size = AUDIO_INTERVAL_CD;
746
 
        else if (self->priv->current->media & (BRASERO_MEDIUM_DVD|BRASERO_MEDIUM_DVD_DL))
747
 
                interval_size = DATA_INTERVAL_DVD;
748
 
        else
749
 
                interval_size = DATA_INTERVAL_CD;
750
 
 
751
 
        total = self->priv->current->sectors > self->priv->sectors ? self->priv->current->sectors:self->priv->sectors;
752
 
        do {
753
 
                num = (gdouble) total / (gdouble) interval_size;
754
 
                if (num > MAX_INTERVAL)
755
 
                        interval_size *= 10;
756
 
                else if (num < MIN_INTERVAL)
757
 
                        interval_size /= 2;
758
 
        } while (num > MAX_INTERVAL || num < MIN_INTERVAL);
759
 
 
760
 
        /* calculate the size of the interval in pixels */
761
 
        bar_width = widget->allocation.width - button_width - self->priv->frame->style->xthickness * 2;
762
 
        interval_width = bar_width / num;
763
 
 
764
 
        /* draw the ruler */
765
 
        layout = gtk_widget_create_pango_layout (widget, NULL);
766
 
 
767
 
        if (is_rtl)
768
 
                next_possible = widget->allocation.width - button_width - self->priv->frame->style->xthickness;
769
 
        else
770
 
                next_possible = button_width + self->priv->frame->style->xthickness;
771
 
 
772
 
        for (i = 1.; i < num; i ++) {
773
 
                gchar *string;
774
 
                guint text_x;
775
 
 
776
 
                string = brasero_utils_get_sectors_string (i * interval_size,
777
 
                                                           (self->priv->context != BRASERO_PROJECT_TYPE_DATA),
778
 
                                                           TRUE,
779
 
                                                           TRUE);
780
 
 
781
 
                markup = g_strdup_printf ("<span size='x-small' foreground='grey10'>%s</span>", string);
782
 
                g_free (string);
783
 
                pango_layout_set_markup (layout, markup, -1);
784
 
                g_free (markup);
785
 
 
786
 
                pango_layout_get_pixel_extents (layout, NULL, &extents);
787
 
 
788
 
                text_height = MAX (text_height, extents.height);
789
 
                y = widget->allocation.height - extents.height;
790
 
 
791
 
                if (is_rtl)
792
 
                        x = widget->allocation.width - button_width - self->priv->frame->style->xthickness -
793
 
                            i * interval_width;
794
 
                else
795
 
                        x = button_width + self->priv->frame->style->xthickness + i * interval_width;
796
 
 
797
 
                if (!is_rtl && x <= next_possible)
798
 
                        continue;
799
 
 
800
 
                if (is_rtl && x >= next_possible)
801
 
                        continue;
802
 
 
803
 
                if (is_rtl)
804
 
                        text_x = x + widget->style->xthickness + ARROW_WIDTH / 2 + 2;
805
 
                else
806
 
                        text_x = x - widget->style->xthickness - ARROW_WIDTH / 2 - extents.width - 2;
807
 
 
808
 
                if (!is_rtl && text_x <= next_possible)
809
 
                        continue;
810
 
 
811
 
                if (is_rtl && text_x + extents.width >= next_possible)
812
 
                        continue;
813
 
 
814
 
                gtk_paint_layout (widget->style,
815
 
                                  widget->window,
816
 
                                  GTK_STATE_NORMAL,
817
 
                                  TRUE,
818
 
                                  &event->area,
819
 
                                  widget,
820
 
                                  NULL,
821
 
                                  text_x,
822
 
                                  y,
823
 
                                  layout);
824
 
 
825
 
                gtk_paint_arrow (widget->style,
826
 
                                 widget->window,
827
 
                                 GTK_STATE_NORMAL,
828
 
                                 GTK_SHADOW_ETCHED_IN,
829
 
                                 &event->area,
830
 
                                 widget,
831
 
                                 NULL,
832
 
                                 GTK_ARROW_UP,
833
 
                                 FALSE,
834
 
                                 x - widget->style->xthickness - ARROW_WIDTH/ 2,
835
 
                                 widget->allocation.height - text_height,
836
 
                                 ARROW_WIDTH,
837
 
                                 ARROW_HEIGHT);
838
 
 
839
 
                /* calculate the next possible location (2 pixels spacing) */
840
 
                if (is_rtl)
841
 
                        next_possible = x - ARROW_WIDTH / 2;
842
 
                else
843
 
                        next_possible = x + 2 + ARROW_WIDTH / 2;
844
 
        }
845
 
        g_object_unref (layout);
846
 
 
847
 
        bar_height = widget->allocation.height - text_height - 2;
848
 
 
849
 
        if (drive->medium
850
 
        && (brasero_medium_get_status (drive->medium) & BRASERO_MEDIUM_REWRITABLE)
851
 
        && !self->priv->multi)  
852
 
                disc_size = drive->sectors;
853
 
        else
854
 
                disc_size = drive->free_space;
855
 
 
856
 
        /* green part */
857
 
        fraction = ((gdouble) self->priv->sectors / (gdouble) disc_size);
858
 
        if (fraction > 1.0)
859
 
                width = bar_width / fraction * 1.0;
860
 
        else
861
 
                width = fraction * bar_width;
862
 
 
863
 
        if (is_rtl)
864
 
                x = self->priv->frame->style->xthickness + bar_width - width;
865
 
        else
866
 
                x = self->priv->frame->style->xthickness + button_width;
867
 
 
868
 
        gtk_paint_flat_box (widget->style,
869
 
                            widget->window,
870
 
                            GTK_STATE_INSENSITIVE,
871
 
                            GTK_SHADOW_NONE,
872
 
                            &event->area,
873
 
                            NULL,
874
 
                            NULL,
875
 
                            x,
876
 
                            self->priv->frame->style->ythickness,
877
 
                            width,
878
 
                            bar_height - self->priv->frame->style->ythickness);
879
 
 
880
 
        if (fraction > 1.0) {
881
 
                gint width2;
882
 
 
883
 
                if (fraction > 1.03)
884
 
                        width2 = bar_width / fraction * 0.03;
885
 
                else
886
 
                        width2 = bar_width / fraction * (fraction - 1.0);
887
 
 
888
 
                if (is_rtl)
889
 
                        x = widget->allocation.width - width - width2 - self->priv->frame->style->xthickness - button_width;
890
 
                else
891
 
                        x = width + self->priv->frame->style->xthickness + button_width;
892
 
 
893
 
                gtk_paint_flat_box (widget->style,
894
 
                                    widget->window,
895
 
                                    GTK_STATE_ACTIVE,
896
 
                                    GTK_SHADOW_NONE,
897
 
                                    &event->area,
898
 
                                    NULL,
899
 
                                    NULL,
900
 
                                    x,
901
 
                                    self->priv->frame->style->ythickness,
902
 
                                    width2,
903
 
                                    bar_height - self->priv->frame->style->ythickness * 2);
904
 
 
905
 
                if (fraction > 1.03) {
906
 
                        if (is_rtl)
907
 
                                x = widget->allocation.width - bar_width - self->priv->frame->style->xthickness - button_width;
908
 
                        else
909
 
                                x = width + width2 + self->priv->frame->style->xthickness + button_width;
910
 
 
911
 
                        gtk_paint_flat_box (widget->style,
912
 
                                            widget->window,
913
 
                                            GTK_STATE_PRELIGHT,
914
 
                                            GTK_SHADOW_NONE,
915
 
                                            &event->area,
916
 
                                            NULL,
917
 
                                            NULL,
918
 
                                            x,
919
 
                                            self->priv->frame->style->ythickness,
920
 
                                            bar_width - width - width2,
921
 
                                            bar_height - self->priv->frame->style->ythickness);
922
 
                }
923
 
        }
924
 
        else {
925
 
                /* This is the white part */
926
 
                if (is_rtl)
927
 
                        x = self->priv->frame->style->xthickness;
928
 
                else
929
 
                        x = width ? width + button_width:self->priv->frame->style->xthickness + button_width;
930
 
 
931
 
                gtk_paint_flat_box (widget->style,
932
 
                                    widget->window,
933
 
                                    GTK_STATE_SELECTED,
934
 
                                    GTK_SHADOW_NONE,
935
 
                                    &event->area,
936
 
                                    NULL,
937
 
                                    NULL,
938
 
                                    x,
939
 
                                    self->priv->frame->style->ythickness,
940
 
                                    bar_width - width + self->priv->frame->style->xthickness,
941
 
                                    bar_height - self->priv->frame->style->ythickness);
942
 
        }
943
 
 
944
 
        /* Frame around bar */
945
 
        if (is_rtl)
946
 
                alloc.x = 0;
947
 
        else
948
 
                alloc.x = button_width;
949
 
 
950
 
        alloc.y = 0;
951
 
        alloc.width = bar_width + self->priv->frame->style->xthickness * 2;
952
 
        alloc.height = bar_height;
953
 
        gtk_widget_size_allocate (self->priv->frame, &alloc);
954
 
        gtk_container_propagate_expose (GTK_CONTAINER (widget),
955
 
                                        self->priv->frame,
956
 
                                        event);
957
 
 
958
 
        /* set the text */
959
 
        pango_layout_set_width (self->priv->text_layout, -1);
960
 
        pango_layout_get_pixel_extents (self->priv->text_layout, NULL, &extents);
961
 
        if (extents.width > bar_width) {
962
 
                pango_layout_set_ellipsize (self->priv->text_layout, PANGO_ELLIPSIZE_END);
963
 
                pango_layout_set_width (self->priv->text_layout, (bar_width - BRASERO_PROJECT_SIZE_SPACE * 2) * PANGO_SCALE);
964
 
        }
965
 
        else
966
 
                pango_layout_set_ellipsize (self->priv->text_layout, PANGO_ELLIPSIZE_NONE);
967
 
 
968
 
        pango_layout_get_pixel_extents (self->priv->text_layout, NULL, &extents);
969
 
        x = (bar_width - extents.width) / 2;
970
 
        y = (widget->allocation.height - extents.height - text_height) / 2;
971
 
 
972
 
        if (!is_rtl)
973
 
                x += button_width;
974
 
 
975
 
        gtk_paint_layout (widget->style,
976
 
                          widget->window,
977
 
                          GTK_STATE_NORMAL,
978
 
                          TRUE,
979
 
                          &event->area,
980
 
                          widget,
981
 
                          NULL,
982
 
                          x,
983
 
                          y,
984
 
                          self->priv->text_layout);
985
 
 
986
 
        return FALSE;
987
 
}
988
 
 
989
 
static void
990
 
brasero_project_size_disc_changed (BraseroProjectSize *self)
991
 
{
992
 
        gtk_widget_queue_resize (GTK_WIDGET (self));
993
 
        g_signal_emit (self,
994
 
                       brasero_project_size_signals [DISC_CHANGED_SIGNAL],
995
 
                       0);
996
 
}
997
 
 
998
 
static void
999
 
brasero_project_size_disc_changed_cb (GtkMenuItem *item,
1000
 
                                      BraseroProjectSize *self)
1001
 
{
1002
 
        BraseroDriveSize *drive;
1003
 
 
1004
 
        drive = g_object_get_data (G_OBJECT (item), DRIVE_STRUCT);
1005
 
        self->priv->current = drive;
1006
 
        brasero_project_size_disc_changed (self);
1007
 
}
1008
 
 
1009
 
static void
1010
 
brasero_project_size_menu_position_cb (GtkMenu *menu,
1011
 
                                       gint *x,
1012
 
                                       gint *y,
1013
 
                                       gboolean *push_in,
1014
 
                                       gpointer user_data)
1015
 
{
1016
 
        gint sx, sy;
1017
 
        gint width, height;
1018
 
        GtkRequisition req;
1019
 
        GdkScreen *screen;
1020
 
        gint monitor_num;
1021
 
        GdkRectangle monitor;
1022
 
        GtkWidget *self = user_data;
1023
 
 
1024
 
        /* All this comes from GTK+ gtkcombobox.c */
1025
 
        gdk_window_get_origin (self->window, &sx, &sy);
1026
 
        gtk_widget_size_request (GTK_WIDGET (menu), &req);
1027
 
 
1028
 
        gdk_drawable_get_size (GDK_DRAWABLE (self->window), &width, &height);
1029
 
        gtk_widget_set_size_request (GTK_WIDGET (menu), width, -1);
1030
 
 
1031
 
        *x = sx;
1032
 
        *y = sy;
1033
 
 
1034
 
        screen = gtk_widget_get_screen (self);
1035
 
        monitor_num = gdk_screen_get_monitor_at_window (screen, self->window);
1036
 
        gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
1037
 
  
1038
 
        if (*x < monitor.x)
1039
 
                *x = monitor.x;
1040
 
        else if (*x + req.width > monitor.x + monitor.width)
1041
 
                *x = monitor.x + monitor.width - req.width;
1042
 
  
1043
 
        *y -= req.height;
1044
 
        *push_in = FALSE;
1045
 
}
1046
 
 
1047
 
static gboolean
1048
 
brasero_project_size_is_valid_drive (BraseroProjectSize *self,
1049
 
                                     BraseroDriveSize *current)
1050
 
{
1051
 
        BraseroBurnCaps *caps;
1052
 
        gboolean result = TRUE;
1053
 
        BraseroMedia media_status;
1054
 
 
1055
 
        if (!current)
1056
 
                return FALSE;
1057
 
 
1058
 
        caps = brasero_burn_caps_get_default ();
1059
 
        media_status = brasero_burn_caps_media_capabilities (caps, current->media);
1060
 
        
1061
 
        if (!BRASERO_MEDIUM_VALID (current->media))
1062
 
                result = FALSE;
1063
 
        /* Library must support it */
1064
 
        else if (!(media_status & (BRASERO_MEDIUM_WRITABLE|BRASERO_MEDIUM_REWRITABLE)))
1065
 
                result = FALSE;
1066
 
        /* No media with data for audio/video context, that can't be erased */
1067
 
        else if (self->priv->context != BRASERO_PROJECT_TYPE_DATA
1068
 
             && (current->media & (BRASERO_MEDIUM_HAS_AUDIO|BRASERO_MEDIUM_HAS_DATA))
1069
 
             && !(media_status & BRASERO_MEDIUM_REWRITABLE))
1070
 
                result = FALSE;
1071
 
        /* No DVDs in an audio context */
1072
 
        else if (self->priv->context == BRASERO_PROJECT_TYPE_AUDIO
1073
 
             && (current->media & (BRASERO_MEDIUM_DVD|BRASERO_MEDIUM_DVD_DL|BRASERO_MEDIUM_APPENDABLE)))
1074
 
                result = FALSE;
1075
 
 
1076
 
        g_object_unref (caps);
1077
 
        return result;
1078
 
}
1079
 
 
1080
 
static GtkWidget *
1081
 
brasero_project_size_build_menu (BraseroProjectSize *self)
1082
 
{
1083
 
        gboolean separator;
1084
 
        gint64 disc_size;
1085
 
        GtkWidget *menu;
1086
 
        GtkWidget *item;
1087
 
        GList *iter;
1088
 
 
1089
 
        menu = gtk_menu_new ();
1090
 
 
1091
 
        separator = TRUE;
1092
 
        for (iter = self->priv->drives; iter; iter = iter->next) {
1093
 
                BraseroDriveSize *drive;
1094
 
                GtkWidget *image;
1095
 
                gchar *size_str;
1096
 
                gchar *label;
1097
 
 
1098
 
                drive = iter->data;
1099
 
 
1100
 
                if (!brasero_project_size_is_valid_drive (self, drive))
1101
 
                        continue;
1102
 
 
1103
 
                if (!drive->medium && !separator) {
1104
 
                        item = gtk_separator_menu_item_new ();
1105
 
                        gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1106
 
                        separator = TRUE;
1107
 
                }
1108
 
                else if (drive->medium)
1109
 
                        separator = FALSE;
1110
 
 
1111
 
                if (drive->medium
1112
 
                && (brasero_medium_get_status (drive->medium) & BRASERO_MEDIUM_REWRITABLE)
1113
 
                && !self->priv->multi)
1114
 
                        disc_size = drive->sectors;
1115
 
                else
1116
 
                        disc_size = drive->free_space;
1117
 
 
1118
 
                if (self->priv->context != BRASERO_PROJECT_TYPE_DATA)
1119
 
                        size_str = brasero_utils_get_time_string_from_size (disc_size * AUDIO_SECTOR_SIZE, TRUE, TRUE);
1120
 
                else
1121
 
                        size_str = brasero_utils_get_size_string (disc_size * DATA_SECTOR_SIZE, TRUE, TRUE); 
1122
 
 
1123
 
                if (drive->medium) {
1124
 
                        gchar *name;
1125
 
 
1126
 
                        name = brasero_volume_get_display_label (BRASERO_VOLUME (drive->medium), FALSE);
1127
 
                        label = g_strdup_printf ("%s %s", size_str, name);
1128
 
                        g_free (name);
1129
 
                }
1130
 
                else if (drive->media & BRASERO_MEDIUM_DVD_DL)
1131
 
                        label = g_strdup_printf (_("%s (DVD-R Dual Layer)"),
1132
 
                                                 size_str);
1133
 
                else if (drive->media & BRASERO_MEDIUM_DVD)
1134
 
                        label = g_strdup_printf (_("%s (DVD-R)"),
1135
 
                                                 size_str);
1136
 
                else
1137
 
                        label = g_strdup_printf (_("%s (CD-R)"),
1138
 
                                                 size_str);
1139
 
 
1140
 
                g_free (size_str);
1141
 
 
1142
 
                if (self->priv->current == drive) {
1143
 
                        gchar *tmp;
1144
 
                        GtkWidget *widget;
1145
 
 
1146
 
                        /* This is the selected drive mark it as such */
1147
 
                        tmp = g_strdup_printf ("<b><i>%s</i></b>", label);
1148
 
                        g_free (label);
1149
 
                        label = tmp;
1150
 
 
1151
 
                        widget = gtk_label_new (label);
1152
 
                        gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
1153
 
                        gtk_label_set_use_markup (GTK_LABEL (widget), TRUE);
1154
 
                        gtk_label_set_ellipsize (GTK_LABEL (widget), PANGO_ELLIPSIZE_END);
1155
 
                        g_free (label);
1156
 
 
1157
 
                        item = gtk_image_menu_item_new ();
1158
 
                        gtk_item_select (GTK_ITEM (item));
1159
 
                        gtk_container_add (GTK_CONTAINER (item), widget);
1160
 
                }
1161
 
                else {
1162
 
                        item = gtk_image_menu_item_new_with_label (label);
1163
 
                        g_free (label);
1164
 
                }
1165
 
 
1166
 
                if (!drive->medium)
1167
 
                        image = gtk_image_new_from_icon_name ("drive-optical", GTK_ICON_SIZE_MENU);
1168
 
                else if (drive->media & (BRASERO_MEDIUM_DVD|BRASERO_MEDIUM_DVD_DL))
1169
 
                        image = gtk_image_new_from_icon_name ("gnome-dev-disc-dvdr", GTK_ICON_SIZE_MENU);
1170
 
                else
1171
 
                        image = gtk_image_new_from_icon_name ("gnome-dev-disc-cdr", GTK_ICON_SIZE_MENU);
1172
 
 
1173
 
                gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
1174
 
 
1175
 
                g_signal_connect (item,
1176
 
                                  "activate",
1177
 
                                  G_CALLBACK (brasero_project_size_disc_changed_cb),
1178
 
                                  self);
1179
 
 
1180
 
                gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1181
 
                g_object_set_data (G_OBJECT (item), DRIVE_STRUCT, drive);
1182
 
        }
1183
 
 
1184
 
        gtk_widget_show_all (menu);
1185
 
 
1186
 
        return menu;
1187
 
}
1188
 
 
1189
 
static void
1190
 
brasero_project_size_menu_finished_cb (GtkMenuShell *shell,
1191
 
                                       BraseroProjectSize *self)
1192
 
{
1193
 
        gtk_widget_destroy (self->priv->menu);
1194
 
        self->priv->menu = NULL;
1195
 
        gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (self->priv->button), FALSE);
1196
 
        gtk_arrow_set (GTK_ARROW (self->priv->arrow), GTK_ARROW_UP, GTK_SHADOW_NONE);
1197
 
}
1198
 
 
1199
 
static void
1200
 
brasero_project_size_show_menu_real (BraseroProjectSize *self,
1201
 
                                     GdkEventButton *event)
1202
 
{
1203
 
        GtkWidget *menu;
1204
 
 
1205
 
        menu = brasero_project_size_build_menu (self);
1206
 
        if (!menu)
1207
 
                return;
1208
 
 
1209
 
        if (self->priv->menu)
1210
 
                gtk_widget_destroy (self->priv->menu);
1211
 
 
1212
 
        self->priv->menu = menu;
1213
 
        gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (self->priv->button), TRUE);
1214
 
 
1215
 
        gtk_arrow_set (GTK_ARROW (self->priv->arrow), GTK_ARROW_DOWN, GTK_SHADOW_NONE);
1216
 
 
1217
 
        gtk_menu_popup (GTK_MENU (menu),
1218
 
                        NULL,
1219
 
                        NULL,
1220
 
                        brasero_project_size_menu_position_cb,
1221
 
                        GTK_WIDGET (self),
1222
 
                        event ? event->button:1,
1223
 
                        event ? event->time:gtk_get_current_event_time ());
1224
 
 
1225
 
        g_signal_connect (menu,
1226
 
                          "selection-done",
1227
 
                          G_CALLBACK (brasero_project_size_menu_finished_cb),
1228
 
                          self);
1229
 
}
1230
 
 
1231
 
static void
1232
 
brasero_project_size_button_toggled_cb (GtkToggleButton *button,
1233
 
                                        BraseroProjectSize *self)
1234
 
{
1235
 
        if (gtk_toggle_button_get_active (button)) {
1236
 
                if (self->priv->menu)
1237
 
                        return;
1238
 
        }
1239
 
        else if (!self->priv->menu)
1240
 
                return;
1241
 
 
1242
 
        brasero_project_size_show_menu_real (self, NULL);
1243
 
}
1244
 
 
1245
 
static gboolean
1246
 
brasero_project_size_scroll_event (GtkWidget *widget,
1247
 
                                   GdkEventScroll *event)
1248
 
{
1249
 
        BraseroProjectSize *self;
1250
 
 
1251
 
        self = BRASERO_PROJECT_SIZE (widget);
1252
 
 
1253
 
        if (event->direction == GDK_SCROLL_DOWN) {
1254
 
                GList *node, *iter;
1255
 
 
1256
 
                node = g_list_find (self->priv->drives, self->priv->current);
1257
 
                iter = g_list_next (node);
1258
 
                if (!iter)
1259
 
                        return TRUE;
1260
 
 
1261
 
                while (iter != node) {
1262
 
                        BraseroDriveSize *drive;
1263
 
 
1264
 
                        drive = iter->data;
1265
 
 
1266
 
                        /* must be a valid media */
1267
 
                        if (!brasero_project_size_is_valid_drive (self, drive))
1268
 
                                iter = g_list_next (iter);
1269
 
                        else {
1270
 
                                self->priv->current = drive;
1271
 
                                break;
1272
 
                        }
1273
 
 
1274
 
                        if (!iter)
1275
 
                                return TRUE;
1276
 
                }
1277
 
                brasero_project_size_disc_changed (self);
1278
 
        }
1279
 
        else if (event->direction == GDK_SCROLL_UP) {
1280
 
                GList *node, *iter;
1281
 
 
1282
 
                node = g_list_find (self->priv->drives, self->priv->current);
1283
 
                iter = g_list_previous (node);
1284
 
                if (!iter)
1285
 
                        return TRUE;
1286
 
 
1287
 
                while (iter != node) {
1288
 
                        BraseroDriveSize *drive;
1289
 
 
1290
 
                        drive = iter->data;
1291
 
 
1292
 
                        /* must be a valid media */
1293
 
                        if (!brasero_project_size_is_valid_drive (self, drive))
1294
 
                                iter = g_list_previous (iter);
1295
 
                        else {
1296
 
                                self->priv->current = drive;
1297
 
                                break;
1298
 
                        }
1299
 
 
1300
 
                        if (!iter)
1301
 
                                return TRUE;
1302
 
                }
1303
 
                brasero_project_size_disc_changed (self);
1304
 
        }
1305
 
 
1306
 
        return FALSE;
1307
 
}
1308
 
 
1309
 
static gboolean
1310
 
brasero_project_size_update_sectors (BraseroProjectSize *self)
1311
 
{
1312
 
        gtk_widget_queue_resize (GTK_WIDGET (self));
1313
 
        self->priv->refresh_id = 0;
1314
 
        return FALSE;
1315
 
}
1316
 
 
1317
 
void
1318
 
brasero_project_size_set_sectors (BraseroProjectSize *self,
1319
 
                                  gint64 sectors)
1320
 
{
1321
 
        /* we don't update the size right now but in half a second.
1322
 
         * when exploring directories size can changed repeatedly
1323
 
         * and we don't want to lose too much time updating.
1324
 
         * if a size is already set, we know that we're waiting for
1325
 
         * a size update, so, just replace the old size. otherwise
1326
 
         * we add a g_timeout_add */
1327
 
 
1328
 
        /* we add 175 sectors for a single session track (that's the needed
1329
 
         * overhead.
1330
 
         * for multisessions (we'll need ncb 2.15), the overhead is much
1331
 
         * larger since we'll have to add 2 sec gap between tracks (300 sectors)
1332
 
         * - first track : 6750 sectors (1.5 min) and leadout 4500 sectors (1 mn)
1333
 
         *   and 2 sec gap (150 sectors)
1334
 
         * - next tracks : leadin 6750 sectors, leadout 2250 sectors (0.5 mn)
1335
 
         * Now, for the moment we don't know exactly how much we need ...
1336
 
         * so we add the maximum number of sectors and if the user wants he can
1337
 
         * still use overburn
1338
 
         */
1339
 
        /* FIXME: for now just add 500 sectors = 1Mib */
1340
 
        if (sectors)
1341
 
                self->priv->sectors = sectors + 500;
1342
 
        else
1343
 
                self->priv->sectors = 0;
1344
 
        
1345
 
        if (!self->priv->refresh_id)
1346
 
                self->priv->refresh_id = g_timeout_add (500,
1347
 
                                                       (GSourceFunc) brasero_project_size_update_sectors,
1348
 
                                                       self);
1349
 
}
1350
 
 
1351
 
static void
1352
 
brasero_project_size_find_proper_drive (BraseroProjectSize *self)
1353
 
{
1354
 
        GList *iter;
1355
 
        BraseroDriveSize *candidate = NULL;
1356
 
 
1357
 
        if (self->priv->current) {
1358
 
                BraseroDriveSize *current;
1359
 
 
1360
 
                /* we check the current drive to see if it is suitable */
1361
 
                current = self->priv->current;
1362
 
 
1363
 
                if (!brasero_project_size_is_valid_drive (self, current))
1364
 
                        current = NULL;
1365
 
                else if (current->sectors >= self->priv->sectors && current->medium) {
1366
 
                        /* The current drive is still a perfect fit keep it */
1367
 
                        return;
1368
 
                }
1369
 
                else if (self->priv->multi) {
1370
 
                        /* The rule:
1371
 
                         * - we don't change the current drive if multisession
1372
 
                         * is on to avoid disrupting the user current selection
1373
 
                         * (except of course if the media used for multisession
1374
 
                         * is the one removed)
1375
 
                         * - we don't change the current drive if it is real
1376
 
                         * unless another real drive comes up with a size
1377
 
                         * fitting the size of the selection. */
1378
 
                        return;
1379
 
                }
1380
 
                else /* see if there is better */
1381
 
                        candidate = self->priv->current;
1382
 
        }
1383
 
 
1384
 
        /* Try to find the first best candidate */
1385
 
        for (iter = self->priv->drives; iter; iter = iter->next) {
1386
 
                BraseroDriveSize *drive;
1387
 
 
1388
 
                drive = iter->data;
1389
 
 
1390
 
                if (!brasero_project_size_is_valid_drive (self, drive))
1391
 
                        continue;
1392
 
 
1393
 
                /* we must have at least one candidate */
1394
 
                if (!candidate)
1395
 
                        candidate = drive;
1396
 
 
1397
 
                /* Try to find a drive large enough */
1398
 
                if (drive->sectors < self->priv->sectors)
1399
 
                        continue;
1400
 
 
1401
 
                if (candidate->sectors < self->priv->sectors) {
1402
 
                        if (!candidate->medium) {
1403
 
                                candidate = drive;
1404
 
 
1405
 
                                if (drive->medium)
1406
 
                                        break;
1407
 
                        }
1408
 
                        else if (drive->medium) {
1409
 
                                candidate = drive;
1410
 
                                break;
1411
 
                        }
1412
 
                }
1413
 
                else if (drive->medium) {
1414
 
                        candidate = drive;
1415
 
                        break;
1416
 
                }
1417
 
        }
1418
 
 
1419
 
        self->priv->current = candidate;
1420
 
}
1421
 
 
1422
 
void
1423
 
brasero_project_size_set_context (BraseroProjectSize *self,
1424
 
                                  BraseroProjectType type)
1425
 
{
1426
 
        BraseroDriveSize *current;
1427
 
 
1428
 
        self->priv->sectors = 0;
1429
 
        self->priv->context = type;
1430
 
 
1431
 
        if (!self->priv->is_loaded) {
1432
 
                brasero_project_size_add_real_medias (self);
1433
 
                self->priv->is_loaded = 1;
1434
 
        }
1435
 
 
1436
 
        /* try to find a better drive in the following cases:
1437
 
         * - there is not real current drive selected
1438
 
         * - the previous project was a data project and it contained an
1439
 
         *   appendable disc or the disc is a DVD
1440
 
         * No need to find a better one for DVD+RW */
1441
 
        current = self->priv->current;
1442
 
 
1443
 
        if (!current)
1444
 
                brasero_project_size_find_proper_drive (self);
1445
 
        else if (!current->medium)
1446
 
                brasero_project_size_find_proper_drive (self);
1447
 
        else if (!brasero_project_size_is_valid_drive (self, current))
1448
 
                brasero_project_size_find_proper_drive (self);
1449
 
 
1450
 
        brasero_project_size_disc_changed (self);
1451
 
}
1452
 
 
1453
 
void
1454
 
brasero_project_size_set_multisession (BraseroProjectSize *self,
1455
 
                                       gboolean multi)
1456
 
{
1457
 
        self->priv->multi = multi;
1458
 
        brasero_project_size_disc_changed (self);
1459
 
}
1460
 
 
1461
 
gboolean
1462
 
brasero_project_size_check_status (BraseroProjectSize *self,
1463
 
                                   gboolean *overburn)
1464
 
{
1465
 
        gint64 max_sectors;
1466
 
        gint64 disc_size;
1467
 
 
1468
 
        if (!self->priv->current)
1469
 
                return FALSE;
1470
 
 
1471
 
        if (self->priv->current->medium
1472
 
        && (brasero_medium_get_status (self->priv->current->medium) & BRASERO_MEDIUM_REWRITABLE)
1473
 
        && !self->priv->multi)
1474
 
                disc_size = self->priv->current->sectors;
1475
 
        else
1476
 
                disc_size = self->priv->current->free_space;
1477
 
 
1478
 
        if (disc_size < 0)
1479
 
                disc_size = 0;
1480
 
 
1481
 
        /* FIXME: This is not good since with a DVD 3% of 4.3G may be too much
1482
 
         * with 3% we are slightly over the limit of the most overburnable discs
1483
 
         * but at least users can try to overburn as much as they can. */
1484
 
 
1485
 
        /* The idea would be to test write the disc with cdrecord from /dev/null
1486
 
         * until there is an error and see how much we were able to write. So,
1487
 
         * when we propose overburning to the user, we could ask if he wants
1488
 
         * us to determine how much data can be written to a particular disc
1489
 
         * provided he has chosen a real disc. */
1490
 
        max_sectors = disc_size * 103 / 100;
1491
 
 
1492
 
        if (disc_size <= 0) {
1493
 
                if (overburn)
1494
 
                        *overburn = FALSE;
1495
 
 
1496
 
                return TRUE;
1497
 
        }
1498
 
 
1499
 
        if (max_sectors < self->priv->sectors) {
1500
 
                if (overburn)
1501
 
                        *overburn = FALSE;
1502
 
 
1503
 
                return FALSE;
1504
 
        }
1505
 
 
1506
 
        if (disc_size < self->priv->sectors) {
1507
 
                if (overburn)
1508
 
                        *overburn = TRUE;
1509
 
 
1510
 
                return FALSE;
1511
 
        }
1512
 
 
1513
 
        return TRUE;
1514
 
}
1515
 
 
1516
 
/********************************* real drives *********************************/
1517
 
static void
1518
 
brasero_project_size_disc_added_cb (BraseroMediumMonitor *monitor,
1519
 
                                    BraseroMedium *medium,
1520
 
                                    BraseroProjectSize *self)
1521
 
{
1522
 
        BraseroDriveSize *drive;
1523
 
 
1524
 
        /* first add it to the list */
1525
 
        drive = g_new0 (BraseroDriveSize, 1);
1526
 
        drive->medium = medium;
1527
 
        g_object_ref (medium);
1528
 
 
1529
 
        self->priv->drives = g_list_prepend (self->priv->drives, drive);
1530
 
 
1531
 
        drive->media = brasero_medium_get_status (medium);
1532
 
 
1533
 
        /* If there is an appendable session we just ignore it, the size of this
1534
 
         * session will simply be added to the size of the project if the user
1535
 
         * decides to merge them */
1536
 
        brasero_medium_get_capacity (medium, NULL, &drive->sectors);
1537
 
        brasero_medium_get_free_space (medium, NULL, &drive->free_space);
1538
 
 
1539
 
        brasero_project_size_find_proper_drive (self);
1540
 
        brasero_project_size_disc_changed (self);
1541
 
 
1542
 
        /* we need to rebuild the menu is any */
1543
 
        if (self->priv->menu)
1544
 
                brasero_project_size_show_menu_real (self, NULL);
1545
 
}
1546
 
 
1547
 
static void
1548
 
brasero_project_size_disc_removed_cb (BraseroMediumMonitor *monitor,
1549
 
                                      BraseroMedium *medium,
1550
 
                                      BraseroProjectSize *self)
1551
 
{
1552
 
        GList *iter;
1553
 
        GList *next;
1554
 
 
1555
 
        for (iter = self->priv->drives; iter; iter = next) {
1556
 
                BraseroDriveSize *drive;
1557
 
 
1558
 
                drive = iter->data;
1559
 
                next = iter->next;
1560
 
                if (medium == drive->medium) {
1561
 
                        if (self->priv->current == drive)
1562
 
                                self->priv->current = NULL;
1563
 
 
1564
 
                        self->priv->drives = g_list_remove (self->priv->drives, drive);
1565
 
                        g_object_unref (drive->medium);
1566
 
                        g_free (drive);
1567
 
                }
1568
 
        }
1569
 
 
1570
 
        brasero_project_size_find_proper_drive (self);
1571
 
        brasero_project_size_disc_changed (self);
1572
 
 
1573
 
        /* we need to rebuild the menu is any */
1574
 
        if (self->priv->menu)
1575
 
                brasero_project_size_show_menu_real (self, NULL);
1576
 
}
1577
 
 
1578
 
static void
1579
 
brasero_project_size_add_real_medias (BraseroProjectSize *self)
1580
 
{
1581
 
        GSList *iter, *list;
1582
 
        BraseroMediumMonitor *monitor;
1583
 
 
1584
 
        monitor = brasero_medium_monitor_get_default ();
1585
 
        g_signal_connect (monitor,
1586
 
                          "medium-added",
1587
 
                          G_CALLBACK (brasero_project_size_disc_added_cb),
1588
 
                          self);
1589
 
        g_signal_connect (monitor,
1590
 
                          "medium-removed",
1591
 
                          G_CALLBACK (brasero_project_size_disc_removed_cb),
1592
 
                          self);
1593
 
        list = brasero_medium_monitor_get_media (monitor,
1594
 
                                                 BRASERO_MEDIA_TYPE_WRITABLE|
1595
 
                                                 BRASERO_MEDIA_TYPE_REWRITABLE);
1596
 
        g_object_unref (monitor);
1597
 
 
1598
 
        for (iter = list; iter; iter = iter->next) {
1599
 
                BraseroDriveSize *drive;
1600
 
 
1601
 
                drive = g_new0 (BraseroDriveSize, 1);
1602
 
                drive->medium = iter->data;
1603
 
                self->priv->drives = g_list_prepend (self->priv->drives, drive);
1604
 
 
1605
 
                /* get all the information about the current media */
1606
 
                drive->media = brasero_medium_get_status (drive->medium);
1607
 
                if (!BRASERO_MEDIUM_VALID (drive->media))
1608
 
                        continue;
1609
 
 
1610
 
                brasero_medium_get_capacity (drive->medium, NULL, &drive->sectors);
1611
 
                brasero_medium_get_free_space (drive->medium, NULL, &drive->free_space);
1612
 
        }
1613
 
        g_slist_free (list);
1614
 
 
1615
 
        brasero_project_size_find_proper_drive (self);
1616
 
        brasero_project_size_disc_changed (self);
1617
 
}
1618
 
 
1619
 
gint
1620
 
brasero_project_get_ruler_height (BraseroProjectSize *self)
1621
 
{
1622
 
        return self->priv->ruler_height;
1623
 
}
1624
 
 
1625
 
BraseroMedium *
1626
 
brasero_project_size_get_active_medium (BraseroProjectSize *self)
1627
 
{
1628
 
        BraseroMedium *medium;
1629
 
 
1630
 
        if (!self->priv->current)
1631
 
                return NULL;
1632
 
 
1633
 
        if (!self->priv->current->medium)
1634
 
                return NULL;
1635
 
 
1636
 
        medium = self->priv->current->medium;
1637
 
        g_object_ref (medium);
1638
 
        return medium;
1639
 
}