1
/***************************************************************************
2
* brasero-project-size.c
4
* jeu jui 27 11:54:52 2006
5
* Copyright 2006 Rouquier Philippe
6
* brasero-app@wanadoo.fr
7
***************************************************************************/
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.
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.
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.
34
#include <glib-object.h>
35
#include <glib/gi18n-lib.h>
37
#include <gtk/gtkwidget.h>
38
#include <gtk/gtkmenu.h>
39
#include <gtk/gtkcontainer.h>
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"
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);
53
static void brasero_project_size_realize (GtkWidget *widget);
54
static void brasero_project_size_unrealize (GtkWidget *widget);
57
brasero_project_size_size_request (GtkWidget *widget,
58
GtkRequisition *requisition);
60
brasero_project_size_size_allocate (GtkWidget *widget,
61
GtkAllocation *allocation);
64
brasero_project_size_expose (GtkWidget *widget,
65
GdkEventExpose *event);
68
brasero_project_size_button_toggled_cb (GtkToggleButton *button,
69
BraseroProjectSize *self);
72
brasero_project_size_scroll_event (GtkWidget *widget,
73
GdkEventScroll *event);
76
brasero_project_size_add_real_medias (BraseroProjectSize *self);
79
brasero_project_size_disc_changed_cb (GtkMenuItem *item,
80
BraseroProjectSize *self);
83
brasero_project_size_forall_children (GtkContainer *container,
84
gboolean include_internals,
86
gpointer callback_data);
88
struct _BraseroDriveSize {
92
BraseroMedium *medium;
94
typedef struct _BraseroDriveSize BraseroDriveSize;
96
struct _BraseroProjectSizePrivate {
107
PangoLayout *text_layout;
111
BraseroDriveSize *current;
113
BraseroProjectType context;
121
enum _BraseroProjectSizeSignalType {
126
#define BRASERO_PROJECT_SIZE_HEIGHT 42
128
#define BRASERO_PROJECT_SIZE_SPACE 12
130
#define BRASERO_ARROW_NUM 4
131
#define ARROW_WIDTH 6
132
#define ARROW_HEIGHT 8
134
#define AUDIO_SECTOR_SIZE 2352
135
#define DATA_SECTOR_SIZE 2048
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
143
#define DRIVE_STRUCT "drive-struct"
145
static guint brasero_project_size_signals [LAST_SIGNAL] = { 0 };
146
static GtkWidgetClass *parent_class = NULL;
149
brasero_project_size_get_type ()
151
static GType type = 0;
154
static const GTypeInfo our_info = {
155
sizeof (BraseroProjectSizeClass),
158
(GClassInitFunc)brasero_project_size_class_init,
161
sizeof (BraseroProjectSize),
163
(GInstanceInitFunc)brasero_project_size_init,
166
type = g_type_register_static (GTK_TYPE_CONTAINER,
167
"BraseroProjectSize",
176
brasero_project_size_class_init (BraseroProjectSizeClass *klass)
178
GObjectClass *object_class = G_OBJECT_CLASS (klass);
179
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
180
GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
182
parent_class = g_type_class_peek_parent(klass);
183
object_class->finalize = brasero_project_size_finalize;
185
widget_class->scroll_event = brasero_project_size_scroll_event;
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;
193
container_class->forall = brasero_project_size_forall_children;
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),
201
g_cclosure_marshal_VOID__VOID,
207
brasero_project_size_add_default_medias (BraseroProjectSize *self)
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},
216
const BraseroDriveSize *iter;
218
for (iter = drives; iter->sectors; iter ++) {
219
BraseroDriveSize *drive;
221
drive = g_new0 (BraseroDriveSize, 1);
222
memcpy (drive, iter, sizeof (BraseroDriveSize));
223
self->priv->drives = g_list_prepend (self->priv->drives, drive);
228
brasero_project_size_init (BraseroProjectSize *obj)
232
GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (obj), GTK_NO_WINDOW);
234
obj->priv = g_new0 (BraseroProjectSizePrivate, 1);
235
obj->priv->text_layout = gtk_widget_create_pango_layout (GTK_WIDGET (obj), "");
237
brasero_project_size_add_default_medias (obj);
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,
245
G_CALLBACK (brasero_project_size_button_toggled_cb),
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);
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);
254
gtk_widget_set_parent (obj->priv->button, GTK_WIDGET (obj));
255
gtk_widget_show_all (obj->priv->button);
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);
261
obj->priv->frame = gtk_frame_new (NULL);
262
gtk_frame_set_shadow_type (GTK_FRAME (obj->priv->frame), GTK_SHADOW_IN);
264
gtk_widget_set_parent (obj->priv->frame, GTK_WIDGET (obj));
265
gtk_widget_show_all (obj->priv->frame);
269
brasero_project_size_finalize (GObject *object)
271
BraseroProjectSize *cobj;
274
cobj = BRASERO_PROJECT_SIZE (object);
276
if (cobj->priv->frame) {
277
gtk_widget_unparent (cobj->priv->frame);
278
cobj->priv->frame = NULL;
281
if (cobj->priv->button) {
282
gtk_widget_unparent (cobj->priv->button);
283
cobj->priv->button = NULL;
286
if (cobj->priv->arrow) {
287
gtk_widget_unparent (cobj->priv->arrow);
288
cobj->priv->arrow = NULL;
291
if (cobj->priv->refresh_id) {
292
g_source_remove (cobj->priv->refresh_id);
293
cobj->priv->refresh_id = 0;
296
if (cobj->priv->menu) {
297
gtk_widget_destroy (cobj->priv->menu);
298
cobj->priv->menu = NULL;
301
if (cobj->priv->text_layout) {
302
g_object_unref (cobj->priv->text_layout);
303
cobj->priv->text_layout = NULL;
306
for (iter = cobj->priv->drives; iter; iter = iter->next) {
307
BraseroDriveSize *drive;
312
g_object_unref (drive->medium);
316
g_list_free (cobj->priv->drives);
319
G_OBJECT_CLASS (parent_class)->finalize(object);
323
brasero_project_size_new ()
327
obj = GTK_WIDGET (g_object_new (BRASERO_TYPE_PROJECT_SIZE, NULL));
333
brasero_project_size_forall_children (GtkContainer *container,
334
gboolean include_internals,
335
GtkCallback callback,
336
gpointer callback_data)
338
if (include_internals) {
339
BraseroProjectSize *self;
341
self = BRASERO_PROJECT_SIZE (container);
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);
353
brasero_project_size_realize (GtkWidget *widget)
355
GdkWindowAttr attributes;
356
gint attributes_mask;
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|
371
attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_COLORMAP | GDK_WA_COLORMAP;
373
widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
376
gdk_window_set_user_data (widget->window, widget);
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);
387
widget->style = gtk_style_attach (widget->style, widget->window);
388
gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
390
GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
394
brasero_project_size_unrealize (GtkWidget *widget)
396
GTK_WIDGET_UNSET_FLAGS (widget, GTK_REALIZED);
398
if (GTK_WIDGET_CLASS (parent_class)->unrealize)
399
GTK_WIDGET_CLASS (parent_class)->unrealize (widget);
403
brasero_project_size_get_ruler_min_width (BraseroProjectSize *self,
407
PangoRectangle extents = { 0 };
410
BraseroDriveSize *drive;
412
gint max_width, max_height, total;
416
drive = self->priv->current;
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;
429
interval_size = DATA_INTERVAL_CD;
431
/* Here is the rule for the displaying of sizes:
432
* if the disc is rewritable and multisession is on, then show the
434
* if the disc is rewritable and multisession is off, then show the
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
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.
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;
448
total = drive->free_space > self->priv->sectors ? drive->free_space:self->priv->sectors;
451
num = (gdouble) total / (gdouble) interval_size;
452
if (num > MAX_INTERVAL)
454
else if (num < MIN_INTERVAL)
456
} while (num > MAX_INTERVAL || num < MIN_INTERVAL);
459
max_height = ARROW_HEIGHT;
461
layout = gtk_widget_create_pango_layout (GTK_WIDGET (self), NULL);
462
for (i = 1.0; i < num; i ++) {
463
gchar *markup, *string;
465
string = brasero_utils_get_sectors_string (i * interval_size,
466
(self->priv->context != BRASERO_PROJECT_TYPE_DATA),
470
markup = g_strdup_printf ("<span size='x-small' foreground='grey10'>%s</span>", string);
473
pango_layout_set_markup (layout, markup, -1);
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);
480
g_object_unref (layout);
482
*ruler_width = (max_width + GTK_WIDGET (self)->style->xthickness * 2 + ARROW_WIDTH) * num;
483
*ruler_height = max_height;
487
brasero_project_size_get_media_string (BraseroProjectSize *self)
491
BraseroDriveSize *drive;
493
gchar *drive_name = NULL;
494
gchar *disc_sectors_str = NULL;
495
gchar *selection_size_str = NULL;
497
drive = self->priv->current;
501
status = brasero_medium_get_status (drive->medium);
503
&& (status & BRASERO_MEDIUM_REWRITABLE)
504
&& !self->priv->multi)
505
disc_size = drive->sectors;
507
disc_size = drive->free_space;
509
/* we should round the disc sizes / length */
510
if (drive->sectors == -2) {
511
/* this is an empty drive */
515
if (status == BRASERO_MEDIUM_BUSY) {
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);
523
return disc_sectors_str;
526
if (drive->sectors == -1) {
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);
534
return disc_sectors_str;
537
if (status == BRASERO_MEDIUM_UNSUPPORTED) {
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);
545
return disc_sectors_str;
548
disc_sectors_str = brasero_utils_get_sectors_string (disc_size,
549
(self->priv->context != BRASERO_PROJECT_TYPE_DATA),
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) {
560
tmp = g_strdup_printf ("%.16s...", drive_name);
566
selection_size_str = brasero_utils_get_sectors_string (self->priv->sectors,
567
(self->priv->context != BRASERO_PROJECT_TYPE_DATA),
571
if (self->priv->sectors > disc_size) {
573
text = g_strdup_printf (_("<b>Oversized</b> (%s / %s in <i>%s</i>)"),
578
text = g_strdup_printf (_("<b>Oversized</b> (%s / %s)"),
582
else if (self->priv->sectors == 0) {
584
text = g_strdup_printf (_("<b>Empty</b> (%s free for <i>%s</i>)"),
588
text = g_strdup_printf (_("<b>Empty</b> (%s free)"),
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>)"),
602
* - %s is the size of the project
603
* - %s is the size available (on disc) */
604
text = g_strdup_printf (_("%s / %s"),
608
g_free (selection_size_str);
609
g_free (disc_sectors_str);
616
brasero_project_size_size_request (GtkWidget *widget,
617
GtkRequisition *requisition)
619
gint width, height, ruler_width, ruler_height;
620
PangoRectangle extents = { 0 };
621
BraseroProjectSize *self;
625
self = BRASERO_PROJECT_SIZE (widget);
627
/* Set markup every time a size change this function is called */
628
text = brasero_project_size_get_media_string (self);
630
pango_layout_set_markup (self->priv->text_layout, text, -1);
634
brasero_project_size_get_ruler_min_width (self, &ruler_width, &ruler_height);
635
gtk_widget_size_request (self->priv->button, &req);
637
width = self->priv->frame->style->xthickness * 2 + req.width * 2;
639
height = extents.height + self->priv->frame->style->ythickness * 2;
640
height = MAX (height, req.height);
641
height += ruler_height;
643
requisition->height = height;
644
requisition->width = width;
646
self->priv->ruler_height = ruler_height;
650
brasero_project_size_size_allocate (GtkWidget *widget,
651
GtkAllocation *allocation)
653
BraseroProjectSize *self;
657
gboolean is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
659
widget->allocation = *allocation;
660
if (GTK_WIDGET_REALIZED (widget) && !GTK_WIDGET_NO_WINDOW (widget)) {
661
gdk_window_move_resize (widget->window,
668
/* allocate the size for the button */
669
self = BRASERO_PROJECT_SIZE (widget);
670
gtk_widget_size_request (self->priv->button, &req);
672
/* NOTE: since we've got our own window, we don't need to take into
673
* account alloc.x and alloc.y */
675
alloc.x = allocation->width - req.width - 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);
684
/* allocate the size for the arrow we want to draw on the button */
686
alloc.x += alloc.width / 2;
688
alloc.x = alloc.width / 2;
690
alloc.y = self->priv->button->style->ythickness;
693
gtk_widget_size_allocate (self->priv->arrow, &alloc);
697
brasero_project_size_expose (GtkWidget *widget, GdkEventExpose *event)
699
PangoRectangle extents = { 0 };
702
gint interval_size, interval_width;
703
gint x, y, width, total;
706
guint next_possible = 0;
708
BraseroProjectSize *self;
709
gdouble fraction = 0.0;
710
gint text_height = 0;
711
BraseroDriveSize *drive;
713
gint bar_width, bar_height;
720
gboolean is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
722
if (!GTK_WIDGET_DRAWABLE (widget))
725
self = BRASERO_PROJECT_SIZE (widget);
727
/* paint the button and arrow */
728
gtk_container_propagate_expose (GTK_CONTAINER (widget),
731
gtk_container_propagate_expose (GTK_CONTAINER (widget),
735
button_width = self->priv->button->allocation.width;
737
drive = self->priv->current;
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. */
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;
749
interval_size = DATA_INTERVAL_CD;
751
total = self->priv->current->sectors > self->priv->sectors ? self->priv->current->sectors:self->priv->sectors;
753
num = (gdouble) total / (gdouble) interval_size;
754
if (num > MAX_INTERVAL)
756
else if (num < MIN_INTERVAL)
758
} while (num > MAX_INTERVAL || num < MIN_INTERVAL);
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;
765
layout = gtk_widget_create_pango_layout (widget, NULL);
768
next_possible = widget->allocation.width - button_width - self->priv->frame->style->xthickness;
770
next_possible = button_width + self->priv->frame->style->xthickness;
772
for (i = 1.; i < num; i ++) {
776
string = brasero_utils_get_sectors_string (i * interval_size,
777
(self->priv->context != BRASERO_PROJECT_TYPE_DATA),
781
markup = g_strdup_printf ("<span size='x-small' foreground='grey10'>%s</span>", string);
783
pango_layout_set_markup (layout, markup, -1);
786
pango_layout_get_pixel_extents (layout, NULL, &extents);
788
text_height = MAX (text_height, extents.height);
789
y = widget->allocation.height - extents.height;
792
x = widget->allocation.width - button_width - self->priv->frame->style->xthickness -
795
x = button_width + self->priv->frame->style->xthickness + i * interval_width;
797
if (!is_rtl && x <= next_possible)
800
if (is_rtl && x >= next_possible)
804
text_x = x + widget->style->xthickness + ARROW_WIDTH / 2 + 2;
806
text_x = x - widget->style->xthickness - ARROW_WIDTH / 2 - extents.width - 2;
808
if (!is_rtl && text_x <= next_possible)
811
if (is_rtl && text_x + extents.width >= next_possible)
814
gtk_paint_layout (widget->style,
825
gtk_paint_arrow (widget->style,
828
GTK_SHADOW_ETCHED_IN,
834
x - widget->style->xthickness - ARROW_WIDTH/ 2,
835
widget->allocation.height - text_height,
839
/* calculate the next possible location (2 pixels spacing) */
841
next_possible = x - ARROW_WIDTH / 2;
843
next_possible = x + 2 + ARROW_WIDTH / 2;
845
g_object_unref (layout);
847
bar_height = widget->allocation.height - text_height - 2;
850
&& (brasero_medium_get_status (drive->medium) & BRASERO_MEDIUM_REWRITABLE)
851
&& !self->priv->multi)
852
disc_size = drive->sectors;
854
disc_size = drive->free_space;
857
fraction = ((gdouble) self->priv->sectors / (gdouble) disc_size);
859
width = bar_width / fraction * 1.0;
861
width = fraction * bar_width;
864
x = self->priv->frame->style->xthickness + bar_width - width;
866
x = self->priv->frame->style->xthickness + button_width;
868
gtk_paint_flat_box (widget->style,
870
GTK_STATE_INSENSITIVE,
876
self->priv->frame->style->ythickness,
878
bar_height - self->priv->frame->style->ythickness);
880
if (fraction > 1.0) {
884
width2 = bar_width / fraction * 0.03;
886
width2 = bar_width / fraction * (fraction - 1.0);
889
x = widget->allocation.width - width - width2 - self->priv->frame->style->xthickness - button_width;
891
x = width + self->priv->frame->style->xthickness + button_width;
893
gtk_paint_flat_box (widget->style,
901
self->priv->frame->style->ythickness,
903
bar_height - self->priv->frame->style->ythickness * 2);
905
if (fraction > 1.03) {
907
x = widget->allocation.width - bar_width - self->priv->frame->style->xthickness - button_width;
909
x = width + width2 + self->priv->frame->style->xthickness + button_width;
911
gtk_paint_flat_box (widget->style,
919
self->priv->frame->style->ythickness,
920
bar_width - width - width2,
921
bar_height - self->priv->frame->style->ythickness);
925
/* This is the white part */
927
x = self->priv->frame->style->xthickness;
929
x = width ? width + button_width:self->priv->frame->style->xthickness + button_width;
931
gtk_paint_flat_box (widget->style,
939
self->priv->frame->style->ythickness,
940
bar_width - width + self->priv->frame->style->xthickness,
941
bar_height - self->priv->frame->style->ythickness);
944
/* Frame around bar */
948
alloc.x = button_width;
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),
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);
966
pango_layout_set_ellipsize (self->priv->text_layout, PANGO_ELLIPSIZE_NONE);
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;
975
gtk_paint_layout (widget->style,
984
self->priv->text_layout);
990
brasero_project_size_disc_changed (BraseroProjectSize *self)
992
gtk_widget_queue_resize (GTK_WIDGET (self));
994
brasero_project_size_signals [DISC_CHANGED_SIGNAL],
999
brasero_project_size_disc_changed_cb (GtkMenuItem *item,
1000
BraseroProjectSize *self)
1002
BraseroDriveSize *drive;
1004
drive = g_object_get_data (G_OBJECT (item), DRIVE_STRUCT);
1005
self->priv->current = drive;
1006
brasero_project_size_disc_changed (self);
1010
brasero_project_size_menu_position_cb (GtkMenu *menu,
1021
GdkRectangle monitor;
1022
GtkWidget *self = user_data;
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);
1028
gdk_drawable_get_size (GDK_DRAWABLE (self->window), &width, &height);
1029
gtk_widget_set_size_request (GTK_WIDGET (menu), width, -1);
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);
1040
else if (*x + req.width > monitor.x + monitor.width)
1041
*x = monitor.x + monitor.width - req.width;
1048
brasero_project_size_is_valid_drive (BraseroProjectSize *self,
1049
BraseroDriveSize *current)
1051
BraseroBurnCaps *caps;
1052
gboolean result = TRUE;
1053
BraseroMedia media_status;
1058
caps = brasero_burn_caps_get_default ();
1059
media_status = brasero_burn_caps_media_capabilities (caps, current->media);
1061
if (!BRASERO_MEDIUM_VALID (current->media))
1063
/* Library must support it */
1064
else if (!(media_status & (BRASERO_MEDIUM_WRITABLE|BRASERO_MEDIUM_REWRITABLE)))
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))
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)))
1076
g_object_unref (caps);
1081
brasero_project_size_build_menu (BraseroProjectSize *self)
1089
menu = gtk_menu_new ();
1092
for (iter = self->priv->drives; iter; iter = iter->next) {
1093
BraseroDriveSize *drive;
1100
if (!brasero_project_size_is_valid_drive (self, drive))
1103
if (!drive->medium && !separator) {
1104
item = gtk_separator_menu_item_new ();
1105
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1108
else if (drive->medium)
1112
&& (brasero_medium_get_status (drive->medium) & BRASERO_MEDIUM_REWRITABLE)
1113
&& !self->priv->multi)
1114
disc_size = drive->sectors;
1116
disc_size = drive->free_space;
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);
1121
size_str = brasero_utils_get_size_string (disc_size * DATA_SECTOR_SIZE, TRUE, TRUE);
1123
if (drive->medium) {
1126
name = brasero_volume_get_display_label (BRASERO_VOLUME (drive->medium), FALSE);
1127
label = g_strdup_printf ("%s %s", size_str, name);
1130
else if (drive->media & BRASERO_MEDIUM_DVD_DL)
1131
label = g_strdup_printf (_("%s (DVD-R Dual Layer)"),
1133
else if (drive->media & BRASERO_MEDIUM_DVD)
1134
label = g_strdup_printf (_("%s (DVD-R)"),
1137
label = g_strdup_printf (_("%s (CD-R)"),
1142
if (self->priv->current == drive) {
1146
/* This is the selected drive mark it as such */
1147
tmp = g_strdup_printf ("<b><i>%s</i></b>", label);
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);
1157
item = gtk_image_menu_item_new ();
1158
gtk_item_select (GTK_ITEM (item));
1159
gtk_container_add (GTK_CONTAINER (item), widget);
1162
item = gtk_image_menu_item_new_with_label (label);
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);
1171
image = gtk_image_new_from_icon_name ("gnome-dev-disc-cdr", GTK_ICON_SIZE_MENU);
1173
gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
1175
g_signal_connect (item,
1177
G_CALLBACK (brasero_project_size_disc_changed_cb),
1180
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1181
g_object_set_data (G_OBJECT (item), DRIVE_STRUCT, drive);
1184
gtk_widget_show_all (menu);
1190
brasero_project_size_menu_finished_cb (GtkMenuShell *shell,
1191
BraseroProjectSize *self)
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);
1200
brasero_project_size_show_menu_real (BraseroProjectSize *self,
1201
GdkEventButton *event)
1205
menu = brasero_project_size_build_menu (self);
1209
if (self->priv->menu)
1210
gtk_widget_destroy (self->priv->menu);
1212
self->priv->menu = menu;
1213
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (self->priv->button), TRUE);
1215
gtk_arrow_set (GTK_ARROW (self->priv->arrow), GTK_ARROW_DOWN, GTK_SHADOW_NONE);
1217
gtk_menu_popup (GTK_MENU (menu),
1220
brasero_project_size_menu_position_cb,
1222
event ? event->button:1,
1223
event ? event->time:gtk_get_current_event_time ());
1225
g_signal_connect (menu,
1227
G_CALLBACK (brasero_project_size_menu_finished_cb),
1232
brasero_project_size_button_toggled_cb (GtkToggleButton *button,
1233
BraseroProjectSize *self)
1235
if (gtk_toggle_button_get_active (button)) {
1236
if (self->priv->menu)
1239
else if (!self->priv->menu)
1242
brasero_project_size_show_menu_real (self, NULL);
1246
brasero_project_size_scroll_event (GtkWidget *widget,
1247
GdkEventScroll *event)
1249
BraseroProjectSize *self;
1251
self = BRASERO_PROJECT_SIZE (widget);
1253
if (event->direction == GDK_SCROLL_DOWN) {
1256
node = g_list_find (self->priv->drives, self->priv->current);
1257
iter = g_list_next (node);
1261
while (iter != node) {
1262
BraseroDriveSize *drive;
1266
/* must be a valid media */
1267
if (!brasero_project_size_is_valid_drive (self, drive))
1268
iter = g_list_next (iter);
1270
self->priv->current = drive;
1277
brasero_project_size_disc_changed (self);
1279
else if (event->direction == GDK_SCROLL_UP) {
1282
node = g_list_find (self->priv->drives, self->priv->current);
1283
iter = g_list_previous (node);
1287
while (iter != node) {
1288
BraseroDriveSize *drive;
1292
/* must be a valid media */
1293
if (!brasero_project_size_is_valid_drive (self, drive))
1294
iter = g_list_previous (iter);
1296
self->priv->current = drive;
1303
brasero_project_size_disc_changed (self);
1310
brasero_project_size_update_sectors (BraseroProjectSize *self)
1312
gtk_widget_queue_resize (GTK_WIDGET (self));
1313
self->priv->refresh_id = 0;
1318
brasero_project_size_set_sectors (BraseroProjectSize *self,
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 */
1328
/* we add 175 sectors for a single session track (that's the needed
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
1339
/* FIXME: for now just add 500 sectors = 1Mib */
1341
self->priv->sectors = sectors + 500;
1343
self->priv->sectors = 0;
1345
if (!self->priv->refresh_id)
1346
self->priv->refresh_id = g_timeout_add (500,
1347
(GSourceFunc) brasero_project_size_update_sectors,
1352
brasero_project_size_find_proper_drive (BraseroProjectSize *self)
1355
BraseroDriveSize *candidate = NULL;
1357
if (self->priv->current) {
1358
BraseroDriveSize *current;
1360
/* we check the current drive to see if it is suitable */
1361
current = self->priv->current;
1363
if (!brasero_project_size_is_valid_drive (self, current))
1365
else if (current->sectors >= self->priv->sectors && current->medium) {
1366
/* The current drive is still a perfect fit keep it */
1369
else if (self->priv->multi) {
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. */
1380
else /* see if there is better */
1381
candidate = self->priv->current;
1384
/* Try to find the first best candidate */
1385
for (iter = self->priv->drives; iter; iter = iter->next) {
1386
BraseroDriveSize *drive;
1390
if (!brasero_project_size_is_valid_drive (self, drive))
1393
/* we must have at least one candidate */
1397
/* Try to find a drive large enough */
1398
if (drive->sectors < self->priv->sectors)
1401
if (candidate->sectors < self->priv->sectors) {
1402
if (!candidate->medium) {
1408
else if (drive->medium) {
1413
else if (drive->medium) {
1419
self->priv->current = candidate;
1423
brasero_project_size_set_context (BraseroProjectSize *self,
1424
BraseroProjectType type)
1426
BraseroDriveSize *current;
1428
self->priv->sectors = 0;
1429
self->priv->context = type;
1431
if (!self->priv->is_loaded) {
1432
brasero_project_size_add_real_medias (self);
1433
self->priv->is_loaded = 1;
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;
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);
1450
brasero_project_size_disc_changed (self);
1454
brasero_project_size_set_multisession (BraseroProjectSize *self,
1457
self->priv->multi = multi;
1458
brasero_project_size_disc_changed (self);
1462
brasero_project_size_check_status (BraseroProjectSize *self,
1468
if (!self->priv->current)
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;
1476
disc_size = self->priv->current->free_space;
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. */
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;
1492
if (disc_size <= 0) {
1499
if (max_sectors < self->priv->sectors) {
1506
if (disc_size < self->priv->sectors) {
1516
/********************************* real drives *********************************/
1518
brasero_project_size_disc_added_cb (BraseroMediumMonitor *monitor,
1519
BraseroMedium *medium,
1520
BraseroProjectSize *self)
1522
BraseroDriveSize *drive;
1524
/* first add it to the list */
1525
drive = g_new0 (BraseroDriveSize, 1);
1526
drive->medium = medium;
1527
g_object_ref (medium);
1529
self->priv->drives = g_list_prepend (self->priv->drives, drive);
1531
drive->media = brasero_medium_get_status (medium);
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);
1539
brasero_project_size_find_proper_drive (self);
1540
brasero_project_size_disc_changed (self);
1542
/* we need to rebuild the menu is any */
1543
if (self->priv->menu)
1544
brasero_project_size_show_menu_real (self, NULL);
1548
brasero_project_size_disc_removed_cb (BraseroMediumMonitor *monitor,
1549
BraseroMedium *medium,
1550
BraseroProjectSize *self)
1555
for (iter = self->priv->drives; iter; iter = next) {
1556
BraseroDriveSize *drive;
1560
if (medium == drive->medium) {
1561
if (self->priv->current == drive)
1562
self->priv->current = NULL;
1564
self->priv->drives = g_list_remove (self->priv->drives, drive);
1565
g_object_unref (drive->medium);
1570
brasero_project_size_find_proper_drive (self);
1571
brasero_project_size_disc_changed (self);
1573
/* we need to rebuild the menu is any */
1574
if (self->priv->menu)
1575
brasero_project_size_show_menu_real (self, NULL);
1579
brasero_project_size_add_real_medias (BraseroProjectSize *self)
1581
GSList *iter, *list;
1582
BraseroMediumMonitor *monitor;
1584
monitor = brasero_medium_monitor_get_default ();
1585
g_signal_connect (monitor,
1587
G_CALLBACK (brasero_project_size_disc_added_cb),
1589
g_signal_connect (monitor,
1591
G_CALLBACK (brasero_project_size_disc_removed_cb),
1593
list = brasero_medium_monitor_get_media (monitor,
1594
BRASERO_MEDIA_TYPE_WRITABLE|
1595
BRASERO_MEDIA_TYPE_REWRITABLE);
1596
g_object_unref (monitor);
1598
for (iter = list; iter; iter = iter->next) {
1599
BraseroDriveSize *drive;
1601
drive = g_new0 (BraseroDriveSize, 1);
1602
drive->medium = iter->data;
1603
self->priv->drives = g_list_prepend (self->priv->drives, drive);
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))
1610
brasero_medium_get_capacity (drive->medium, NULL, &drive->sectors);
1611
brasero_medium_get_free_space (drive->medium, NULL, &drive->free_space);
1613
g_slist_free (list);
1615
brasero_project_size_find_proper_drive (self);
1616
brasero_project_size_disc_changed (self);
1620
brasero_project_get_ruler_height (BraseroProjectSize *self)
1622
return self->priv->ruler_height;
1626
brasero_project_size_get_active_medium (BraseroProjectSize *self)
1628
BraseroMedium *medium;
1630
if (!self->priv->current)
1633
if (!self->priv->current->medium)
1636
medium = self->priv->current->medium;
1637
g_object_ref (medium);