#!/usr/bin/perl # $Id$ # Copyright (C) 1999-2005 Mandriva # Daouda Lo # Damien Krotkine # Thierry Vignaud # 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; use network::network; # i18n: IMPORTANT: to get correct namespace (drakconf instead of libDrakX) BEGIN { unshift @::textdomains, 'drakconf' } use ugtk2 qw(:create :dialogs :helpers :wrappers); use Gtk2::Pango; use Gtk2::Html2; #------------------------------------------------------------- # paths my ($bindir, $sbindir, $xbindir) = ("/usr/bin", "/usr/sbin", "/usr/X11R6/bin"); my $mcc_dir = "/usr/share/mcc"; my $themes_dir = "$mcc_dir/themes/"; my (%tool_pids, %tool_feedback); my ($version, $conffile, $class_install) = (`cat /etc/mandrakelinux-release` =~ /\b(\d+\.{1}.+\))/, "/etc/mcc.conf", "/etc/sysconfig/system"); my ($default_heigth, $default_width) = (523, 720); require_root_capability(); # 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{EXPERT_MODE} ||= bool2text(0); $h{HEIGTH} ||= $default_heigth; $h{WIDTH} ||= $default_width; $h{USE_LONG_DESCRIPTIONS} ||= 'yes'; my %option_values; $option_values{use_long_dscr} = text2bool($h{USE_LONG_DESCRIPTIONS}); $option_values{show_log} = text2bool($h{LOGS}); $option_values{expert_mode} = text2bool($h{EXPERT_MODE}); my $theme = $h{THEME}; $theme = $1 if "@ARGV" =~ /--theme (\w+)/; my $program; foreach (@ARGV) { $program = $1 if /--start-with=(.*)/; } my ($i, $geometry); foreach (@ARGV) { $i++; if (/^--geometry$/) { $geometry = splice @ARGV, $i, 1; last; } } -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 my $rc = find { -r $_ } ("$themes_dir/$theme/gtkrc", if_($theme ne 'default', "$themes_dir/default/gtkrc")); Gtk2::Rc->parse($rc) if -r $rc; #------------------------------------------------------------- # Splash window: please wait ... my $window_splash = Gtk2::Window->new('popup'); $window_splash->signal_connect(delete_event => \&quit_global); $window_splash->set_title(N("Mandriva Linux Control Center")); $window_splash->set_position('center_always'); $window_splash->add(gtkadd(gtkset_shadow_type(Gtk2::Frame->new, 'etched_out'), gtkput(my $fixed = Gtk2::Fixed->new, gtkpack(Gtk2::VBox->new(0, 0), if_(-r "$themes_dir/$theme/splash_screen.png", gtkcreate_img("splash_screen")), gtkset_markup(Gtk2::Label->new, join('', qq(\n), N("Mandriva Linux Control Center"), ""), ), Gtk2::Label->new(N("Loading... Please wait") . "\n"), ), 0, 0), ) ); $fixed->set_has_window(1); $fixed->signal_connect(realize => sub { ugtk2::set_back_pixmap($fixed) }); $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/X11R6/bin/rfbdrake"; my $isDrakStats = -e "/usr/sbin/drakstats"; my $application_driven_menu; # { key => { log_exp, binary, embedded?, description ] } # embedded meaning: -1 => not embedded, 0 => external x11 app, 1 => proper embedding my %programs = ( "Authentication" => { binary => "$sbindir/drakauth", embedded => 1, description => #-PO: this message is already translated in drakx domain from which MCC will searchs it: N("Authentication"), long_description => N("Select the authentication method (local, NIS, LDAP, Windows Domain, ...)"), icon => 'drakauth-mdk', expert_mode => 1, }, "Auto Install" => { binary => "$sbindir/drakautoinst", embedded => 1, description => N("Auto Install floppy"), long_description => N("Generate an Auto Install floppy"), icon => 'drakautoinst-mdk', expert_mode => 1, }, "Auto login Config" => { binary => "$sbindir/drakboot", embedded => 1, description => N("Autologin"), long_description => N("Enable autologin and select the user to automatically log in"), icon => 'autologin-mdk', }, "Backups" => { binary => "$sbindir/drakbackup", embedded => 1, description => N("Backups"), long_description => N("Configure backups of the system and of the users' data"), icon => 'backup-mdk', }, "Boot Config" => { binary => "$sbindir/drakboot --boot", embedded => 1, description => N("Boot loader"), long_description => N("Set up how the system boots"), icon => 'drakboot-mdk', }, "Boot Theme" => { binary => "$sbindir/drakboot --splash", embedded => 1, description => N("Boot theme"), long_description => N("Select the graphical theme of the system while booting"), icon => 'boot-theme-mdk', }, "Boot Disk" => { binary => "$sbindir/drakfloppy", embedded => 1, description => N("Boot floppy"), long_description => N("Generate a standalone boot floppy"), icon => 'drakfloppy-mdk', }, "Connection Sharing" => { binary => "$sbindir/drakgw", embedded => 1, description => N("Internet connection sharing"), long_description => N("Share the Internet connection with other local machines"), icon => 'drakgw-mdk', }, "Add Connection" => { binary => "$sbindir/drakconnect --wizard", embedded => 1, description => N("New connection"), long_description => N("Set up a new network interface (LAN, ISDN, ADSL, ...)"), icon => 'new-connection-mdk', }, "Configure Internet" => { binary => "$sbindir/drakconnect --internet", embedded => 1, description => N("Internet access"), long_description => N("Alter miscellaneous internet settings"), icon => 'internet-access-mdk', }, "Console" => { binary => "$sbindir/drakconsole", embedded => 1, description => N("Console"), long_description => N("Open a console"), icon => 'console-mdk', #The Console will help you to solve issues }, "Date & Time" => { binary => "$sbindir/clock.pl", embedded => 1, description => N("Date and time"), long_description => N("Adjust the date and the time"), icon => 'time-mdk', }, "Display Manager chooser" => { binary => "$sbindir/drakedm", embedded => 1, description => N("Display manager"), long_description => N("Choose the display manager that enables to select which user to log in"), icon => 'drakedm-mdk', }, "Roaming" => { binary => "$sbindir/drakroam", embedded => 1, description => translate("Wireless connection"), long_description => translate("Wireless connection"), # translation came from DrakX icon => 'drakroam-mdk', }, "Fax" => { binary => "$sbindir/drakfax_server", embedded => 1, description => N("Fax"), long_description => N("Configure a fax server"), icon => 'drakfax-mdk', }, "Firewall" => { binary => "$sbindir/drakfirewall", embedded => 1, description => N("Firewall"), long_description => N("Set up a personal firewall in order to protect the computer and the network"), icon => 'firewall-mdk', }, "Fonts" => { binary => "$sbindir/drakfont", embedded => 1, description => N("Fonts"), long_description => N("Manage, add and remove fonts. Import Windows(TM) fonts"), icon => 'drakfont-mdk', }, "Graphical server configuration" => { binary => "$sbindir/XFdrake", embedded => 1, description => N("Graphical server"), long_description => N("Set up the graphical server"), icon => 'XFdrake-mdk' }, "Hard Drives" => { binary => "$sbindir/diskdrake --hd", embedded => 1, description => N("Partitions"), long_description => N("Create, delete and resize hard disk partitions"), icon => 'diskdrake_hd', }, "Hardware List" => { binary => "$sbindir/harddrake2", embedded => 1, description => N("Hardware"), long_description => N("Look at and configure the hardware"), icon => 'harddrake-mdk', application_driven_menu => 1, }, "Hosts" => { binary => "$sbindir/drakhosts", embedded => 1, description => N("Hosts definitions"), long_description => N("Manage hosts definitions"), icon => 'drakhosts', }, "Install Software" => { binary => "$sbindir/rpmdrake", embedded => 1, description => N("Install"), long_description => N("Look at installable software and install software packages"), icon => 'rpmdrake', application_driven_menu => 1, }, "Installed Software" => { binary => "$sbindir/rpmdrake-remove", embedded => 1, description => N("Installed Software"), icon => 'rpmdrake-remove', application_driven_menu => 1, hidden => 1, }, "Keyboard" => { binary => "$sbindir/keyboarddrake", embedded => 1, description => N("Keyboard"), long_description => N("Set up the keyboard layout"), icon => 'keyboard-mdk', }, "Kolab" => { binary => "$sbindir/kolab", embedded => 1, description => N("Kolab"), long_description => N("Set up a groupware server"), expert_mode => 1, }, "Localization" => { binary => "$bindir/localedrake", embedded => 1, description => #-PO: this message is already translated in drakx domain from which MCC will searchs it: N("Language") . " - " . #-PO: this message is already translated in drakx domain from which MCC will searchs it: N("Country / Region"), long_description => N("Select the language and the country or region of the system"), }, "Logs" => { binary => "$sbindir/logdrake", embedded => 1, description => N("Logs"), long_description => N("View and search system logs"), icon => 'logdrake-mdk', }, "Manage Connection" => { binary => "$sbindir/drakconnect --skip-wizard", embedded => 1, description => N("Manage connections"), long_description => N("Reconfigure a network interface"), icon => 'manage-connections-mdk', }, "Mandriva Online" => { binary => "$xbindir/mdkonline", embedded => 1, description => N("Mandriva Online"), long_description => N("Upload your configuration in order to keep you informed about security updates and useful upgrades"), icon => 'mdkonline-mdk', expert_mode => 1, }, "Manage park" => { binary => "$sbindir/park-rpmdrake", embedded => 1, description => N("Manage computer group"), long_description => N("Manage installed software packages on a group of computers"), icon => 'drakpark-mdk', expert_mode => 1, }, "Mandriva Update" => { binary => "$sbindir/MandrivaUpdate", embedded => 1, description => N("Updates"), long_description => N("Look at available updates and apply any fixes or upgrades to installed packages"), icon => 'MandrakeUpdate', application_driven_menu => 1, }, "Menus" => { binary => "$bindir/menudrake", embedded => -1, description => N("Menus"), long_description => N("Select the application menu layout and change which programs are shown on the menu"), icon => 'menudrake-mdk', }, "Monitor" => { binary => "$sbindir/XFdrake monitor", embedded => 1, description => N("Monitor"), long_description => N("Configure your monitor"), icon => 'configure-monitor-mdk', }, "Monitor Connection" => { binary => "$sbindir/net_monitor", embedded => 1, description => N("Monitor connections"), long_description => N("Monitor the network connections"), icon => 'net_monitor-mdk', }, "Mouse" => { binary => "$sbindir/mousedrake", embedded => 1, description => N("Mouse"), long_description => N("Set up the pointer device (mouse, touchpad)"), icon => 'mousedrake-mdk', }, "NFS mount points" => { binary => "$sbindir/diskdrake --nfs", embedded => 1, description => N("NFS mount points"), long_description => N("Set NFS mount points"), icon => 'diskdrake_nfs', }, "NFS exports" => { binary => "$sbindir/draknfs", embedded => 1, description => N("Manage NFS shares"), long_description => N("Manage NFS shares"), icon => 'draknfs', }, "Package stats" => { binary => "$sbindir/drakstats", embedded => 1, description => N("Package Stats"), long_description => N("Show statistics about usage of installed software packages"), icon => 'source-manager', }, "Partition Sharing" => { binary => "$sbindir/diskdrake --fileshare", embedded => 1, description => N("Local disk sharing"), long_description => N("Set up sharing of your hard disk partitions"), icon => 'diskdrake_fileshare', }, "Printer" => { binary => "$sbindir/printerdrake", embedded => 1, description => N("Printers"), icon => 'printer-mcc-mdk', long_description => N("Set up the printer(s), the print job queues, ..."), application_driven_menu => 1, }, "Programs scheduling" => { binary => "/usr/X11R6/bin/drakcronat", embedded => 1, description => N("Scheduled tasks"), long_description => N("Schedule programs to run periodically or at given times"), #DrakCronAt enables to schedule Programs execution through crond and atd daemons icon => 'drakcronat-mdk', }, "Proxy Configuration" => { binary => "$sbindir/drakproxy", embedded => 1, description => N("Proxy"), long_description => N("Set up a proxy server for files and web browsing"), icon => 'drakproxy-mdk', }, "Remote Control" => { binary => "$xbindir/rfbdrake", embedded => 1, description => N("Remote Control (Linux/Unix, Windows)"), long_description => N("Remote Control of another machine (Linux/Unix, Windows)"), icon => 'internet-access-mdk', }, "Remove Interface" => { binary => "$sbindir/drakconnect --del", embedded => 1, description => N("Remove a connection"), long_description => N("Delete a network interface"), icon => 'remove-connection-mdk', }, "Remove Software" => { binary => "$sbindir/rpmdrake-remove", embedded => 1, description => N("Remove"), long_description => N("Look at installed software and uninstall software packages"), icon => 'rpmdrake-remove', application_driven_menu => 1, }, "Resolution" => { binary => "$sbindir/XFdrake resolution", embedded => 1, description => N("Screen resolution"), long_description => N("Change the screen resolution"), icon => 'resolution-mdk', }, "Samba mount points" => { binary => "$sbindir/diskdrake --smb", embedded => 1, description => N("Samba mount points"), long_description => N("Set Samba mount points"), icon => 'diskdrake_samba', }, "Samba configuration" => { binary => "$sbindir/draksambashare", embedded => 1, description => N("Manage Samba configuration"), long_description => N("Manage configuration of Samba"), icon => 'draksambashare', }, "Scanner" => { binary => "$sbindir/scannerdrake", embedded => 1, description => N("Scanners"), long_description => N("Set up scanner"), icon => 'scanner-mdk', }, "Security Level" => { binary => "$sbindir/draksec", embedded => 1, description => N("Level and checks"), long_description => N("Set the system security level and the periodic security audit"), icon => 'draksec-mdk', expert_mode => 1, }, "Security Permissions" => { binary => "$sbindir/drakperm", embedded => 1, description => N("Permissions"), long_description => N("Fine-tune the security permissions of the system"), icon => 'drakperm-mdk', expert_mode => 1, }, "Services" => { binary => "$sbindir/drakxservices", embedded => 1, description => N("Services"), long_description => N("Enable or disable the system services"), icon => 'service-mdk', }, "Software Media Manager" => { binary => "$sbindir/edit-urpm-sources.pl", embedded => 1, description => N("Media Manager"), long_description => N("Select from where software packages are downloaded when updating the system"), icon => 'source-manager', }, "TV Cards" => { binary => "$sbindir/drakxtv", embedded => 1, description => N("TV card"), long_description => N("Set up TV card"), icon =>, 'tv-mdk', }, "UPS" => { binary => "$sbindir/drakups --wizard", embedded => 1, description => N("UPS"), long_description => #-PO: here power means electrical power N("Set up a UPS for power monitoring"), icon => 'drakups-mdk', }, "Users" => { # too big binary => "$bindir/userdrake", embedded => 1, description => N("Users and groups"), long_description => N("Add, remove or change users of the system"), icon => 'user-mdk', application_driven_menu => 1, }, "WebDAV mount points" => { binary => "$sbindir/diskdrake --dav", embedded => 1, description => N("WebDAV mount points"), long_description => N("Set WebDAV mount points"), icon => 'webdav-mdk', }, ); 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, $expert_mode) = @$_; $programs{$id} = { binary => "$sbindir/drakwizard $wizard", embedded => 1, description => $description, long_description => $long_description, icon => $icon, expert_mode => $expert_mode, }; is_wizard_installed($file) ? $id : (); } @_; } # [ [ class_label, class icon name, [ program_label, ... ] ] my @tree = (if_($isRpmDrake || $isParkRpmDrake, [ N("Software Management"), 'software', [ if_($isRpmDrake, "Install Software", "Installed Software", "Remove Software", "Mandriva Update", "Software Media Manager", ), if_($isParkRpmDrake, "Manage park"), if_($isDrakStats, "Package stats"), "Mandriva Online" ] ]), if_(0, [ N("Server wizards"), 'wizard-mdk' ]), [ N("Sharing"), 'file-sharing-mdk', [ (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, ], [ "Samba printing", "sambaprint", 'wizard-sambaprint', N("Samba printing configuration"), N("Enable or disable printers in your Samba server configuration"), 'Sambaprint.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 Mandriva Linux"), 'Installsrv.pm', 1, ], ), ), ] ], [ N("Network Services"), 'network-services-mdk', [ (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', ], ), ), ] ], [ N("Authentication"), 'drakauth-mdk', [ 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', ], ), ), ] ], [ N("Groupware"), 'groupware-mdk', [ (wizard_format(# [ id, wizard file name, icon, description ] [ "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, [ N("Online Administration"), 'online-administration-mdk', [ 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 intalled. 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", ) ] ]), [ N("Hardware"), 'drakhard-mdk', [ "Hardware List",, "Monitor", "Resolution", if_(0, "Graphical server configuration"), if_(-x "$bindir/drakfax", "Fax"), "TV Cards", "Keyboard", "Mouse", "Printer", "Scanner", "UPS", ] ], [ N("Network & Internet"), 'net-mdk', [ "Add Connection", "Configure Internet", "Manage Connection", "Monitor Connection", "Remove Interface", "Proxy Configuration", "Connection Sharing", "Roaming", "Hosts", ], ], [ N("System"), 'system-mdk', [ if_(!$is_auth_wizard_installed, "Authentication"), "Menus", "Display Manager chooser", "Services", "Fonts", "Date & Time", "Logs", if_($ENV{LANGUAGE} !~ /^zh/, "Console"), "Users", if_(-x "/usr/X11R6/bin/drakcronat", "Programs scheduling"), "Backups", ] ], [ N("Mount Points"), 'partition-mdk', [ "Hard Drives", (map { my ($type, $scan, $text, $long_text) = @$_; map_index { my $full_name = $text . ($::i ? $::i + 1 : ''); $programs{$full_name} = { binary => "$sbindir/diskdrake --removable=$_->{device}", embedded => 1, description => $text, long_description => $long_text, 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"), N("Set where your CD-ROM drive is mounted"), ], [ 'dvd', sub { @{$cdroms_by_type{DVD} || []} }, N("DVD-ROM"), N("Set where your DVD-ROM drive is mounted"), ], [ 'cdwriter', sub { @{$cdroms_by_type{burner} || []} }, N("CD/DVD burner"), N("Set where your CD/DVD burner is mounted"), ], [ 'floppy', \&detect_devices::floppies, N("Floppy drive"), N("Set where your floppy drive is mounted"), ], [ 'zip', \&detect_devices::zips, N("ZIP drive"), N("Set where your ZIP drive is mounted"), ], ); }), "NFS mount points", "NFS exports", "Samba mount points", "WebDAV mount points", "Partition Sharing", "Samba configuration", ] ], [ N("Security"), 'security-mdk', [ "Security Level", "Security Permissions", "Firewall", ] ], [ N("Boot"), 'boot-mdk', [ #if_(detect_devices::floppies, "Boot Disk"), # kernel is too big "Auto login Config", "Boot Config", "Boot Theme", 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}, # expert mode by default, as they are provided by 3rd parties expert_mode => 1 }; push(@{$leaf[2]}, $tmp{NAME}); } push(@tree, \@leaf); } #------------------------------------------------------------- # let build the GUI # main window : my ($timeout, %check_boxes, $emb_socket); my $window_global = gtkset_size_request(Gtk2::Window->new('toplevel'), 620, 460); $::main_window = $window_global; if ($geometry) { my ($w, $h) = $geometry =~ /(\d+)x(\d+)/; my ($x, $y) = $geometry =~ /([+-]\d+)([+-]\d+)/; $window_global->resize(max($w, $default_width), max($default_heigth, $h)); $window_global->set_uposition($x, $y) if $x || $y; } else { $window_global->resize(max($default_width, $h{WIDTH}), max($h{HEIGTH}, $default_heigth)); } $window_global->set_icon(gtkcreate_pixbuf("/usr/share/icons/drakconf.png")); my $pending_app = 0; my $help_on_context = 'drakconf-intro'; #Please replace with correct contextual help page my @ctx = qw(drakconf-intro mcc-boot mcc-hardware mcc-mountpoints mcc-network mcc-security mcc-system software-management wiz-client); 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") ], 'expert_mode' => [ N("/_Options"), translate("/_Expert mode") ], ); my %shared_translations = ( "profiles" => N("/_Profiles"), "delete" => N("/_Delete"), "new" => N("/_New"), ); # for profiles: my $net = {}; my @profiles; my $mdk_rel = common::mandrake_release(); my ($notebook_global, $saved_pos_while_in_menu); my @menu_items = ( [ N("/_File"), undef, undef, undef, '' ], [ N("/_File") . N("/_Quit"), N("Q"), \&quit_global, undef, '', N("Quit") ], [ N("/_Options"), undef, undef, undef, '' ], [ 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, '' ], [ join('', @{$options{expert_mode}}), undef, sub { $option_values{expert_mode} = $check_boxes{expert_mode}->get_active; $saved_pos_while_in_menu = $notebook_global && $notebook_global->get_current_page; refresh_tree(1); if ($notebook_global) { if (!$emb_socket) { $notebook_global->show_all; $notebook_global->queue_draw; } # restore previous position: $notebook_global->set_current_page($saved_pos_while_in_menu) if $saved_pos_while_in_menu && $saved_pos_while_in_menu != -1; } }, undef, '' ], if_(0 && $isWiz, [ join('', @{$options{wiz_expert}}), undef, sub { $option_values{expert_wizard} = $check_boxes{wiz_expert}->get_active }, undef, '', ], ), if_(@themes > 1, [ N("/_Themes"), undef, undef, undef, '' ], (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, '' ]; } @themes), [ N("/_Themes") . N("/_More themes"), undef, \&more_themes, undef, '' ] ), [ $shared_translations{profiles}, undef, undef, undef, '' ], [ $shared_translations{profiles} . $shared_translations{new}, undef, sub { my $dialog = _create_dialog(N("New profile..."), { small => 1, transient => $window_global }); my $entry_dialog = Gtk2::Entry->new; gtkpack($dialog->vbox, Gtk2::WrappedLabel->new(N("Name of the profile to create (the new profile is created as a copy of the current one):")), $entry_dialog, ); gtkpack($dialog->action_area, gtksignal_connect(Gtk2::Button->new(N("Cancel")), clicked => sub { $dialog->destroy }), gtksignal_connect(my $bok = Gtk2::Button->new(N("Ok")), clicked => sub { my $prof = $entry_dialog->get_text; # netprofile does not like spaces in profile names... $prof =~ s/ /_/g; # warn if already existing: if (member($prof, @profiles)) { err_dialog(N("Error"), N("The \"%s\" profile already exists!", $prof), { transient => $dialog }); return 1; } network::network::netprofile_add($net, $prof); update_profiles(); $dialog->destroy; }), ); $bok->can_default(1); $bok->grab_default; $dialog->show_all; Gtk2->main; update_profiles(); }, undef, '' ], [ $shared_translations{profiles} . $shared_translations{delete}, undef, sub { return if !$window_global->realized && $net->{PROFILE} ne "default"; my $dialog = _create_dialog(N("Delete profile"), { stock => 'gtk-dialog-warning' }); gtkpack($dialog->vbox, Gtk2::Label->new(N("Profile to delete:")), my $combo_dialog = Gtk2::OptionMenu->new, ); $combo_dialog->set_popdown_strings(grep { ! /default/ } network::network::netprofile_list()); gtkpack($dialog->action_area, gtksignal_connect(Gtk2::Button->new(N("Cancel")), clicked => sub { $dialog->destroy }), gtksignal_connect(Gtk2::Button->new(N("Ok")), clicked => sub { my $profile2delete = $combo_dialog->entry->get_text; if ($profile2delete eq $net->{PROFILE}) { err_dialog(N("Warning"), N("You can not delete the current profile")); return 1; } $dialog->destroy; Gtk2->main_quit; network::network::netprofile_delete($profile2delete); update_profiles(1); }), ); $dialog->show_all; Gtk2->main; return; }, undef, '' ], [ join('/', $shared_translations{profiles}, ""), undef, undef, undef, '' ], [ N("/_Help"), undef, undef, undef, '' ], [ N("/_Help") . N("/_Help"), undef, sub { fork_("drakhelp --id $help_on_context") }, undef, '', N("Help") ], [ N("/_Help") . N("/_Report Bug"), undef, sub { fork_("drakbug --report drakconf &") }, undef, '' ], [ N("/_Help") . N("/_About..."), undef, \&about_mdk_cc, undef, '' ] ); 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 } @_) } # menus do not like "_" from profiles (whereas netprofile does not like spaces in profile names...) sub profile2menu { my ($profile) = @_; $profile =~ s/_/ /g; "/$profile"; } sub enable_profile_entry { my ($profile, $value) = @_; eval { $factory->get_widget(get_path("
", $shared_translations{profiles} . profile2menu($profile)))->set_active($value); }; print "error: $@\n" if $@; } # update profiles list sub update_profiles { my ($removing) = @_; my $done; $factory->delete_item(get_path("
", $shared_translations{profiles} . profile2menu($_))) foreach @profiles; network::network::netprofile_read($net); @profiles = network::network::netprofile_list(); foreach my $prof (@profiles) { $factory->create_item([ $shared_translations{profiles} . profile2menu($prof), undef, sub { return unless $done; if ($net->{PROFILE} eq $prof) { $done = 0; enable_profile_entry($prof, 1); $done = 1; return 0; } if (!warn_dialog(N("Warning"), N("We are about to switch from the \"%s\" profile to the \"%s\" profile. Are you sure you want to do the switch?", $net->{PROFILE}, $prof), { transient => $window_global })) { $done = 0; enable_profile_entry($prof, 0); $done = 1; return; } # wait message is needed $done = 0; enable_profile_entry($net->{PROFILE}, 0); network::network::netprofile_set($net, $prof); enable_profile_entry($prof, 1) if !$removing; $done = 1; }, undef, '' ]); # Radio } $factory->get_widget(get_path("
", $shared_translations{profiles}, $shared_translations{delete}))->set_sensitive(@profiles > 1); eval { $factory->get_widget(get_path("
", $shared_translations{profiles} . profile2menu($net->{PROFILE})))->set_active(1) }; print "error is «$@»\n" if $@; $done = 1; } update_profiles(); %check_boxes = map { $_ => $factory->get_widget("
" . get_path(@{$options{$_}})); } ('show_log', 'expert_mode', if_(0 && $isWiz, "wiz_expert")); gtkadd($window_global, gtkpack_(Gtk2::VBox->new(0, 0), 0, $menu, 0, my $banner_notebook = Gtk2::Notebook->new, 0, Gtk2::HSeparator->new, # 0, gtkset_size_request(Gtk2::VBox->new(10, 10), -1, 2), 1, gtkpack_(Gtk2::HBox->new(0, 0), 1, $notebook_global = gtkset_name(Gtk2::Notebook->new, 'mcc'), 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(); }), gtkset_sensitive(gtkset_relief(Gtk2::Button->new(""), 'none'), 0), ), ) ); sub notebook_set_background { my ($w) = @_; return if !$w->realized; my $color = $window_global->get_style->base('normal'); Gtk2::Rc->parse_string(join('', qq(style "mcc" { bg[NORMAL] = { ), join(' ,', $color->red, $color->green, $color->blue), qq( } bg_pixmap[NORMAL] = "" } widget "*mcc*" style "mcc" ))); $notebook_global->reset_rc_styles; } $notebook_global->signal_connect(realize => \¬ebook_set_background); $window_global->signal_connect("style-set" => sub { notebook_set_background($notebook_global) }); $window_global->signal_connect(delete_event => \&quit_global); use POSIX qw(:sys_utsname_h :math_h :sys_wait_h :unistd_h); my (undef, $nodename) = POSIX::uname(); $window_global->set_title(N("Mandriva Linux Control Center %s [on %s]", $version, $nodename)); $window_global->set_position('center'); foreach my $notebook ($banner_notebook) { $notebook->set_property('show-border', 0); $notebook->set_property('show-tabs', 0); } $notebook_global->set_property('tab-pos', 'left'); $notebook_global->set_scrollable(1); # banner : add2notebook($banner_notebook, "", Gtk2::Banner->new("/usr/share/icons/large/drakconf.png", N("Welcome to the Mandriva Linux Control Center"))); my ($hand_cursor, $normal_cursor, $wait_cursor) = map { Gtk2::Gdk::Cursor->new($_) } qw(hand2 left-ptr watch); my ($index, $left_locked) = (0, 0); my $spacing = 25; my %tool_callbacks; my ($page_count, $need_to_refresh, $is_freezed); sub really_refresh_tree { my $pos = $notebook_global->get_current_page; $notebook_global->show_all; $notebook_global->queue_draw; # workaround buggy gtk+: $notebook_global->set_current_page($page_count-$_-1) foreach 0..$page_count-1; # restore previous position: if ($pos != -1) { $notebook_global->set_current_page($pos); } elsif ($saved_pos_while_in_menu) { $notebook_global->set_current_page($saved_pos_while_in_menu); undef $saved_pos_while_in_menu; } $notebook_global->window && $notebook_global->window->thaw_updates if $is_freezed; $is_freezed = 0; } sub request_url { my ($document, $url, $stream) = @_; $stream->write(join('', cat_($url))); $stream->close; } my $align = lang::text_direction_rtl() ? "right" : "justify"; my $align2 = lang::text_direction_rtl() ? "right" : "left"; sub refresh_tree { my ($mode) = @_; if ($mode && $page_count) { # this is not initial tree filling bug "expert mode" swtich if (!$is_freezed && $notebook_global->window) { $notebook_global->window->freeze_updates; $is_freezed = 1; } $notebook_global->remove_page(-1) foreach 0..$page_count-1; $page_count = 0; } foreach (@tree) { my ($text, $icon, $subtree) = @$_; my @subtree; foreach my $stuff (@$subtree) { my $exec = first(split /\s+/, $programs{$stuff}{binary}); next if $programs{$stuff}{hidden}; next if !$option_values{expert_mode} && $programs{$stuff}{expert_mode}; # do not complain about missing entries in move: if (-x $exec) { push @subtree, $stuff; } else { warn qq("$exec" is not executable [$stuff]) if $mdk_rel !~ /Move/; } } # Skip empty classes: next if !@subtree; my $my_index = $index++; my $string = join("\n", qq( )); my $view = Gtk2::Html2::View->new; my $document = Gtk2::Html2::Document->new; $document->signal_connect (request_url => \&request_url); $document->signal_connect ('link-clicked' => sub { my ($document, $url) = @_; $tool_callbacks{$url}->(); # FIXME: the following code is currently useless: # should we provide a way to kill buggy embedded programs ? return if $left_locked; warn_on_startup(); }); $view->set_document ($document); my $box; # Create right notebook pages : $string .= join("\n", map { "" . join("\n", grep { defined $_ } @$_) . "" } # "" . join("\n\n", grep { defined $_ } @$_) . "" } group_by($option_values{use_long_dscr} ? 2 : 3, map { 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 $file = ugtk2::_find_imgfile($icon); my @widgets = ( qq(), qq() ); @widgets = reverse @widgets if lang::text_direction_rtl(); qq(
$programs{$label}{long_description} @widgets
); } @subtree) ); # b/c we use Pango text markup language, we've to protect '&' caracter: $text =~ s/&/&/g; $page_count++; $string .= qq(
); $document->clear; $document->open_stream("text/html"); $document->write_stream($string); gtkappend_page($notebook_global, my $_w_ret = create_scrolled_window(gtkset_border_width($view, 5), [ 'never', 'automatic' ], # 'none', ), gtkpack__(Gtk2::HBox->new, Gtk2::Image->new_from_pixbuf(::scale(gtkcreate_pixbuf($icon), -16)), gtkset_markup(Gtk2::WrappedLabel->new, '' . $text . ''), ), ); # $w_ret->vscrollbar->set_size_request(19, undef); add2notebook($banner_notebook, "", Gtk2::Banner->new($icon, $text)) if !$mode; } $need_to_refresh = defined($emb_socket); really_refresh_tree() if $mode && !$need_to_refresh; } refresh_tree(); my %icons = ( "Localization" => 'localedrake' ); # 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} ||= 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(); set_page_raw(0); $notebook_global->signal_connect(switch_page => sub { my $tab_number = $_[2]; return unless $tab_number > 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 $notebook ($notebook_global, $banner_notebook) { $notebook->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 { # handle expert mode switch: really_refresh_tree() if $need_to_refresh; $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 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}; if (! -x first(split /\s+/, $exec)) { 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) { foreach my $notebook ($notebook_global) { $notebook->hide; } create_hidden_socket($icon, $text); $emb_box->show; $emb_socket->realize; $pending_app = 1; if ($gtkplug > 0) { $buttons->show; $exec .= " --embedded " . $emb_socket->get_id; $wait_darea->show; $cancel->show; $run_pixbuf = 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 { my $size = $wait_darea->{size} ||= $wait_darea->allocation; my ($width, $height) = ($size->width, $size->height); 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 my $old = $option_values{embedded}; $option_values{embedded} = 0; $tool_pids{$label} = fork_($exec); $option_values{embedded} = $old; } 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 { map { if__($_, kill 'TERM', $_) } @_; } sub kill_children() { kill_them_all(@pid_launched); @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}), EXPERT_MODE => bool2text($option_values{expert_mode}), 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; } 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_mdk_cc() { my $window_about = new_dialog(N("About - Mandriva Linux Control Center")); 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..2; $list->set_headers_visible(0); foreach my $row ([ N("Authors: "), '', '' ], [ '', 'Chmouel Boudjnah', N("(original C version)") ], [ '', 'Damien "dam\'s" Krotkine', #-PO "perl" here is the programming language N("(perl version)") ], [ '', 'Daouda Lo', '' ], [ '', 'Thierry Vignaud', '' ], [ '', 'Yves Duret', N("(perl version)") ], [ '', '' ], [ N("Artwork: "), '', '' ], [ '', 'Anh-Van Nguyen', N("(design)") ], [ '', #-PO If your language allows it, use eacute for first "e" and egrave for 2nd one. N("Helene Durosini"), '' ], ) { $tree_model->append_set(undef, [ map_index { $::i => $_ } @$row ]); } my ($previous_type, $not_first_title, $not_first_block); my $locale = lang::read; my @files = (glob("/usr/share/doc/mandriva-release-*/CREDITS"), glob("/usr/share/doc/mandriva-release-*/CREDITS.$locale->{lang}")); foreach my $line (grep { $_ ne "\n" && !/^#/ } cat_(top((glob("/usr/share/doc/mandriva-release-*/CREDITS"), glob("/usr/share/doc/mandriva-release-*/CREDITS.$locale->{lang}"))))) { $line =~ s/ Limited Edition 2005 \|//; 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(c::to_utf8($type)), "\n"), { 'weight' => Gtk2::Pango->PANGO_WEIGHT_BOLD, scale => Gtk2::Pango->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: "), $translator_name, $translator_email ]; } $list->get_selection->set_mode('none'); gtkpack_($window_about->vbox, (0, gtkset_size_request(Gtk2::Banner->new('splash_screen_about', N("Mandriva Linux Control Center"), { txt_ypos => 50 }), -1, 120)), 0, Gtk2::Label->new(""), 0, Gtk2::Label->new(N("Copyright (C) 1999-2005 Mandriva SA") . "\n"), 0, Gtk2::HSeparator->new, 0, Gtk2::Label->new(""), 1, my $n = Gtk2::Notebook->new, ); add2notebook($n, N("Authors"), $list); add2notebook($n, N("Mandriva Linux Contributors"), gtkset_size_request(create_scrolled_window($credits), 650, 50)); $window_about->show_all; } #------------------------------------------------------------- # mcc specific graphic functions: sub set_page_raw { my ($bool) = @_; foreach my $notebook ($notebook_global, $banner_notebook) { $notebook->set_current_page($bool); } } sub set_page { my ($index) = @_; start_logdrake(); set_page_raw($index); $help_on_context = $ctx[$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 rtl_gtkcreate_pixbuf { my ($icon) = @_; my $pixbuf; eval { $pixbuf = ugtk2::gtkcreate_pixbuf($icon . "_rtl") } if lang::text_direction_rtl(); $pixbuf ||= ugtk2::gtkcreate_pixbuf($icon); } sub rtl_gtkcreate_img { my ($icon) = @_; lang::text_direction_rtl() ? ugtk2::gtkcreate_img($icon . "_rtl") : ugtk2::gtkcreate_img($icon); } sub new_pixbuf { my ($pixbuf) = @_; my ($height, $width) = ($pixbuf->get_height, $pixbuf->get_width); my $new_pixbuf = Gtk2::Gdk::Pixbuf->new('rgb', 1, 8, $height, $width); $new_pixbuf->fill(0x00000000); # transparent white $width, $height, $new_pixbuf; } sub render_alpha { my ($pixbuf, $alpha_threshold) = @_; my ($width, $height, $new_pixbuf) = new_pixbuf($pixbuf); $pixbuf->composite($new_pixbuf, 0, 0, $width, $height, 0, 0, 1, 1, 'nearest', $alpha_threshold); $new_pixbuf; } sub render_shiner { my ($pixbuf, $shine_value) = @_; my $new_pixbuf = (new_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;