summaryrefslogtreecommitdiffstats
path: root/control-center
diff options
context:
space:
mode:
Diffstat (limited to 'control-center')
-rwxr-xr-xcontrol-center1555
1 files changed, 1555 insertions, 0 deletions
diff --git a/control-center b/control-center
new file mode 100755
index 00000000..c5eb5499
--- /dev/null
+++ b/control-center
@@ -0,0 +1,1555 @@
+#!/usr/bin/perl
+# $Id: control-center 269021 2010-05-19 16:37:57Z eugeni $
+
+# Copyright (C) 1999-2008 Mandriva
+# Daouda Lo
+# Damien Krotkine
+# Thierry Vignaud <tvignaud@mandriva.com>
+# Yves Duret
+#
+# This program is free software; you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free Software
+# Foundation; either version 2, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+
+use strict;
+use diagnostics;
+use lib qw(/usr/lib/libDrakX);
+use c;
+use standalone;
+use common;
+use detect_devices;
+use lang;
+
+# i18n: IMPORTANT: to get correct namespace (drakconf instead of libDrakX)
+BEGIN { unshift @::textdomains, 'drakconf' }
+use mygtk2 qw(gtknew);
+use ugtk2 qw(:create :dialogs :helpers :wrappers);
+use Gtk2::WebKit;
+
+use MDV::Control_Center;
+
+
+my (%tool_pids, %tool_feedback, $gurpmi_pid);
+
+my ($conffile, $class_install) = ('/etc/mcc.conf', '/etc/sysconfig/system');
+
+my ($rootwin_width, $rootwin_height) = gtkroot()->get_size;
+my $default_width = $rootwin_width <= 800 ? 720 : 800;
+my $default_height = $rootwin_height <= 480 ? 420 : $rootwin_height <= 600 ? 523 : 600;
+
+my $min_width = $rootwin_width == 640 ? 620 : 680;
+my $min_height = $rootwin_height == 480 ? 420 : 500;
+
+require_root_capability() if !$::testing; # just to get root capabilities
+
+
+#-------------------------------------------------------------
+# read configuration, set themes, ...
+my %h = getVarsFromSh($conffile);
+my %class = getVarsFromSh($class_install);
+$h{THEME} ||= 'default';
+$h{LOGS} ||= bool2text($class{CLASS} eq 'expert' ? 1 : 0);
+$h{EXPERT_WIZARD} ||= 0;
+$h{HEIGTH} ||= $default_height;
+$h{WIDTH} ||= $default_width;
+
+my %option_values;
+$option_values{show_log} = text2bool($h{LOGS});
+my $theme = $h{THEME};
+my $program;
+my ($i, $geometry, $save_html);
+foreach (@ARGV) {
+ $i++;
+ $theme = $1 if /--theme (\w+)/;
+ $program = $1 if /--start-with=(.*)/;
+ if (/^--geometry$/) {
+ $geometry = splice @ARGV, $i, 1;
+ last;
+ }
+ $save_html = 1 if /--save-html-pages/;
+}
+
+-d "$themes_dir/$theme" or $theme = 'default';
+add_icon_path("$themes_dir/$theme/");
+add_icon_path("$themes_dir/default") if $theme ne 'default'; # fall back if theme miss some icons
+
+mygtk2::import_style_ressources();
+my $rc = find { -r $_ } ("$themes_dir/$theme/gtkrc", if_($theme ne 'default', "$themes_dir/default/gtkrc"));
+Gtk2::Rc->parse($rc) if -r $rc;
+
+my $branding = N("Mageia");
+my $product_id = common::parse_LDAP_namespace_structure(cat_('/etc/product.id'));
+# allow OEM branding:
+$branding = translate($product_id->{distribution});
+
+
+#-------------------------------------------------------------
+# Splash window: please wait ...
+my $window_splash = Gtk2::Window->new('popup');
+$window_splash->signal_connect(delete_event => \&quit_global);
+$window_splash->set_title(N("%s Control Center", $branding));
+$window_splash->set_position('center_always');
+$window_splash->add(gtknew('Fixed', widget_name => 'Steps',
+ children => [
+ [ gtknew('Image_using_pixbuf', file => 'splash_screen'), 0, 0 ],
+ [ gtknew('Label', text => N("%s Control Center", $branding)), 21, 60 ],
+ [ gtknew('Label', text => N("Loading... Please wait")), 21, 175 ],
+ ]),
+ );
+$window_splash->show_all;
+gtkflush();
+
+
+#-------------------------------------------------------------
+# Data structures
+my $more_wizard_dir = "/etc/wizard.d/";
+
+my $isWiz = -e "/usr/sbin/drakwizard";
+my $isRpmDrake = -e "/usr/sbin/rpmdrake";
+my $isParkRpmDrake = -e "/usr/sbin/park-rpmdrake";
+my $isWebAdmin = -e "/usr/bin/mdkwebadmin";
+my $isRfbDrake = -e "/usr/bin/rfbdrake";
+my $isDrakStats = -e "/usr/sbin/drakstats";
+
+my $application_driven_menu;
+
+sub is_wizard_installed { -f top(glob("/usr/lib/perl5/vendor_perl/*/MDK/Wizard/$_[0]")) }
+
+my $is_auth_wizard_installed = is_wizard_installed('Nisautofs.pm');
+
+
+sub wizard_format {
+ map {
+ my ($id, $wizard, $icon, $description, $long_description, $file) = @$_;
+ $programs{$id} =
+ {
+ binary => "$sbindir/drakwizard $wizard",
+ embedded => 1,
+ description => $description,
+ long_description => $long_description,
+ icon => $icon,
+ };
+ if_(is_wizard_installed($file), $id);
+ } @_;
+}
+
+# [ [ class_label, class icon name, [ program_label, ... ] ]
+my @tree = (
+ if_($isRpmDrake || $isParkRpmDrake,
+ [
+ #-PO: please keep the following message very short: it must fit in the left list of MCC!!!
+ N("Software Management"), 'software', 'software-management',
+ [
+ if_($isRpmDrake,
+ {
+ title => N("Software Management"),
+ list => [
+ "Install Software",
+ "Mageia Update",
+ if_(0, "Mageia Online"),
+ "Updates Configuration",
+ "Software Media Manager",
+ ]
+ },
+ ),
+ {
+ title => N("Others"),
+ list => [
+ if_($isParkRpmDrake, "Manage park"),
+ if_($isDrakStats, "Package stats"),
+ ]
+ },
+ ]
+ ]
+ ),
+
+ if_(0, [ N("Server wizards"), 'wizard-mdk' ]),
+ [
+ #-PO: please keep the following message very short: it must fit in the left list of MCC!!!
+ N("Sharing"), 'file-sharing-mdk', 'wiz-client',
+ [
+ {
+ title => N("Sharing"),
+ list => [
+ (wizard_format( # [ id, wizard file name, icon, description ]
+ [ "FTP wizard", "proftpd", 'ftp-mdk', N("Configure FTP"),
+ N("Set up an FTP server"), 'Proftpd.pm',
+ ],
+ [ "Samba wizard", "samba", 'samba_server-mdk', N("Configure Samba"),
+ N("Set up a file and print server for workstations running Linux and non-Linux systems"), 'Samba.pm',
+ ],
+ [ "Manage Samba share", "sambashare", 'wizard-mdk', N("Manage Samba share"),
+ N("Manage, create special share, create public/user share"), 'Sambashare.pm', 1,
+ ],
+ [ "Web wizard", "apache2", 'web_server-mdk', N("Configure web server"),
+ N("Set up a web server"), 'Apache.pm',
+ ],
+ [ "Installation server wizard", "installsrv", 'wizard-mdk', N("Configure installation server"),
+ N("Set up server for network installations of %s", $branding), 'Installsrv.pm', 1,
+ ],
+ ),
+ ),
+ ]
+ },
+ ]
+ ],
+ [
+ #-PO: please keep the following message very short: it must fit in the left list of MCC!!!
+ N("Network Services"), 'network-services-mdk', 'mcc-network',
+ [
+ {
+ title => N("Network Services"),
+ list => [
+ (wizard_format( # [ id, wizard file name, icon, description ]
+ [ "DHCP wizard", "dhcp", 'dhcp_server-mdk', N("Configure DHCP"),
+ N("Set up a DHCP server"), 'Dhcp.pm',
+ ],
+ [ "DNS wizard", "bind", 'dns_server-mdk', N("Configure DNS"),
+ N("Set up a DNS server (network name resolution)"), 'Bind.pm',
+ ],
+ [ "Squid wizard", "squid", 'drakproxy-mdk', N("Configure proxy"),
+ N("Configure a web caching proxy server"), 'Squid.pm',
+ ],
+ [ "Time wizard", "ntp", 'ntp_server-mdk', N("Configure time"),
+ N("Set the time of the server to be synchronized with an external time server"), 'Ntp.pm',
+ ],
+ [ "SSHD wizard", "sshd", 'wizard-sshd', N("OpenSSH daemon configuration"),
+ N("OpenSSH daemon configuration"), 'Sshd.pm',
+ ],
+ ),
+ ),
+ ]
+ },
+ ]
+ ],
+
+ [
+ #-PO: please keep the following message very short: it must fit in the left list of MCC!!!
+ N("Authentication"), 'drakauth-mdk', '',
+ [
+ {
+ title => N("Authentication"),
+ list => [
+ if_($is_auth_wizard_installed, "Authentication"),
+ (wizard_format( # [ id, wizard file name, icon, description ]
+ [ 'Nis+autofs wizard', "nisautofs", 'nisautofs', N("Configure NIS and Autofs"),
+ N("Configure the NIS and Autofs services"), 'Nisautofs.pm',
+ ],
+ [ "LDAP wizard", "ldap", "ldap-mdk", N("Configure LDAP"),
+ N("Configure the LDAP directory services"), 'Ldap.pm',
+ ],
+ ),
+ ),
+ ]
+ },
+ ]
+ ],
+
+ [
+ #-PO: please keep the following message very short: it must fit in the left list of MCC!!!
+ N("Groupware"), 'groupware-mdk', '',
+ [
+ {
+ title => N("Groupware"),
+ list => [
+ (wizard_format( # [ id, wizard file name, icon, description ]
+ if_(0, [ "News wizard", "inn", 'news-mdk', N("Configure news"),
+ N("Configure a newsgroup server"), 'Inn.pm',
+ ],
+ [ "Kolab wizard", "kolab", "kolab-mdk", N("Configure groupware"),
+ N("Configure a groupware server"), 'Kolab.pm',
+ ]),
+ [ "Postfix wizard", "postfix", 'postfix-mdk', N("Configure mail"),
+ N("Configure the Internet Mail services"), 'Postfix.pm'
+ ],
+ ),
+ ),
+ ]
+ },
+ ]
+ ],
+
+ if_($isWebAdmin || $isRfbDrake,
+ [
+ #-PO: please keep the following message very short: it must fit in the left list of MCC!!!
+ N("Online Administration"), 'online-administration-mdk', '',
+ [
+ {
+ title => N("Online Administration"),
+ list => [
+ if_($isWebAdmin,
+ (map {
+ my ($id, $icon, $op, $description, $long_description) = @$_;
+ $programs{$id} =
+ {
+ binary => "$bindir/mdkwebadmin.pl $op",
+ embedded => -1, # too big
+ description => $description,
+ long_description => $long_description,
+ icon => $icon,
+ };
+
+ $id;
+ } ( # [ id, wizard file name, icon, description ]
+ [ "Local Admin", 'local-administration-mdk', '--direct', N("Local administration"),
+ (-e "/usr/bin/webmin" ? N("Configure the local machine via web interface") : N("You don't seem to have webmin installed. Local config is disabled"))
+ ],
+ [ "Remote Admin", 'remote-administration-mdk', '--link', N("Remote administration"),
+ N("Click here if you want to configure a remote box via Web interface"),
+ ])
+ )
+ ),
+ if_($isRfbDrake,
+ "Remote Control",
+ )
+ ]
+ },
+ ]
+ ]),
+
+ [
+ #-PO: please keep the following message very short: it must fit in the left list of MCC!!!
+ N("Hardware"), 'drakhard-mdk', 'mcc-hardware',
+ [
+ {
+ title => N("Manage your hardware"),
+ list => [
+ "Hardware List",
+ "Sound",
+ ]
+ },
+ {
+ title => N("Configure graphics"),
+ list => [
+ "3D",
+ "Graphical server configuration",
+ ]
+ },
+ {
+ title => N("Configure mouse and keyboard"),
+ list => [
+ "Keyboard",
+ "Mouse",
+ ]
+ },
+ {
+ title => N("Configure printing and scanning"),
+ list => [
+ "Printer",
+ "Scanner",
+ if_(-x "$bindir/drakfax", "Fax"),
+ ]
+ },
+ {
+ title => N("Others"),
+ list => [
+ "UPS",
+ ]
+ },
+ ]
+ ],
+
+ [
+ #-PO: please keep the following message very short: it must fit in the left list of MCC!!!
+ N("Network & Internet"), 'net-mdk', 'mcc-network',
+ [
+ {
+ title => N("Manage your network devices"),
+ list => [
+ "Network Center",
+ "Add Connection",
+ if_(!-x "$sbindir/draknetcenter",
+ "Configure Internet",
+ "Manage Connection",
+ "Monitor Connection",
+ ),
+ "Remove Interface",
+ ]
+ },
+ {
+ title => N("Personalize and Secure your network"),
+ list => [
+ "Proxy Configuration",
+ "Connection Sharing",
+ "Network Profiles",
+ "VPN",
+ ]
+ },
+ {
+ title => N("Others"),
+ list => [
+ "Hosts",
+ ]
+ },
+ ],
+ ],
+
+ [
+ #-PO: please keep the following message very short: it must fit in the left list of MCC!!!
+ N("System"), 'system-mdk', 'mcc-system',
+ [
+ {
+ title => N("Manage system services"),
+ list => [
+ if_(!$is_auth_wizard_installed, "Authentication"),
+ "Menus",
+ "Services",
+ "Fonts",
+ ]
+ },
+ {
+ title => N("Localization"),
+ list => [
+ "Date & Time",
+ "Localization",
+ ]
+ },
+ {
+ title => N("Administration tools"),
+ list => [
+ "Logs",
+ if_($ENV{LANGUAGE} !~ /^zh/, "Console"),
+ "Users",
+ "Migration",
+ if_(-x "$xbindir/drakcronat", "Programs scheduling"),
+ "Backups",
+ 'Snapshots',
+ "Virtualization",
+ ]
+ },
+ ]
+ ],
+
+ [
+ #-PO: please keep the following message very short: it must fit in the left list of MCC!!!
+ N("Network Sharing"), 'network-sharing-mdk', '',
+ [
+ {
+ title => N("Configure Windows(R) shares"),
+ list => [
+ "Access Windows shares",
+ "Samba configuration",
+ ]
+ },
+ {
+ title => N("Configure NFS shares"),
+ list => [
+ "NFS mount points",
+ "NFS exports",
+ ]
+ },
+ {
+ title => N("Configure WebDAV shares"),
+ list => [
+ "WebDAV mount points",
+ ]
+ },
+ ],
+ ],
+
+ [
+ #-PO: please keep the following message very short: it must fit in the left list of MCC!!!
+ N("Local disks"), 'partition-mdk', 'mcc-localdisks',
+ [
+ {
+ title => N("Local disks"),
+ list => [
+ "Hard Drives",
+ (map {
+ my ($type, $scan, $text_orig, $long_text) = @$_;
+ map_index {
+ my $text = sprintf(translate($text_orig), $_->{info});
+ my $full_name = $text . ($::i ? $::i + 1 : '');
+ $programs{$full_name} =
+ {
+ binary => "$sbindir/diskdrake --removable=$_->{device}",
+ embedded => 1,
+ description => $text,
+ long_description => sprintf(translate($long_text), $_->{info}),
+ icon => "diskdrake_$type",
+ };
+ $full_name;
+ } $scan->();
+ } do {
+ my %cdroms_by_type;
+ foreach (detect_devices::cdroms()) {
+ my $type = detect_devices::isBurner($_) ? 'burner' : detect_devices::isDvdDrive($_) ? 'DVD' : 'cdrom';
+ push @{$cdroms_by_type{$type}}, $_;
+ }
+ ([ 'cdrom', sub { @{$cdroms_by_type{cdrom} || []} }, N_("CD-ROM (%s)",),
+ N_("Set where your \"%s\" CD-ROM drive is mounted"),
+ ],
+ [ 'dvd', sub { @{$cdroms_by_type{DVD} || []} }, N_("DVD-ROM (%s)"),
+ N_("Set where your \"%s\" DVD-ROM drive is mounted"),
+ ],
+ [ 'cdwriter', sub { @{$cdroms_by_type{burner} || []} }, N_("CD/DVD burner (%s)"),
+ N_("Set where your \"%s\" CD/DVD burner is mounted"),
+ ],
+ [ 'zip', \&detect_devices::zips, N_("ZIP drive"),
+ N_("Set where your ZIP drive is mounted"),
+ ],
+ );
+ }),
+ "Partition Sharing",
+ ]
+ },
+ ]
+ ],
+
+ [
+ #-PO: please keep the following message very short: it must fit in the left list of MCC!!!
+ N("Security"), 'security-mdk', 'mcc-security',
+ [
+ {
+ title => N("Security"),
+ list => [
+ "Security Level",
+ "Tomoyo Policy",
+ "Firewall",
+ "Mageia Tools Authentication",
+ "Invictus Firewall",
+ "Parental Controls",
+ ]
+ },
+ ]
+ ],
+
+ [
+ #-PO: please keep the following message very short: it must fit in the left list of MCC!!!
+ N("Boot"), 'drakboot-mdk', 'mcc-boot',
+ [
+ {
+ title => N("Configure boot steps"),
+ list => [
+ #if_(detect_devices::floppies, "Boot Disk"), # kernel is too big
+ "Auto login Config",
+ "Boot Config",
+ "Display Manager chooser",
+ ]
+ },
+ {
+ title => N("Boot look'n feel"),
+ list => [
+ #"Boot Theme",
+ ]
+ },
+ {
+ title => N("Others"),
+ list => [
+ if_(0, "Auto Install"),
+ ]
+ },
+ ]
+ ],
+);
+
+if (scalar glob_("$more_wizard_dir/*.conf")) {
+ my @leaf = (
+ N("Additional wizards"),
+ 'wizard-mdk',
+ []
+ );
+
+ foreach my $file (glob_("$more_wizard_dir/*.conf")) {
+ next unless -f $file;
+ my %tmp = getVarsFromSh($file);
+ $programs{$tmp{NAME}} = {
+ binary => "$sbindir/drakwizard " . lc($file),
+ embedded => 1,
+ description => $tmp{DESCRIPTION},
+ icon => $tmp{ICON} || 'wizard-mdk',
+ long_description => $tmp{LONG_DESCRIPTION},
+ };
+ push(@{$leaf[2]}, $tmp{NAME});
+ }
+ push(@tree, \@leaf);
+}
+
+#-------------------------------------------------------------
+# let build the GUI
+
+
+my $align = mygtk2::text_direction_rtl() ? "right" : "left";
+my $align2 = mygtk2::text_direction_rtl() ? "right" : "left";
+
+
+# main window :
+
+my ($timeout, %check_boxes, $emb_socket);
+
+# set default size:
+
+my $window_global = gtkset_size_request(Gtk2::Window->new('toplevel'), $min_width, $min_height);
+$::main_window = $window_global;
+
+if ($geometry) {
+ @h{qw(HEIGTH WIDTH)} = $geometry =~ /(\d+)x(\d+)/;
+ my ($x, $y) = $geometry =~ /([+-]\d+)([+-]\d+)/;
+ $window_global->set_uposition($x, $y) if $x || $y;
+} else {
+}
+$window_global->resize(max($default_width, $h{WIDTH}, $min_width), max($h{HEIGTH}, $default_height, $min_height));
+
+$window_global->set_icon(gtkcreate_pixbuf("/usr/share/icons/drakconf.png"));
+
+my $pending_app = 0;
+
+my $help_on_context = 'drakconf-intro';
+
+my @themes = grep { -d "$themes_dir/$_" } all($themes_dir);
+
+#-PO Translators, please keep all "/" charaters !!!
+my %options = (
+ 'show_log' => [ N("/_Options"), N("/Display _Logs") ],
+ 'embedded_mode' => [ N("/_Options"), N("/_Embedded Mode") ],
+ 'wiz_expert' => [ N("/_Options"), N("/Expert mode in _wizards") ],
+);
+
+my $mga_rel = common::mageia_release();
+
+my ($steps, $view);
+
+my $release = mageia_release_info();
+
+my @menu_items = (
+ [ N("/_File"), undef, undef, undef, '<Branch>' ],
+ [ N("/_File") . N("/_Quit"), N("<control>Q"), \&quit_global, undef, '<Item>', N("Quit") ],
+ [ N("/_Options"), undef, undef, undef, '<Branch>' ],
+ [ join('', @{$options{show_log}}), undef,
+ sub {
+ $option_values{show_log} = $check_boxes{show_log}->get_active;
+ if ($option_values{show_log}) {
+ start_logdrake();
+ } else {
+ kill_logdrake();
+ }
+ },
+ undef, '<CheckItem>'
+ ],
+
+ if_(0 && $isWiz,
+ [ join('', @{$options{wiz_expert}}), undef,
+ sub { $option_values{expert_wizard} = $check_boxes{wiz_expert}->get_active },
+ undef, '<CheckItem>',
+ ],
+ ),
+ if_(@themes > 1,
+ [ N("/_Themes"), undef, undef, undef, '<Branch>' ],
+ (map {
+ my $name = $_;
+ [ N("/_Themes") . "/" . ($name eq $theme ? " O " : " ") . "_$_", undef,
+ sub {
+ return if $theme eq $name;
+ !$pending_app || splash_warning(N("This action will restart the control center.\nAny change not applied will be lost."), 1) and do {
+ # embedded app must be killed
+ kill_children();
+ kill_logdrake();
+ child_just_exited();
+ exec "$0 --theme $name";
+ };
+ }, undef, '<CheckItem>'
+ ];
+ } @themes),
+ [ N("/_Themes") . N("/_More themes"), undef, \&more_themes, undef, '<Item>' ]
+ ),
+ [ N("/_Help"), undef, undef, undef, '<Branch>' ],
+ [ N("/_Help") . N("/_Help"), undef, \&run_help, undef, '<Item>', N("Help") ],
+ [ N("/_Help") . N("/_Release notes"), undef, sub { run_browser('Notes') }, undef, '<Item>', N("Help") ],
+ [ N("/_Help") . N("/What's _New?"), undef, sub { run_browser("What's New?") }, undef, '<Item>', N("Help") ],
+ [ N("/_Help") . N("/_Errata"), undef, sub { run_browser('Errata') }, undef, '<Item>', N("Help") ],
+ [ N("/_Help") . N("/_Report Bug"), undef, sub {
+ run_program::raw({ detach => 1, as_user => 1 }, 'drakbug', '--report', (split(/\s/, $pending_app))[0] || 'drakconf');
+ }, undef, '<Item>' ],
+ [ N("/_Help") . N("/_About..."), undef, \&about_mga_cc, undef, '<Item>' ]
+ );
+
+
+sub run_help() {
+ run_program::raw({ detach => 1, as_user => 1 }, 'drakhelp', '--id', $help_on_context);
+}
+
+sub run_browser {
+ my ($url) = @_;
+ # Enable back $url when we will have our first release and our first release wiki page
+ #$url = "http://wiki.mageia.org/en/$release->{version}_$url" if $url !~ m!^http://!;
+ $url = "http://www.mageia.org/" if $url !~ m!^http://!;
+ run_program::raw({ detach => 1, as_user => 1 }, '/usr/bin/www-browser', $url);
+}
+
+my ($menu, $factory) = create_factory_menu($window_global, @menu_items);
+
+# to retrieve a path, one must prevent "accelerators completion":
+sub get_path { join('', map { my $i = $_; $i =~ s/_//g; $i } @_) }
+
+%check_boxes = map {
+ $_ => $factory->get_widget("<main>" . get_path(@{$options{$_}}));
+} ('show_log', if_(0 && $isWiz, "wiz_expert"));
+
+my @buttons;
+my $offset = 15;
+
+$view = gtknew('WebKit_View', no_popup_menu => 1);
+# so that it exists when building steps:
+my $banner_notebook = Gtk2::Notebook->new;
+build_list();
+
+gtkadd($window_global,
+ gtkpack_(Gtk2::VBox->new(0, 0),
+ 0, $menu,
+ #0, $banner_notebook,
+ 0, Gtk2::HSeparator->new,
+ # 0, gtkset_size_request(Gtk2::VBox->new(10, 10), -1, 2),
+ 1, gtkpack_(Gtk2::HBox->new(0, 0),
+ 1, $steps = gtknew('MDV_Notebook', parent_window => $window_global, children => [ #Layout Fixed
+ # 145 is the vertical offset in order to be below the actual logo:
+ [ gtknew('VBox', widget_name => 'Steps', spacing => 0, width => (192 - $offset),
+ children_tight => [ map {
+ gtknew('HBox', spacing => 0, children => [
+ 1, $_,
+ 0, gtknew('Alignment', width => 12),
+ ]);
+ } @buttons ]), 0, 100 ],
+ ], right_child => gtknew('ScrolledWindow', child => gtkset_border_width($view, 5),
+ no_shadow => 1, h_policy => 'never')),
+ 1, gtkpack(my $emb_box = Gtk2::VBox->new(0, 0),
+ my $wait_darea = gtkset_size_request(Gtk2::DrawingArea->new, -1, -1),
+ ),
+ ),
+ 0, Gtk2::HSeparator->new,
+ 0, my $buttons = gtkadd(gtkset_layout(Gtk2::HButtonBox->new, 'start'),
+ map { gtkset_border_width($_, 3) }
+ gtksignal_connect(my $cancel = Gtk2::Button->new(N("Cancel")),
+ clicked => sub {
+ stop_wait_area();
+ kill_children();
+ child_just_exited();
+ }),
+ ),
+ )
+ );
+
+$view->set_size_request(-1, -1);
+
+$window_global->signal_connect(delete_event => \&quit_global);
+
+my $accel = Gtk2::AccelGroup->new;
+$accel->connect(Gtk2::Gdk->keyval_from_name('F1'), [], ['visible'], \&run_help);
+$window_global->add_accel_group($accel);
+
+use POSIX qw(:sys_utsname_h :math_h :sys_wait_h :unistd_h);
+my (undef, $nodename) = POSIX::uname();
+$window_global->set_title(N("%s Control Center %s [on %s]", $branding, $version, $nodename));
+$window_global->set_position('center');
+
+foreach my $notebook ($banner_notebook) {
+ $notebook->set_property('show-border', 0);
+ $notebook->set_property('show-tabs', 0);
+}
+
+
+# banner :
+
+#add2notebook($banner_notebook, "", Gtk2::Banner->new("/usr/share/icons/large/drakconf.png",
+# N("Welcome to the %s Control Center", $branding)));
+
+
+my ($_hand_cursor, $wait_cursor) = map { Gtk2::Gdk::Cursor->new($_) } qw(hand2 watch);
+
+my $left_locked = 0;
+
+#my $spacing = 25;
+
+my %tool_callbacks;
+
+my ($page_count);
+
+
+my $conf_file = '/etc/sysconfig/mcc.conf';
+foreach (cat_($conf_file)) {
+ #s/^ENABLE_//;
+ #my ($key, $val) = /^(.*)=(.*)/;
+ if (my ($key, $val) = /^ENABLE_(.*)=(.*)/) {
+ $key =~ s/_/ /g;
+ #warn "--> ($key, $val)\n";
+ $programs{$key}{disabled} = 1 if $val ne 'yes';
+ warn ">> disabling $key\n" if $val ne 'yes';
+ } else {
+ warn "bogus line in $conf_file: $_\n";
+ next;
+ }
+}
+
+sub load_packages2install() {
+ my $progs_conf_file = '/usr/share/mcc/progs.conf';
+ foreach (cat_($progs_conf_file)) {
+ #if (my ($key, $val) = /^USE_WRAPPER_FOR_(.*)=(.*)/) {
+ if (my ($key, $val) = /^INSTALL_FOR_(.*)=(.*)/) {
+ $key =~ s/_/ /g;
+ # we'll use gurpmi in order to install missing packages if needed;
+ $programs{$key}{packages2install} = $val if $val;
+ } else {
+ warn "bogus line in $conf_file: $_\n";
+ next;
+ }
+ }
+}
+
+sub clean_list {
+ my ($subtree) = @_;
+ grep {
+ my $stuff = $_;
+ my $exec = real_bin_path($programs{$stuff}{binary});
+ my $is_present = -x $exec;
+ if (!$is_present && $programs{$stuff}{packages2install}) {
+ $is_present = 1;
+ # override missing icon:
+ $programs{$stuff}{real_icon} ||= $programs{$stuff}{icon};
+ $programs{$stuff}{icon} = 'installremoverpm';
+ } elsif ($programs{$stuff}{real_icon}) {
+ $programs{$stuff}{icon} = $programs{$stuff}{real_icon};
+ }
+ # do not complain about missing entries in move:
+ warn qq("$exec" is not executable [$stuff]) if $mga_rel !~ /Move/ && !$is_present && !$programs{$stuff}{disabled};
+ !$programs{$stuff}{hidden} && $is_present && !$programs{$stuff}{disabled};
+ } @$subtree;
+}
+
+sub build_widget_element {
+ my ($label) = @_;
+ my $icon = $programs{$label}{icon};
+
+ die "$label 's icon is missing" if !$programs{$label} && $::testing;
+ $tool_callbacks{$label} = sub {
+ run_tool($label, undef, #$event_box,
+ $icon, $programs{$label}{description}, $programs{$label});
+ };
+ # FIX ME: DO THIS AGAIN:
+ $tool_feedback{$label} = sub {}; #sub { $event_box->window && $event_box->window->set_cursor($hand_cursor) };
+ my $real_icon = $icon ? '<IMG SRC="' . mygtk2::_find_imgfile($icon) . '">' : '';
+ my @widgets = (
+ qq(<TD class="img">$real_icon</TD>),
+ qq(<TD style="text-align: $align"><DIV>)
+ . escape_text_for_TextView_markup_format($programs{$label}{description})
+ . qq(</DIV></TD>)
+ );
+ qq(<TD WIDTH="49%">
+<A HREF="$label"><TABLE align="$align2" ID="subtable"><TR>
+@widgets
+</TR></TABLE></A></TD>
+);
+}
+
+my (@strings, $current_string_idx);
+sub load_view() {
+ $view->load_html_string($strings[$current_string_idx], 'file:///');
+}
+
+sub build_list() {
+ my $index = 0;
+ load_packages2install();
+ my $i;
+foreach (@tree) {
+ my ($text, $icon, $help, $subtrees) = @$_;
+
+ my @subtrees = grep { $_->{list} = [ clean_list($_->{list}) ]; !is_empty_array_ref($_->{list}) } @$subtrees;
+
+
+ # Skip empty classes:
+ next if !@subtrees;
+ $i++;
+
+
+ my $my_index = $index++;
+ my $square_icon_uri = mygtk2::_find_imgfile('cadre-ic');
+ my $back_img = mygtk2::_find_imgfile('right-white-background_right_part_768.png');
+ my $string = join("\n", qq(<HTML>
+<HEAD>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<style type="text/css">
+ body {
+// background-color: #ecf0f2;
+// background-image: url($back_img);
+ background-repeat: no-repeat; /*pas de répition de l'image*/
+ background-attachment: fixed;
+ background-position: top left
+ }
+ p {text-align: $align}
+ td {text-align: $align}
+ #title {
+ text-align: $align;
+ color: #grey;
+ font-weight: bold;
+ margin-left: 13px;
+ margin-top: 16px;
+ margin-bottom: 8px;
+ }
+ #top_margin {
+ margin-top: 30px;
+ }
+ #block {
+ margin-left: 4px;
+ margin-bottom: 24px;
+ border-spacing: 8px 0px;
+ }
+ #subtable {
+ border-spacing: 8px 8px;
+ }
+ td.img {
+ background-image: url($square_icon_uri);
+ background-repeat: no-repeat;
+ background-position: center center;
+ width: 60; height: 60;
+ text-align: center;
+ }
+ hr {
+ background-color: #eef2f6;
+ margin-left: 21px;
+ margin-right: 22px;
+ height: 1;
+ border: 0;
+ }
+ tr {text-align: $align}
+ td {
+ margin-left: 10px;
+ margin-right: 10px;
+ }
+),
+ if_(mygtk2::text_direction_rtl(), " a { direction: rtl; unicode-bidi: embed }"), qq(
+ a:link {color:black; text-decoration:none }
+ a:visited {color:black; text-decoration:none }
+ a:hover {color:grey }
+// a:active {color:black; text-decoration:none }
+</style>
+
+</HEAD>
+<BODY>
+));
+
+
+
+ # Create right notebook pages :
+
+ my $section;
+ foreach my $subtree (@subtrees) {
+ $string .= $section++ ? "<hr NOSHADE>\n" : '<div ID="top_margin"></div>';
+ my $title = mygtk2::asteriskize($subtree->{title});
+ $string .= qq(
+<div ID="title">$title</div>
+<TABLE BORDER=0 WIDTH="100%" ID="block">
+);
+ if (@{$subtree->{list}} % 2) {
+ my @widgets = (pop @{$subtree->{list}}, "");
+ @widgets = reverse @widgets if mygtk2::text_direction_rtl();
+ push @{$subtree->{list}}, @widgets;
+ }
+ $string .= join("\n",
+ map {
+ "<TR>" . join("\n", grep { defined $_ } @$_) . "</TR>" }
+# "<TR>" . join("\n<TD> </TD>\n", grep { defined $_ } @$_) . "</TR>" }
+ group_by(2, map { $_ ? build_widget_element($_) : '<TD></TD>' } @{$subtree->{list}})
+ );
+
+ $string .= "</TABLE>\n";
+ }
+ my $text_orig = $text;
+ # b/c we use Pango text markup language, we've to protect '&' caracter:
+ $text =~ s/&/&amp;/g;
+ $page_count++;
+
+ $string .= qq(</BODY></HTML>);
+ if ($save_html) {
+ mkdir_p('/tmp/mcc');
+ MDK::Common::File::output_utf8("/tmp/mcc/$i.html", $string);
+ }
+
+ $strings[$my_index] = $string;
+ push @buttons, gtknew('Button', relief => 'none', child =>
+ gtknew('Label_Right', text_markup => qq(<small>$text</small>), ellipsize => 'end'),
+ clicked => sub {
+ $current_string_idx = $my_index;
+ load_view();
+ $steps->move_selection($_[0]->child);
+ $banner_notebook->set_current_page($my_index);
+ $help_on_context = $help;
+ },
+ );
+
+ #add2notebook($banner_notebook, "", Gtk2::Banner->new($icon, $text_orig));
+}
+}
+
+$view->signal_connect('navigation-requested' =>
+ sub {
+ my (undef, undef, $request) = @_;
+ my $res = 'ignore';
+
+ # get the actual program ID:
+ my $url = Glib::filename_from_uri($request->get_uri);
+ $url =~ s!^/*!!; # not a path
+
+ # workaround wekbit calling navigation-requested with "/":
+ if (!$url) {
+ return 'accept';
+ }
+
+ # url can be a translated UTF-8 string (eg: for CD/DVD entries):
+ c::set_tagged_utf8($url);
+
+ # do not crash on eg: "reload":
+ if (!$tool_callbacks{$url}) {
+ warn "Warning: invalid tool name: $url\n";
+ return $res;
+ }
+ $tool_callbacks{$url}->();
+ # FIXME: the following code is currently useless:
+ # should we provide a way to kill buggy embedded programs ?
+ return $res if $left_locked;
+ warn_on_startup();
+ return $res;
+ });
+
+my %icons = (
+ );
+
+# manage tools not present in MCC (localedrake, drakauth, ...):
+foreach my $label (difference2([ keys %programs ], [ keys %tool_callbacks ])) {
+ my $text = $programs{$label}{description};
+ $tool_callbacks{$label} = sub { run_tool($label, undef, $icons{$label} || 'wizard-mdk', $text, $programs{$label}) };
+ $tool_feedback{$label} = sub {};
+}
+
+
+foreach (keys %check_boxes) {
+ my $widget = $check_boxes{$_};
+ if (defined $widget) {
+ $widget->set_active($option_values{$_});
+ } else {
+ print STDERR qq(BUG with LANGUAGE "$ENV{LANGUAGE}" for "$_"\n);
+ err_dialog(N("Error"), N("There's a bug in translations of your language (%s)
+
+Please report that bug.", $ENV{LANGUAGE}));
+ }
+}
+
+# "wait while launching a program" area :
+
+my ($run_pixbuf, $run_counter, $run_counter_add, %run_pixbufs);
+
+sub stop_wait_area() {
+ $wait_darea->hide;
+ Glib::Source->remove($timeout) if $timeout;
+ undef %run_pixbufs;
+}
+
+$wait_darea->signal_connect(expose_event => sub {
+ my ($w) = @_;
+ return if !$wait_darea->realized;
+ return unless $run_pixbuf; # some people got an expose event before we start an embedded tool
+ return unless $wait_darea->{size};
+ $wait_darea->{layout} ||= $wait_darea->create_pango_layout(N("Loading... Please wait"));
+ my $pixbuf = $run_pixbufs{$run_counter} ||= mygtk2::_pixbuf_render_alpha($run_pixbuf, $run_counter);
+ if (!$wait_darea->{first_expose}) {
+ $wait_darea->{first_expose} = 1;
+ my $size = $wait_darea->{size};
+ my ($d_width, $d_height) = ($size->width, $size->height);
+ ($w->{pix_width}, $w->{pix_height}) = ($pixbuf->get_width, $pixbuf->get_height);
+ my ($txt_width, $txt_height) = $wait_darea->{layout}->get_pixel_size;
+ $w->{pix_yy} = ($d_width - $w->{pix_width})/2;
+ $w->{pix_xx} = ($d_height - $w->{pix_height} - $txt_height)/2;
+ $w->{text_yy} = $w->{pix_yy} + ($w->{pix_width} - $txt_width)/2;
+ $w->{text_xx} = $w->{pix_xx} + $w->{pix_height} + 5;
+ }
+ $pixbuf->render_to_drawable($w->window, $w->style->fg_gc('normal'), 0, 0, $w->{pix_yy}, $w->{pix_xx}, $w->{pix_width}, $w->{pix_height}, 'normal', 0, 0);
+ my $style = $wait_darea->{style} ||= $wait_darea->get_style;
+ $wait_darea->window->draw_layout($style->text_gc('normal'), $w->{text_yy}, $w->{text_xx}, $w->{layout});
+ $run_counter += $run_counter_add;
+ $run_counter_add = -$run_counter_add if $run_counter < 100 || 255-$run_counter_add < $run_counter;
+});
+
+gtkflush();
+
+# display first page (we use a timeout so that Y position of widgets is know):
+Glib::Timeout->add(100, sub { $buttons[0]->signal_emit('clicked'); 0 });
+
+$window_global->show_all;
+
+hide_buttons();
+$emb_box->hide;
+$wait_darea->realize;
+
+$SIG{USR1} = 'IGNORE';
+$SIG{USR2} = 'IGNORE';
+$SIG{TERM} = \&quit_global;
+$SIG{CHLD} = \&sig_child;
+
+$window_splash->destroy;
+undef $window_splash;
+Glib::Timeout->add(200, sub { sig_child('CHLD', 1); 1 });
+
+if ($program) {
+ if (my $sub = $tool_callbacks{$program}) {
+ Glib::Timeout->add(500, sub { $sub->(); 0 });
+ } else {
+ err_dialog(N("Error"), N("Impossible to run unknown '%s' program", $program));
+
+ }
+}
+
+Gtk2->main;
+
+
+sub group_by {
+ my $nb = shift @_;
+ my @l;
+ for (my $i = 0; $i < @_; $i += $nb) {
+ push @l, [ map { $_[$_] } $i..$i+$nb-1 ]; # $_[$i], $_[$i+1], $_[$i+2] ];
+ }
+ @l;
+}
+
+sub warn_on_startup() {
+ if ($pending_app) {
+ return if !splash_warning(N("The modifications done in the current module won't be saved."), 1);
+ kill_children();
+ child_just_exited();
+ }
+}
+
+#-------------------------------------------------------------
+# socket/plug managment
+
+# called once embedded tool has exited
+sub child_just_exited() {
+ $pending_app = 0;
+ $left_locked = 0;
+ if ($emb_socket) {
+ $emb_socket->destroy;
+ undef $emb_socket;
+ }
+ $emb_box->hide;
+ hide_buttons();
+ $cancel->hide;
+ gtkset_mousecursor_normal();
+ foreach my $w ($steps, $banner_notebook) {
+ $w->show;
+ }
+
+ stop_wait_area();
+}
+
+sub hide_socket_and_clean() {
+ $emb_box->hide;
+ $pending_app = 0;
+}
+
+sub create_hidden_socket {
+ my ($icon, $label) = @_;
+ my $banner;
+ gtkpack_($emb_box,
+ 0, $banner = gtkpack__(Gtk2::VBox->new(0, 0), Gtk2::Banner->new($icon, $label),
+ Gtk2::HSeparator->new,
+ ),
+ 1, gtksignal_connect($emb_socket = Gtk2::Socket->new, 'plug-removed' => sub {
+ $menu->show if $application_driven_menu;
+ $banner->destroy;
+ child_just_exited();
+ }));
+ $banner->hide;
+ # signal emitted when embedded apps begin to draw:
+ $emb_socket->signal_connect('plug-added' => sub {
+ $banner_notebook->hide;
+ if ($application_driven_menu) {
+ $menu->hide;
+ } else {
+ $banner->show;
+ }
+ stop_wait_area();
+ $left_locked = 0;
+ hide_buttons();
+ $buttons->hide;
+ return if !$emb_socket;
+ $emb_socket->show;
+ $emb_socket->can_focus(1);
+ $emb_socket->grab_focus;
+ #$emb_socket->window->XSetInputFocus; #only need by console (no more embedded until we've vte/zvt binding)
+ });
+ $emb_box->set_focus_child($emb_socket);
+ $emb_socket->hide;
+}
+
+
+#-------------------------------------------------------------
+# processes managment
+
+# embedded processes pid will be stocked there
+my @pid_launched;
+
+# logdrake pid are stocked here
+my $pid_exp;
+
+sub fork_ {
+ my ($prog, $o_pid_table) = @_;
+ $o_pid_table ||= \@pid_launched;
+ my $pid = fork();
+ if (defined $pid) {
+ !$pid and do { exec($prog) or POSIX::_exit(1) }; # immediate exit, else forked gtk+ object destructors will badly catch up parent mcc
+ push @$o_pid_table, $pid;
+ return $pid;
+ } else {
+ splash_warning(N("cannot fork: %s", "$!"));
+ child_just_exited();
+ }
+}
+
+sub real_bin_path {
+ my ($prog) = @_;
+ first(split /\s+/, $prog);
+}
+
+sub run_tool {
+ my ($label, $box, $icon, $text, $tool) = @_;
+ my ($exec, $gtkplug) = @$tool{qw(binary embedded)};
+ $application_driven_menu = $tool->{application_driven_menu};
+ return if $tool_pids{$label};
+ my $will_run_gurpmi;
+ if (! -x real_bin_path($exec)) {
+ if ($tool->{packages2install}) {
+ # gurpmi doesn't support being embedded yet:
+ $gtkplug = -1;
+ $exec = join(' ', "$bindir/gurpmi", split(/\s/, $tool->{packages2install}));
+ $will_run_gurpmi = 1;
+ } else {
+ splash_warning(N("cannot fork and exec \"%s\" since it is not executable", $exec));
+ return;
+ }
+ }
+ $exec .= " --summary" if $option_values{expert_wizard} && $exec =~ /drakwizard/;
+ my $embedded = $gtkplug != -1; # not "explicitely not embedded"
+ if ($embedded) {
+ $steps->hide;
+ create_hidden_socket($icon, $text);
+ $emb_box->show;
+ $emb_socket->realize;
+ $pending_app = $tool->{binary};
+ if ($gtkplug > 0) {
+ $buttons->show;
+ $exec .= " --embedded " . $emb_socket->get_id;
+ $wait_darea->show;
+ $cancel->show;
+ $run_pixbuf = eval { gtkcreate_pixbuf($icon . "_128") };
+ $run_counter = 255;
+ $run_counter_add = -5;
+ undef $wait_darea->{color};
+ undef $wait_darea->{size};
+ undef $wait_darea->{first_expose};
+ $wait_darea->{not_yet_complete} = 1;
+ $timeout = Glib::Timeout->add(35, sub {
+ $wait_darea->{size} ||= $wait_darea->allocation;
+ my $style = $wait_darea->{style} ||= $wait_darea->get_style;
+ my $bg = $wait_darea->{bg} ||= $style->bg('normal');
+ my $base = $wait_darea->{base} ||= $style->base('normal');
+ my $color = $wait_darea->{color} ||= $base;
+ # $base -> $bg
+ my @colors = ([ $color->red, $bg->red ],
+ [ $color->green, $bg->green ],
+ [ $color->blue, $bg->blue ]);
+ if ($wait_darea->{not_yet_complete} && any { $_->[0] != $_->[1] } @colors) {
+ $wait_darea->window->set_background($color);
+ $wait_darea->{color} = gtkcolor(map { $_->[0] - min(300, $_->[0] - $_->[1]) } @colors);
+ $wait_darea->queue_draw;
+ } elsif ($wait_darea->{not_yet_complete}) {
+ # set exact color
+ $wait_darea->window->set_background($bg);
+ $wait_darea->queue_draw;
+ $wait_darea->{not_yet_complete} = 0;
+ } else {
+ my $w = $wait_darea;
+ $wait_darea->queue_draw_area($w->{pix_yy}, $w->{pix_xx}, $w->{pix_width}, $w->{pix_height});
+ }
+ 1;
+ });
+ $left_locked = 1;
+ $buttons->show;
+ $tool_pids{$label} = fork_($exec);
+ }
+ } else { # not embedded
+ # fix #3415 when $gtkplug eq -1
+ local $option_values{embedded} = 0;
+ $tool_pids{$label} = fork_($exec);
+ $gurpmi_pid = $tool_pids{$label} if $will_run_gurpmi;
+ }
+ start_logdrake();
+ $box->window->set_cursor($wait_cursor) if $box;
+}
+
+sub start_logdrake() {
+ # (re)start logdrake if needed
+ if ($option_values{show_log} && !$pid_exp) {
+ my $exec_log = "logdrake --explain=drakxtools";
+ $pid_exp = fork_($exec_log, []);
+ }
+
+}
+
+sub kill_them_all {
+ foreach my $pid (@_) {
+ kill('TERM', $pid) if $pid;
+ }
+}
+
+sub kill_children() {
+ kill_them_all(@pid_launched);
+}
+
+sub kill_logdrake() {
+ kill_them_all($pid_exp) if $pid_exp;
+}
+
+sub quit_global() {
+ if (@pid_launched) {
+ &kill_children();
+ return 1; # tell gtk+ not to quit
+ }
+ &kill_children();
+ &kill_logdrake();
+ my ($x, $y) = $window_global->get_size;
+ setVarsInSh($conffile, {
+ LOGS => bool2text($option_values{show_log}),
+ EXPERT_WIZARD => bool2text($option_values{expert_wizard}),
+ HEIGTH => $y,
+ WIDTH => $x,
+ THEME => $theme,
+ });
+ gtkset_mousecursor_normal();
+ Gtk2::exit(0);
+ standalone::exit(0);
+}
+
+
+#-------------------------------------------------------------
+# signals managment
+
+# got when child died and gone in zombie state
+sub sig_child {
+ my ($_sig, $o_is_cleaner) = @_;
+ my $child_pid;
+ do {
+ $child_pid = waitpid(-1, POSIX::WNOHANG);
+ if (my $tool = find { $tool_pids{$_} eq $child_pid } keys %tool_pids) {
+ $tool_feedback{$tool}->();
+ delete $tool_pids{$tool};
+ @pid_launched = grep { $_ ne $child_pid } @pid_launched;
+ if ($child_pid == $gurpmi_pid) {
+ undef $gurpmi_pid;
+
+ my @services;
+ if ($programs{$tool}{services_to_start_after_install}) {
+ @services = @{$programs{$tool}{services_to_start_after_install}};
+ run_program::raw({ detach => 1 }, 'service', $_, 'restart') foreach @services;
+ }
+
+ # refresh the icon list if some package got installed (eg: system-config-printer)
+ build_list();
+ load_view();
+ }
+ }
+ undef $pid_exp if $pid_exp eq $child_pid;
+ } while $child_pid > 0;
+ # child unexpectedly died (cleanup since child_just_exited won't be called by plug-removed since plug never was added)
+ return if $o_is_cleaner || !$left_locked;
+ child_just_exited();
+ splash_warning(N("This program has exited abnormally"));
+}
+
+
+#-------------------------------------------------------------
+# mcc dialog specific functions
+
+sub splash_warning {
+ my ($label, $o_cancel_button) = @_;
+ warn_dialog(N("Warning"), $label, { cancel => $o_cancel_button });
+}
+
+sub new_dialog {
+ my ($title, $o_no_button) = @_;
+ my $dialog = gtkset_border_width(Gtk2::Dialog->new, 10);
+ $dialog->set_transient_for($window_global);
+ $dialog->set_position('center-on-parent');
+ $dialog->set_title($title);
+ $dialog->action_area->pack_start(gtkadd(Gtk2::HButtonBox->new,
+ gtksignal_connect(Gtk2::Button->new(N("Close")), clicked => sub { $dialog->destroy })
+ ),
+ 0,0,0) unless $o_no_button;
+ gtkset_modal($dialog, 1);
+}
+
+sub more_themes() {
+ my $window_about = new_dialog(N("More themes"));
+ gtkpack_($window_about->vbox,
+ 0, Gtk2::Label->new(N("Getting new themes")),
+ 0, gtkadd(gtkset_shadow_type(gtkset_border_width(Gtk2::Frame->new(N("Additional themes")), 10), 'etched_out'),
+ gtkpack(Gtk2::HBox->new(0, 5),
+ N("Get additional themes on www.damz.net"),
+ )
+ )
+ );
+ $window_about->show_all;
+}
+
+sub about_mga_cc() {
+ my $window_about = new_dialog(N("About - %s Control Center", $branding));
+ my $tree_model = Gtk2::TreeStore->new("Glib::String", "Glib::String", "Glib::String");
+ my $credits = Gtk2::TextView->new;
+ my $list = Gtk2::TreeView->new_with_model($tree_model);
+ $list->can_focus(0);
+ each_index { $list->append_column(Gtk2::TreeViewColumn->new_with_attributes(undef, Gtk2::CellRendererText->new, 'text' => $::i)) } 0..1;
+ $list->set_headers_visible(0);
+
+ foreach my $row ([ N("Authors: "), '' ],
+ [ '', 'Chmouel Boudjnah' ],
+ [ '', 'Damien "dam\'s" Krotkine',
+ #-PO "perl" here is the programming language
+ N("(perl version)") ],
+ [ '', 'Daouda Lo' ],
+ [ '', 'Thierry Vignaud' ],
+ [ '', 'Yves Duret' ],
+ [ '', '' ],
+ [ N("Artwork: "), '', '' ],
+ [ '', 'Anh-Van Nguyen' ],
+
+ [ '',
+ #-PO If your language allows it, use eacute for first "e" and egrave for 2nd one.
+ N("Helene Durosini"), '<ln@mandriva.com>' ],
+ ) {
+ $tree_model->append_set(undef, [ map_index { $::i => $_ } @$row ]);
+ }
+
+ my ($previous_type, $not_first_title, $not_first_block);
+ my $locale = lang::read;
+ require Gtk2::Pango;
+ foreach my $line (grep { $_ ne "\n" && !/^#/ } cat_(top(glob("/usr/share/doc/mageia-release-*/CREDITS.$locale->{lang}")))) {
+ if (my ($type, $comment, $contributor) = split(/\|/, $line, 3)) {
+ last if !$type;
+ $comment =~ s/^ //; # fix initial space of first section (CREDITS format should be enhanced to specify lines that really are sections)
+ chomp($contributor);
+ if ($previous_type ne $type) {
+ gtktext_append($credits, [ [ join('', if_($not_first_title, "\n"), translate(common::to_utf8($type)), "\n"),
+ { 'weight' => Gtk2::Pango->PANGO_WEIGHT_BOLD, scale => Gtk2::Pango->scale_large } ] ]);
+ $previous_type = $type;
+ $not_first_title = 1;
+ }
+ if ($contributor) {
+ gtktext_append($credits,
+ #-PO: this is used as "language: translator" in credits part of the about dialog:
+ N("- %s: %s\n", map { translate($_) } $comment, $contributor)
+ );
+ } else {
+ $comment = $comment . "\n" if !$not_first_block; # fix spacing before second title;
+ gtktext_append($credits, join('', if_($not_first_block, "- "), translate($comment)));
+ $not_first_block = 1;
+ }
+ }
+ }
+
+
+ # Give our translators the ability to show their family and
+ # friends that thez participated ...
+
+#-PO Add your Name here to find it in the About section in your language.
+ my $translator_name = N("_: NAME OF TRANSLATORS\nYour names");
+#-PO Add your E-Mail address here if you want to show it in the about doialog.
+ my $translator_email = N("_: EMAIL OF TRANSLATORS\nYour emails");
+ if ($translator_name ne "Your names" && 0) {
+ $tree_model->append_set(undef, [ 0 => $_->[0], 1 => $_->[1] ]) foreach [ '', '' ], [ N("Translator: ") ];
+ $tree_model->append_set(undef, [ 0 => $_->[0], 1 => $_->[1] ]) foreach [ '', $translator_name, $translator_email ];
+ }
+ $list->get_selection->set_mode('none');
+
+ gtkpack_($window_about->vbox,
+ (0, Gtk2::Banner->new('/usr/share/icons/large/drakconf.png',
+ #-PO: Here, first %s will be replaced by 'Mageia'
+ #-PO: second %s will be replaced by the version (eg: "Mageia 1 (Free) Control Center")
+ N("%s %s (%s) Control Center",
+ $branding, @$release{qw(version product)}))),
+ 0, Gtk2::Label->new(""),
+ 0, Gtk2::Label->new(
+ #-PO: here %s is eg: "1999-2008"
+ N("Copyright (C) %s Mandriva SA", '1999-2008') . "\n" . N("Copyright (C) %s Mageia", '2011') . "\n" ),
+ 0, Gtk2::HSeparator->new,
+ 0, Gtk2::Label->new(""),
+ 1, my $n = Gtk2::Notebook->new,
+ );
+
+ add2notebook($n, N("Authors"), $list);
+ add2notebook($n, N("Mageia Contributors"), gtkset_size_request(create_scrolled_window($credits), 650, 50));
+ $n->set_current_page(0);
+
+ $window_about->show_all;
+}
+
+
+#-------------------------------------------------------------
+# mcc specific graphic functions:
+
+
+sub set_page {
+ my ($index) = @_;
+ start_logdrake();
+ set_page_raw($index);
+ hide_buttons();
+}
+
+sub hide_buttons() {
+ $buttons->hide;
+ $cancel->hide;
+}
+
+
+sub create_packtable2 {
+ my ($options, @l) = @_;
+ my $w = Gtk2::Table->new(0, 0, 1);
+ add2hash_($options, { xpadding => 5, ypadding => 0 });
+ each_index {
+ my ($i, $l) = ($::i, $_);
+ each_index {
+ my $j = $::i;
+ if ($_) {
+ ref $_ or $_ = gtknew('WrappedLabel', text => $_);
+ $w->attach($_, $j, $j + 1, $i, $i + 1, ['expand', 'fill'], ['expand', 'fill'], $options->{xpadding}, $options->{ypadding});
+ $_->show;
+ }
+ } @$l;
+ } @l;
+ $w->set_col_spacings($options->{col_spacings} || 0);
+ $w->set_row_spacings($options->{row_spacings} || 0);
+ gtkset_border_width($w, $::isInstall ? 3 : 10);
+}
+
+#-------------------------------------------------------------
+# mcc specific graphic functions:
+
+sub render_shiner {
+ my ($pixbuf, $shine_value) = @_;
+ my $new_pixbuf = (mygtk2::_new_alpha_pixbuf($pixbuf))[2];
+ $pixbuf->saturate_and_pixelate($new_pixbuf, $shine_value, 0);
+ $new_pixbuf;
+}
+
+sub scale {
+ my ($pixbuf, $gain) = @_;
+ my ($width, $height) = ($pixbuf->get_height, $pixbuf->get_width);
+ $pixbuf->scale_simple($height+$gain, $width+$gain, 'hyper');
+}
+
+
+1;