summaryrefslogtreecommitdiffstats
path: root/rescue
Commit message (Expand)AuthorAgeFilesLines
* *** empty log message ***Pascal Rigaux2005-03-211-0/+1
* addmd5 to the generated isoPascal Rigaux2005-03-211-0/+1
* factorizePascal Rigaux2005-03-211-3/+5
* tell how to go back to the rescue menuOlivier Blin2005-03-181-0/+1
* MERGE: fix ldso nameGwenolé Beauchesne2005-03-171-1/+1
* - in rest_all, try to restore from the cdromPascal Rigaux2005-02-282-6/+26
* add xfs_repair to the rescue (bugzilla #10488)Pascal Rigaux2005-02-281-0/+1
* add a basic partimage save_all/rest_all featurePascal Rigaux2005-02-022-0/+53
* add a dhcp-client built using mdk-stage1 codePascal Rigaux2005-01-311-1/+2
* create /var/logPascal Rigaux2005-01-241-1/+1
* not useful anymore (maybe others are unneeded too?)Pascal Rigaux2005-01-201-3/+0
* we want /mnt at the root of the rescuePascal Rigaux2005-01-201-0/+2
* factorize the distrib versionPascal Rigaux2005-01-153-2/+3
* rsync is useful tooPascal Rigaux2005-01-101-0/+1
* use "mingetty --autologin" instead of calling directly "bash --login", thatPascal Rigaux2005-01-101-1/+1
* have /dev rw (eg: for /dev/initctl)Pascal Rigaux2005-01-101-0/+2
* add what Lord Packdrakeng.pm requestPascal Rigaux2005-01-101-0/+7
* minimal ssh tools (alas it doesn't on console 1 because /dev/tty is allocated...Pascal Rigaux2005-01-101-0/+3
* at least be able to mount /dev/pts if neededPascal Rigaux2005-01-101-0/+1
* ld-linux.so.2 is also needed on the rescue :)Pascal Rigaux2005-01-041-0/+1
* fix typo and perl_checker compliancePascal Rigaux2004-12-021-9/+10
* remove temporary directoryPascal Rigaux2004-12-021-0/+1
* update version for rescue issueFlorent Villard2004-11-301-1/+1
* - drop oem & recovery code (which was broken)Pascal Rigaux2004-11-297-1385/+1
* - no more kernel/all.modules, things are in kernel/all.kernelsPascal Rigaux2004-11-221-3/+2
* move libperl.so from list.ARCH back to list, using a wildcardPascal Rigaux2004-11-165-4/+1
* major switch from ramdisk to clpPascal Rigaux2004-11-163-31/+7
* add partimagePascal Rigaux2004-11-131-0/+1
* umount /stage1 when /etc/mtab exists to remove a warningPascal Rigaux2004-11-051-3/+3
* free up stage1 memoryPascal Rigaux2004-11-051-0/+3
* fix typoPascal Rigaux2004-11-051-1/+1
* keep the tmpfs and rescue in /tmp/stage2Pascal Rigaux2004-11-052-1/+15
* add /sbin/lvm2 to the rescuePascal Rigaux2004-10-141-0/+1
* create /dev/md* devices in rescuePascal Rigaux2004-10-141-0/+1
* add grub filesGwenolé Beauchesne2004-10-041-0/+3
* handle /etc/mandrakelinux-releasePascal Rigaux2004-09-281-1/+5
* /bin/loadkeys is no morePascal Rigaux2004-09-101-1/+0
* umount mount point instead of umounting the loopback filePascal Rigaux2004-08-101-2/+2
* update (Christiaan Welvaart)Pascal Rigaux2004-08-051-0/+5
* replace /sbin/mkraid with /sbin/mdadm (as told on cooker by Luca Berra)Pascal Rigaux2004-08-041-1/+1
* adapt to new directories layout:Pascal Rigaux2004-07-261-6/+2
* MandrakeSoft -> MandrakesoftPascal Rigaux2004-07-207-7/+22
* replace "Mandrake Linux" with "Mandrakelinux"Pascal Rigaux2004-07-193-5/+8
* use "*" instead of PERL_VERSION in list, but ensure only one matchPascal Rigaux2004-07-092-5/+11
* remove file already in cluster/mdkc2 cvs branchAntoine Ginies2004-04-037-1091/+0
* first relseaseAntoine Ginies2004-04-027-0/+1091
* add /sbin/badblocksPascal Rigaux2004-03-301-0/+1
* adapt to perl packages rebuiltPascal Rigaux2004-03-011-1/+1
* 10.0Guillaume Cottenceau2004-02-231-1/+1
* support 2.4 and 2.6Guillaume Cottenceau2004-01-231-5/+19
544' href='#n544'>544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638
package install_steps_gtk; # $Id$

use diagnostics;
use strict;
use vars qw(@ISA);

@ISA = qw(install_steps_interactive interactive::gtk);

#-######################################################################################
#- misc imports
#-######################################################################################
use pkgs;
use install_steps_interactive;
use interactive::gtk;
use xf86misc::main;
use common;
use mygtk2;
use ugtk2 qw(:helpers :wrappers :create);
use devices;
use modules;
use install_gtk;
use install_any;
use mouse;
use help;
use log;

#-######################################################################################
#- In/Out Steps Functions
#-######################################################################################
sub new($$) {
    my ($type, $o) = @_;

    $ENV{DISPLAY} ||= $o->{display} || ":0";
    my $wanted_DISPLAY = $::testing && -x '/usr/X11R6/bin/Xnest' ? ':9' : $ENV{DISPLAY};

    if ($ENV{DISPLAY} =~ /^:\d/ && !$::testing || $ENV{DISPLAY} ne $wanted_DISPLAY) { #- is the display local or distant?
	my $f = "/tmp/Xconf";
	if (!$::testing) {
	    devices::make("/dev/kbd");
	}
	my $launchX = sub {
	    my ($server, $Driver) = @_;

	    mkdir '/var/log' if !-d '/var/log';

	    my @options = $wanted_DISPLAY;
	    if ($server eq 'Xnest') {
		push @options, '-ac', '-geometry', $o->{vga} || ($o->{vga16} ? '640x480' : '800x600');
	    } elsif ($::globetrotter || !$::move) {
                #- use alternate mouse in install if mouse is unsafe or needs some specific module (e.g. synaptics)
                my $mouse = is_empty_hash_ref($o->{mouse}{alternate_install}) ? $o->{mouse} : $o->{mouse}{alternate_install};
		install_gtk::createXconf($f, @$mouse{"XMOUSETYPE", "device"}, $o->{mouse}{wacom}[0], $Driver);

		push @options, if_(!$::globetrotter, '-kb'), '-allowMouseOpenFail', '-xf86config', $f if arch() !~ /^sparc/;
		push @options, 'tty7', '-dpms', '-s', '240';

		#- old weird servers: Xsun
		push @options, '-fp', '/usr/X11R6/lib/X11/fonts:unscaled' if $server =~ /Xsun/;
	    }

	    if (!fork()) {
		c::setsid();
		exec $server, @options or c::_exit(1);
	    }

	    #- wait for the server to start
	    foreach (1..5) {
		sleep 1;
		last if fuzzy_pidofs(qr/\b$server\b/);
		log::l("$server still not running, trying again");
	    }
	    my $nb;
	    foreach (1..60) {
		log::l("waiting for the server to start ($_ $nb)");
		log::l("Server died"), return 0 if !fuzzy_pidofs(qr/\b$server\b/);
		$nb++ if xf86misc::main::Xtest($wanted_DISPLAY);
		if ($nb > 2) { #- one succeeded test is not enough :-(
		    $ugtk2::force_focus = 1;
		    log::l("AFAIK X server is up");
		    return 1;
		}
		sleep 1;
	    }
	    log::l("Timeout!!");
	    0;
	};
	my @servers = qw(Driver:fbdev); #-)
	if ($::testing) {
	    @servers = 'Xnest';
	} elsif (arch() eq "alpha") {
	    require Xconfig::card;
	    my ($card) = Xconfig::card::probe();
	    Xconfig::card::add_to_card__using_Cards($card, $card->{type}) if $card && $card->{type};
	    @servers = $card->{server} || "TGA";
	    #-@servers = qw(SVGA 3DLabs TGA) 
	} elsif (arch() =~ /^sparc/) {
	    local $_ = cat_("/proc/fb");
	    if (/Mach64/) {
		@servers = qw(Mach64);
	    } elsif (/Permedia2/) {
		@servers = qw(3DLabs);
	    } else {
		@servers = qw(Xsun24);
	    }
	} elsif (arch() =~ /ia64|x86_64/) {
	    require Xconfig::card;
	    my ($card) = Xconfig::card::probe();
	    @servers = map { if_($_, "Driver:$_") } $card && $card->{Driver}, 'fbdev';
        }

        if (($::move || $::globetrotter) && !$::testing) {
            require move;
            require run_program;
            move::automatic_xconf($o);
            run_program::run('/sbin/service', 'xfs', 'start');
            @servers = $::globetrotter ? qw(Driver:fbdev) : qw(X_move);
	}

	foreach (@servers) {
	    log::l("Trying with server $_");
	    my ($prog, $Driver) = /Driver:(.*)/ ? ('Xorg', $1) : /Xsun|Xnest|^X_move$/ ? $_ : "XF86_$_";
	    if (/FB/i) {
		!$o->{vga16} && $o->{allowFB} or next;

		$o->{allowFB} = &$launchX($prog, $Driver) #- keep in mind FB is used.
		  and goto OK;
	    } else {
		$o->{vga16} = 1 if /VGA16/;
		&$launchX($prog, $Driver) and goto OK;
	    }
            $::move and print("can not launch graphical mode :(\n"), c::_exit(1);
	}
	return undef;
    }
  OK:
    $ENV{DISPLAY} = $wanted_DISPLAY;
    install_gtk::init_gtk($o);
    install_gtk::init_sizes();
    install_gtk::install_theme($o);
    install_gtk::create_logo_window($o);
    install_gtk::create_steps_window($o);

    $ugtk2::grab = 1;
    $ugtk2::force_center_at_pos = [ $::rootwidth - $::windowwidth, $::logoheight, $::windowwidth, $::windowheight ];

    $o = (bless {}, ref($type) || $type)->SUPER::new($o);
    $o->interactive::gtk::new;
    $o;
}

sub enteringStep {
    my ($o, $step) = @_;

    printf "Entering step `%s'\n", $o->{steps}{$step}{text};
    $o->SUPER::enteringStep($step);
    install_gtk::update_steps_position($o);
#    install_gtk::create_help_window($o); #- HACK: without this it does not work (reaches step doPartitionDisks then fail)
}
sub leavingStep {
    my ($o, $step) = @_;
    $o->SUPER::leavingStep($step);
}


sub charsetChanged {
    my ($o) = @_;
    Gtk2->set_locale;
    install_gtk::load_font($o);
    install_gtk::create_steps_window($o);
}

#-######################################################################################
#- Steps Functions
#-######################################################################################
sub selectLanguage {
    my ($o, $first_time) = @_;
    $o->SUPER::selectLanguage;
  
    $o->ask_warn('',
formatAlaTeX(N("Your system is low on resources. You may have some problem installing
Mandrakelinux. If that occurs, you can try a text install instead. For this,
press `F1' when booting on CDROM, then enter `text'."))) if $first_time && availableRamMB() < 70; # 70MB

}

#------------------------------------------------------------------------------
sub selectMouse {
    my ($o, $force) = @_;
    my %old = %{$o->{mouse}};
    $o->SUPER::selectMouse($force) or return;
    my $mouse = $o->{mouse};
    $mouse->{type} eq 'none' ||
      $old{type}   eq $mouse->{type}   && 
      $old{name}   eq $mouse->{name}   &&
      $old{device} eq $mouse->{device} && !$force and return;

    while (1) {
	my $x_protocol_changed = mouse::change_mouse_live($mouse, \%old);
	mouse::test_mouse_install($mouse, $x_protocol_changed) and return;

	%old = %$mouse;
	$o->SUPER::selectMouse(1);
	$mouse = $o->{mouse};
    } 
}

sub reallyChooseGroups {
    my ($o, $size_to_display, $individual, $_compssUsers) = @_;

    my $w = ugtk2->new('');
    my $w_size = gtknew('Label', text => &$size_to_display);

    my $entry = sub {
	my ($e) = @_;

	gtknew('CheckButton', 
	       text => translate($e->{label}), 
	       tip => translate($e->{descr}),
	       active_ref => \$e->{selected},
	       toggled => sub { 
		   gtkset($w_size, text => &$size_to_display);
	       });
    };
    #- when restarting this step, it might be necessary to reload the compssUsers.pl (bug 11558). kludgy.
    if (!ref $o->{gtk_display_compssUsers}) { install_any::load_rate_files($o) }
    ugtk2::gtkadd($w->{window},
	   gtkpack_($w->create_box_with_title(N("Package Group Selection")),
		    1, $o->{gtk_display_compssUsers}->($entry),
		    1, '',
		   0, gtknew('HBox', children_loose => [
			  gtknew('Button', text => N("Help"), clicked => $o->interactive_help_sub_display_id('choosePackages')),
			  $w_size,
			  if_($individual,
			      gtknew('CheckButton', text => N("Individual package selection"), active_ref => $individual),
			  ),
			  gtknew('Button', text => N("Next"), clicked => sub { Gtk2->main_quit }),
			 ]),
		  ),
	  );
    $w->main;
    1;    
}

sub choosePackagesTree {
    my ($o, $packages, $o_limit_medium) = @_;

    my $available = install_any::getAvailableSpace($o);
    my $availableCorrected = pkgs::invCorrectSize($available / sqr(1024)) * sqr(1024);

    my $common;
    $common = {             get_status => sub {
				my $size = pkgs::selectedSize($packages);
				N("Total size: %d / %d MB", pkgs::correctSize($size / sqr(1024)), $available / sqr(1024));
			    },
			    node_state => sub {
				my $p = pkgs::packageByName($packages, $_[0]) or return;
				pkgs::packageMedium($packages, $p)->{selected} or return;
				$p->arch eq 'src'                       and return;
				$p->flag_base                           and return 'base';
				$p->flag_installed && !$p->flag_upgrade and return 'installed';
				$p->flag_selected                       and return 'selected';
				return 'unselected';
			    },
			    build_tree => sub {
				my ($add_node, $flat) = @_;
				if ($flat) {
				    foreach (sort map { $_->name }
					     grep { !$o_limit_medium || pkgs::packageMedium($packages, $_) == $o_limit_medium }
					     grep { $_ && $_->arch ne 'src' }
					     @{$packages->{depslist}}) {
					$add_node->($_, undef);
				    }
				} else {
				    foreach my $root (@{$o->{compssUsers}}) {
					my (@firstchoice, @others);
					my %fl = map { ("CAT_$_" => 1) } @{$root->{flags}};
					foreach my $p (@{$packages->{depslist}}) {
					    !$o_limit_medium || pkgs::packageMedium($packages, $p) == $o_limit_medium or next;
					    my @flags = $p->rflags;
					    next if !($p->rate && any { any { !/^!/ && $fl{$_} } split('\|\|') } @flags);
					    $p->rate >= 3 ?
					      push(@firstchoice, $p->name) :
						push(@others,    $p->name);
					}
					my $root2 = translate($root->{path}) . '|' . translate($root->{label});
					$add_node->($_, $root2)                    foreach sort @firstchoice;
					$add_node->($_, $root2 . '|' . N("Other")) foreach sort @others;
				    }
				}
			    },
			    get_info => sub {
				my $p = pkgs::packageByName($packages, $_[0]) or return '';
				pkgs::extractHeaders([$p], $packages->{mediums});

				my $imp = translate($pkgs::compssListDesc{$p->flag_base ? 5 : $p->rate});

                                my $tag = { 'foreground' => 'royalblue3' };
				$@ ? N("Bad package") :
				  [ [ N("Name: "), $tag ], [ $p->name . "\n" ],
                                    [ N("Version: "), $tag ], [ $p->version . '-' . $p->release . "\n" ],
                                    [ N("Size: "), $tag ], [ N("%d KB\n", $p->size / 1024) ],
                                    if_($imp, [ N("Importance: "), $tag ], [ "$imp\n" ]),
                                    [ "\n" ], [ formatLines(c::from_utf8($p->description)) ] ];
			    },
			    toggle_nodes => sub {
				my $set_state = shift @_;
				my $isSelection = 0;
				my %l = map { my $p = pkgs::packageByName($packages, $_);
					      $isSelection ||= !$p->flag_selected;
					      $p->id => 1 } @_;
				my $state = $packages->{state} ||= {};
				my @l = $isSelection ? $packages->resolve_requested($packages->{rpmdb}, $state, \%l,
										    callback_choices => \&pkgs::packageCallbackChoices) :
						       $packages->disable_selected($packages->{rpmdb}, $state,
										   map { $packages->{depslist}[$_] } keys %l);
				my $size = pkgs::selectedSize($packages);
				my $error;

				if (!@l) {
				    #- no package can be selected or unselected.
				    my @ask_unselect = grep { $state->{rejected}{$_}{backtrack} &&
								exists $l{$packages->search($_, strict_fullname => 1)->id} }
				      keys %{$state->{rejected} || {}};
				    #- extend to closure (to given more detailed and not absurd reason).
				    my %ask_unselect;
				    while (@ask_unselect > keys %ask_unselect) {
					@ask_unselect{@ask_unselect} = ();
					foreach (keys %ask_unselect) {
					    foreach (keys %{$state->{rejected}{$_}{backtrack}{closure} || {}}) {
						next if exists $ask_unselect{$_};
						push @ask_unselect, $_;
					    }
					}
				    }
				    $error = [ N("You can not select/unselect this package"),
					       formatList(20, map { my $rb = $state->{rejected}{$_}{backtrack};
									    my @froms = keys %{$rb->{closure} || {}};
									    my @unsatisfied = @{$rb->{unsatisfied} || []};
									    my $s = join ", ", ((map { N("due to missing %s", $_) } @froms),
												(map { N("due to unsatisfied %s", $_) } @unsatisfied),
												$rb->{promote} && !$rb->{keep} ? N("trying to promote %s", join(", ", @{$rb->{promote}})) : @{[]},
												$rb->{keep} ? N("in order to keep %s", join(", ", @{$rb->{keep}})) : @{[]},
											       );
									    $_ . ($s ? " ($s)" : '');
									} sort @ask_unselect) ];
				} elsif (pkgs::correctSize($size / sqr(1024)) > $available / sqr(1024)) {
				    $error = N("You can not select this package as there is not enough space left to install it");
				} elsif (@l > @_ && $common->{state}{auto_deps}) {
				    $o->ask_okcancel('', [ $isSelection ? 
							   N("The following packages are going to be installed") :
							   N("The following packages are going to be removed"),
							       formatList(20, sort(map { $_->name } @l)) ], 1) or $error = ''; #- defined
				}
				if (defined $error) {
				    $o->ask_warn('', $error) if $error;
				    #- disable selection (or unselection).
				    $isSelection ? $packages->disable_selected($packages->{rpmdb}, $state, @l) :
				                   $packages->resolve_requested($packages->{rpmdb}, $state, { map { $_->id => 1 } @l });
				} else {
				    #- keep the changes, update visible state.
				    foreach (@l) {
					$set_state->($_->name, $_->flag_selected ? 'selected' : 'unselected');
				    }
				}
			    },
			    grep_allowed_to_toggle => sub {
				grep { my $p = pkgs::packageByName($packages, $_); $p && !$p->flag_base } @_;
			    },
			    grep_unselected => sub {
				grep { !pkgs::packageByName($packages, $_)->flag_selected } @_;
			    },
			    check_interactive_to_toggle => sub {
				my $p = pkgs::packageByName($packages, $_[0]) or return;
				if ($p->flag_base) {
				    $o->ask_warn('', N("This is a mandatory package, it can not be unselected"));
				} elsif ($p->flag_installed && !$p->flag_upgrade) {
				    $o->ask_warn('', N("You can not unselect this package. It is already installed"));
				} elsif ($p->flag_selected && $p->flag_installed) {
				    if ($::expert) {
					$o->ask_yesorno('', N("This package must be upgraded.\nAre you sure you want to deselect it?")) or return;
					return 1;
				    } else {
					$o->ask_warn('', N("You can not unselect this package. It must be upgraded"));
				    }
				} else { return 1 }
				return;
			    },
			    auto_deps => N("Show automatically selected packages"),
			    interactive_help_id => 'choosePackagesTree',
			    ok => N("Install"),
			    cancel => N("Previous"),
			    icons => [ { icon         => 'floppy',
					 help         => N("Load/Save on floppy"),
					 wait_message => N("Updating package selection"),
					 code         => sub { $o->loadSavePackagesOnFloppy($packages); 1 },
				       }, 
				       if_(0, 
				       { icon         => 'feather',
					 help         => N("Minimal install"),
					 code         => sub {
					     
					     install_any::unselectMostPackages($o);
					     pkgs::setSelectedFromCompssList($packages, { SYSTEM => 1 }, 4, $availableCorrected);
					     1;
					 } }),
				     ],
			    state => {
				      auto_deps => 1,
				      flat      => $o_limit_medium,
				     },
			  };

    $o->ask_browse_tree_info('', N("Choose the packages you want to install"), $common);
}

#------------------------------------------------------------------------------
sub beforeInstallPackages {
    my ($o) = @_;    
    $o->SUPER::beforeInstallPackages;
    install_any::copy_advertising($o);
}

#------------------------------------------------------------------------------
sub installPackages {
    my ($o, $packages) = @_;

    my ($current_total_size, $last_size, $nb, $total_size, $start_time, $last_dtime, $_trans_progress_total);

    my $w = ugtk2->new(N("Installing"));
    $w->sync;
    my $text = gtknew('Label');
    my ($advertising, $change_time, $i);
    my $show_advertising if 0;
    $show_advertising = to_bool(@install_any::advertising_images) if !defined $show_advertising;

    my ($msg, $msg_time_remaining) = map { gtknew('Label', text => $_) } '', N("Estimating");
    my ($progress, $progress_total) = map { Gtk2::ProgressBar->new } (1..2);
    ugtk2::gtkadd($w->{window}, my $box = gtknew('VBox', spacing => 10));

    my $advertize = sub {
	my ($update) = @_;
	@install_any::advertising_images or return;
	foreach ($msg, $progress, $text) {
	    $show_advertising ? $_->hide : $_->show;
	}

	gtkdestroy($advertising) if $advertising;
	if ($show_advertising && $update) {
	    $change_time = time();
	    my $f = $install_any::advertising_images[$i++ % @install_any::advertising_images];
	    log::l("advertising $f");
	    my $pl = $f; $pl =~ s/\.png$/.pl/;
	    my $icon_name = $f; $icon_name =~ s/\.png$/_icon.png/;
	    my ($draw_text, $width, $height, $border, $y_start, @text);
	    -e $pl and $draw_text = 1;
	    eval(cat_($pl)) if $draw_text;
	    my $pix = gtkcreate_pixbuf($f);
	    my $darea = gtknew('DrawingArea');
	    gtkpack($box, $advertising = !$draw_text ?
		    gtkcreate_img($f) :
		    gtkset($darea, width => $width, height => $height, expose_event => sub {
			       my (undef, undef, $dx, $dy) = $darea->allocation->values;
				   $darea->window->draw_rectangle($darea->style->bg_gc('active'), 1, 0, 0, $dx, $dy);
				   $pix->render_to_drawable($darea->window, $darea->style->bg_gc('normal'), 0, 0,
							    ($dx-$width)/2, 0, $width, $height, 'none', 0, 0);

                                   my @lines = wrap_paragraph([ @text ], $darea, $border, $width);
                                   foreach my $line (@lines) {
                                       my $layout = $darea->create_pango_layout($line->{text});
                                       my $draw_lay = sub {
                                           my ($gc, $decx) = @_;
                                           $darea->window->draw_layout($gc, $line->{'x'} + $decx, $y_start + $line->{'y'}, $layout);
                                       };
                                       $draw_lay->($darea->style->black_gc, 0);
                                       $line->{options}{bold} and $draw_lay->($darea->style->black_gc, 1);
                                   }
			   }));
	} else {
	    $advertising = undef;
	}
    };

    my $cancel = gtknew('Button', text => N("Cancel"), clicked => sub { $pkgs::cancel_install = 1 });
    my $details = gtknew('Button', text_ref => \$show_advertising, 
			 format => sub { $show_advertising ? N("Details") : N("No details") },
			 clicked => sub {
			     gtkval_modify(\$show_advertising, !$show_advertising);
			     $advertize->('update');
			 });

    $box->pack_end(gtkshow(gtknew('VBox', spacing => 5, children_loose => [
			   $msg, $progress,
			   gtknew('Table', children => [ [ N("Time remaining "), $msg_time_remaining ] ]),
			   $text,
			   $progress_total,
			   gtknew('HButtonBox', children_loose => [ $cancel, $details ]),
			  ])), 0, 1, 0);
    $details->hide if !@install_any::advertising_images;
    $w->sync;
    gtkset($msg, text => N("Please wait, preparing installation..."));
    foreach ($cancel, $details) {
	gtkset_mousecursor_normal($_->window);
    }

    $advertize->(0);

    my $oldInstallCallback = \&pkgs::installCallback;
    local *pkgs::installCallback = sub {
	my ($data, $type, $id, $subtype, $amount, $total) = @_;
	if ($type eq 'user' && $subtype eq 'install') {
	    #- $amount and $total are used to return number of package and total size.
	    $nb = $amount;
	    $total_size = $total; $current_total_size = 0;
	    $start_time = time();
	    gtkset($msg, text => N("%d packages", $nb));
	    $w->flush;
	} elsif ($type eq 'inst' && $subtype eq 'start') {
	    $progress->set_fraction(0);
	    my $p = $data->{depslist}[$id];
	    gtkset($msg, text => N("Installing package %s", $p->name));
	    $current_total_size += $last_size;
	    $last_size = $p->size;
	    gtkset($text, text => (split /\n/, c::from_utf8($p->summary))[0] || '');
	    $advertize->(1) if $show_advertising && $total_size > 20_000_000 && time() - $change_time > 20;
	    $w->flush;
	} elsif ($type eq 'inst' && $subtype eq 'progress') {
	    $progress->set_fraction($total ? $amount / $total : 0);

	    my $dtime = time() - $start_time;
	    my $ratio = 
	      $total_size == 0 ? 0 :
		pkgs::size2time($current_total_size + $amount, $total_size) / pkgs::size2time($total_size, $total_size);
	    $ratio >= 1 and $ratio = 1;
	    my $total_time = $ratio ? $dtime / $ratio : time();

	    $progress_total->set_fraction($ratio);
	    if ($dtime != $last_dtime && $current_total_size > 80_000_000) {
		gtkset($msg_time_remaining, text => formatTime(10 * round(max($total_time - $dtime, 0) / 10) + 10));
		$last_dtime = $dtime;
	    }
	    $w->flush;
	} else { goto $oldInstallCallback }
    };
    #- the modification is not local as the box should be living for other package installation.
    undef *install_any::changeMedium;
    *install_any::changeMedium = sub {
	my ($method, $medium) = @_;

	#- if not using a cdrom medium or an iso image, always abort.
	return if !install_any::method_allows_medium_change($method);

	my $name = pkgs::mediumDescr($o->{packages}, $medium);
	local $| = 1; print "\a";
	my $time = time();
	my $r = $name !~ /commercial/i || ($o->{useless_thing_accepted2} ||= $o->ask_from_list_('', formatAlaTeX(install_messages::com_license()), [ N_("Accept"), N_("Refuse") ], "Accept") eq "Accept");
	if ($method =~ /-iso$/) {
	    $r = install_any::changeIso($name);
	} else {
	    $r &&= $o->ask_okcancel('', N("Change your Cd-Rom!
Please insert the Cd-Rom labelled \"%s\" in your drive and press Ok when done.
If you do not have it, press Cancel to avoid installation from this Cd-Rom.", $name), 1);
	}
	#- add the elapsed time (otherwise the predicted time will be rubbish)
	$start_time += time() - $time;
	return $r;
    };
    my $install_result;
    catch_cdie { $install_result = $o->install_steps::installPackages($packages) }
      sub {
	  log::l("catch_cdie: $@");
          my $time = time();
	  if ($@ =~ /^error ordering package list: (.*)/) {
	      $o->ask_yesorno('', [
N("There was an error ordering packages:"), $1, N("Go on anyway?") ], 1) and return 1;
	      ${$_[0]} = "already displayed";
	  } elsif ($@ =~ /^error installing package list: (.*)/) {
	      $o->ask_yesorno('', [
N("There was an error installing packages:"), $1, N("Go on anyway?") ], 1) and return 1;
	      ${$_[0]} = "already displayed";
	  }
	  $w->destroy;
          #- add the elapsed time (otherwise the predicted time will be rubbish)
          $start_time += time() - $time;
	  0;
      };
    if ($pkgs::cancel_install) {
	$pkgs::cancel_install = 0;
	die 'already displayed';
    }
    $w->destroy;
    $install_result;
}

sub summary_prompt {
    my ($o, $l, $check_complete) = @_;

    my $w = ugtk2->new('');

    my $set_entry_labels;
    my @table;
    my $group;
    foreach my $e (@$l) {
	if ($group ne $e->{group}) {
	    $group = $e->{group};
	    push @table, [ gtknew('HBox', children_tight => [ $group ]), '' ];
	}
	$e->{widget} = gtknew('WrappedLabel', width => $::real_windowwidth * 0.72);

	push @table, [], [ gtknew('HBox', spacing => 30, children_tight => [ '', $e->{widget} ]),
			   gtknew('Button', text => N("Configure"), clicked => sub { 
						 $w->{rwindow}->hide;
						 $e->{clicked}(); 
						 $w->{rwindow}->show;
						 $set_entry_labels->();
					     }) ];
    }

    $set_entry_labels = sub {
	foreach (@$l) {
	    my $t = $_->{val}() || '<span foreground="red">' . N("not configured") . '</span>';
	    $t =~ s/&/&amp;/g;
	    gtkset($_->{widget}, text_markup => $_->{label} . ' - ' . $t);
	}
    };
    $set_entry_labels->();

    my $help_sub = $o->interactive_help_sub_display_id('summary');

    ugtk2::gtkadd($w->{window},
	   gtknew('VBox', spacing => 5, children => [
		    1, gtknew('ScrolledWindow', child => gtknew('Table', mcc => 1, children => \@table)),
		    0, $w->create_okcancel(undef, '', '', if_($help_sub, [ N("Help"), $help_sub, 1 ]))
		  ]));

    $w->main($check_complete);
}

1;