#!/usr/bin/perl # $Id$ # Copyright (C) 1999-2002 MandrakeSoft # 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. my $xbindir = "/usr/X11R6/bin"; my $bindir = "/usr/bin"; my $sbindir = "/usr/sbin"; my $mcc_dir = "/usr/share/mcc"; my $themes_dir = "$mcc_dir/themes/"; my $wizdir = "/usr/share/wizards"; use strict; use diagnostics; use lib qw(/usr/lib/libDrakX); use standalone; use common; use interactive; use detect_devices; use ugtk2 qw(:create :helpers :wrappers); #------------------------------------------------------------- # i18n : IMPORTANT to get correct namespace (drakconf instead of libDrakX) unshift @::textdomains, 'drakconf'; my ($version, $conffile, $class_install) = ("9.1", "/etc/mcc.conf", "/etc/sysconfig/system"); my $in = 'interactive'->vnew('su', 'default'); # just to get root capabilities #------------------------------------------------------------- # read configuration, set themes, ... my %h = getVarsFromSh($conffile); my %class = getVarsFromSh($class_install); $h{THEME} ||= 'default'; $h{EMBEDDED} ||= bool2text(1); $h{LOGS} ||= bool2text($class{CLASS} eq 'expert' ? 1 : 0); $h{EXPERT_WIZARD} ||= 0; my ($embedded, $show_logs, $expert_wizard) = (text2bool($h{EMBEDDED}), text2bool($h{LOGS}), text2bool($h{EXPERT_WIZARD})); my $theme = $h{THEME}; if ("@ARGV" =~ /--theme (\w+)/) { $theme = $1 } -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 = "$themes_dir/$theme/gtkrc"; $rc = "$themes_dir/default/gtkrc" if ! -r $rc && $theme ne 'default'; 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("Mandrake Control Center") . $version); $window_splash->allow_shrink(0); $window_splash->allow_grow(0); $window_splash->set_position('center_always'); $window_splash->add(gtkadd(gtkset_shadow_type(Gtk2::Frame->new, 'etched_out'), gtkpack(Gtk2::VBox->new(0, 0), if_(-r "$themes_dir/$theme/splash_screen.png", gtkcreate_img("splash_screen")), Gtk2::Label->new(N("Loading... Please wait")) ) ) ); $window_splash->show_all; gtkflush(); #------------------------------------------------------------- # we'll show log only once and don't restart it with new embedded process my $freeze_log = 1; my $still_in_splash_screen = 1; #------------------------------------------------------------- # Data structures $::isWiz = -e "/usr/sbin/drakwizard"; $::isRpmDrake = -e "/usr/sbin/rpmdrake"; # { key => [ log_exp, binary, gtkplug?, description ] } # { key => [ log_exp, [ binary, win_nb ], gtkplug?, description ] } my $exec_hash = { "Auto Install" => [ "drakautoinst", "$sbindir/drakautoinst", 1, N("DrakAutoInst enables to configure an Auto Install floppy") ], "Backups" => [ "drakbackup", "$sbindir/drakbackup", 1, N("DrakBackup help in configuring Backups") ], "Boot Config" => [ "drakboot", "$sbindir/drakboot", 1, N("DrakBoot help in configuring the system bootstrapping") ], "Boot Disk" => [ "drakfloppy", "$sbindir/drakfloppy", 1, N("Drakfloppy enables to build a customized Boot Disk") ], "Connection Sharing" => [ "drakgw", "$sbindir/drakgw", 1, N("DrakGw enables to share an internet connection") ], "Connection" => [ "drakconnect", "$sbindir/drakconnect", 1, N("DrakConnect help in configuring network connections") ], # little workaround to avoid drakconf freeze # "Console" => [ "rxvt", "$xbindir/rxvt", -1, "" ], "Console" => [ "rxvt", [ "$xbindir/rxvt", "rxvt", 1 ], 0, N("The Console will help you to solve issues") ], "Date & Time" => [ "clock", "$sbindir/clock.pl", 1, N("Date & Time configuration") ], "Firewall" => [ "drakfirewall", "$sbindir/drakfirewall", 1, N("DrakFirewall configures a personal firewall (look at MNF for a powerful dedicated firewall solution)") ], "Fonts" => [ "drakfont", "$sbindir/drakfont", 1, N("DrakFont enables to install and remove fonts") ], "Graphical server configuration" => [ "XFdrake", "$sbindir/XFdrake", 1, N("The X configurator help in configuring the graphical server") ], "Hard Drives" => [ "diskdrake", "$sbindir/diskdrake --hd", 1, N("DiskDrake enables to alter hard disks partitionning scheme and to resize partitions") ], "Hardware List" => [ "harddrake", "$sbindir/harddrake2", 1, N("Harddrake enables to list and configure the hardware") ], "Install Software" => [ "rpmdrake", "$sbindir/rpmdrake", -1, N("Install Software: RpmDrake enables to install software packages") ], "Keyboard" => [ "keyboarddrake", "$sbindir/keyboarddrake", 1, N("KeyboardDrake let configure the keyboard layout") ], "Logs" => [ "logdrake", "$sbindir/logdrake", 1, N("Logdrake enables to search in system logs") ], "Mandrake Update" => [ "rpmdrake", "$sbindir/MandrakeUpdate", -1, N("Mandrake Update will enable you to update your system pacakges") ], "Menus" => [ "menudrake", "$sbindir/menus_launcher.pl", 1, N("MenuDrake enables to manage menus"), "$bindir/menudrake" ], "Monitor" => [ "XFdrake", "$sbindir/XFdrake monitor", 1, N("Monitor configuration") ], "Mouse" => [ "mousedrake", "$sbindir/mousedrake", 1, N("MouseDrake enables to configure the mouse") ], "NFS mount points" => [ "diskdrake", "$sbindir/diskdrake --nfs", 1, N("NFS mount points: dummy description") ], "Partition Sharing" => [ "diskdrake", "$sbindir/diskdrake --fileshare", 1, N("Partition Sharing enables to allow users to share some of their directories, allowing users to simply click on \"Share\" in konqueror and nautilus") ], "Printer" => [ "printerdrake", "$sbindir/printerdrake", 1, N("Printerdrake help in configuring printers, print job queues, ..."), "$sbindir/printerdrake" ], "Programs scheduling" => [ "drakcronat", "/usr/X11R6/bin/drakcronat", 1, N("DrakCronAt enables to schedule Programs execution through crond and atd daemons") ], "Proxy Configuration" => [ "drakproxy", "$sbindir/drakproxy", 1, N("DrakProxy help in configuring file and web proxy") ], "Remove Software" => [ "rpmdrake", "$sbindir/rpmdrake-remove", -1, N("Remove Software: RpmDrake enables to remove software packages") ], "Resolution" => [ "XFdrake", "$sbindir/XFdrake resolution", 1, N("Screen resolution configuration") ], "Samba mount points" => [ "diskdrake", "$sbindir/diskdrake --smb", 1, N("Samba mount points: dummy description") ], "Scanner" => [ "scannerdrake", "$sbindir/scannerdrake", 1, N("ScannerDrake enables to configure scanners") ], "Security Level" => [ "draksec", "$sbindir/draksec", 1, N("DrakSec enables to shrewdly configure the system Security Level") ], "Security Permissions" => [ "drakperm", "$sbindir/drakperm", 1, N("Security Permissions: dummy description") ], "Services" => [ "drakxservices", "$sbindir/drakxservices", 1, N("DrakxServices provides an easy way to enabling or disabling system services") ], "Software Sources Manager" => [ "rpmdrake", "$sbindir/edit-urpm-sources.pl", -1, N("The Software Sources Manager enables to configure packages sources") ], "TV Cards" => [ "drakxtv", "$sbindir/drakxtv", 1, N("DrakxTV help in configuring tv cards") ], "Users" => [ "userdrake", "$bindir/userdrake", 1, N("Userdrake help in managing system's users") ], "WebDAV mount points" => [ "diskdrake", "$sbindir/diskdrake --dav", 1, N("WebDAV mount points: dummy description") ], }; # [ [ class_label, class icon name, [ [ program_label, program icon name ] ... ] ] ] my @tree = ([ N("Boot"), 'boot-mdk', [ [ "Boot Disk", 'drakfloppy-mdk', ], [ "Boot Config", 'drakboot-mdk', ], [ "Auto Install", 'drakfloppy-mdk', ], ] ], [ N("Hardware"), 'drakhard-mdk', [ [ "Hardware List", 'harddrake-mdk', ], [ "Monitor", 'XFdrake-mdk', ], [ "Resolution", 'resolution-mdk', ], [ "Graphical server configuration", 'XFdrake-mdk', ], [ "TV Cards", 'tv-mdk', ], [ "Keyboard", 'keyboard-mdk', ], [ "Mouse", 'mousedrake-mdk', ], [ "Printer", 'printer-mdk', ], [ "Scanner", 'scanner-mdk', ], ] ], [ N("Mount Points"), 'partition-mdk', [ [ "Hard Drives", 'diskdrake_hd', ], (map { my ($type, $name, $scan, $text) = @$_; map_index { my $full_name = $name . ($::i ? $::i + 1 : ''); $exec_hash->{$full_name} = [ "diskdrake", "$sbindir/diskdrake --removable=$_->{device}", 1, $text ]; [ $full_name, "diskdrake_$type" ]; } $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', N("CD-ROM"), sub { @{$cdroms_by_type{cdrom} || []} }, N("CD-ROM drive: mount point configuration") ], [ 'dvd', N("DVD"), sub { @{$cdroms_by_type{DVD} || []} }, N("DVD drive: mount point configuration") ], [ 'cdwriter', N("CD Burner"), sub { @{$cdroms_by_type{burner} || []} }, N("CD/DVD burner: mount point configuration") ], [ 'floppy', N("Floppy"), \&detect_devices::floppies, N("Floppy drive: mount point configuration") ], [ 'zip', N("Zip"), \&detect_devices::zips, N("ZIP drive: mount point configuration") ], ), }), [ "NFS mount points", 'diskdrake_nfs', ], [ "Samba mount points", 'diskdrake_samba', ], [ "WebDAV mount points", 'webdav-mdk', ], [ "Partition Sharing", 'diskdrake_fileshare', ], ] ], [ N("Network & Internet"), 'net-mdk', [ [ "Connection", 'drakconnect-mdk', ], [ "Proxy Configuration", 'drakconnect-mdk', ], [ "Connection Sharing", 'drakgw-mdk', ], ], ], [ N("Security"), 'security-mdk', [ [ "Security Level", 'draksec-mdk', ], [ "Security Permissions", 'drakperm-mdk', ], [ "Firewall", 'firewall-mdk', ], ] ], [ N("System"), 'system-mdk', [ [ "Menus" , 'menudrake-mdk', ], [ "Services" , 'service-mdk', ], [ "Fonts", 'drakfont-mdk', ], [ "Date & Time" , 'time-mdk', ], [ "Logs", 'logdrake-mdk', ], [ "Console", 'console-mdk', ], [ "Users", 'user-mdk', ], [ "Programs scheduling", 'time-mdk', ], [ "Backups", 'backup-mdk', ], # [ "RFBDrake", 'unknown-mdk' ], ] ], if_($::isRpmDrake, [ N("Software Management"), 'software', [ [ "Install Software", 'rpmdrake' ], [ "Remove Software", 'rpmdrake-remove' ], [ "Mandrake Update", 'MandrakeUpdate' ], [ "Software Sources Manager", 'source-manager' ], ] ]), if_($::isWiz, [ N("Server Configuration"), 'wizard-mdk', [ (map { my ($id, $wizard, $icon, $description) = @$_; my $path = "/usr/share/wizards/".$wizard."_wizard/"."$wizard".".wiz"; if (-e $path) { $exec_hash->{$id} = [ "drakwizard", "$sbindir/drakwizard $path", -1, $description ]; [ $id, $icon ]; } else { (); } } (# [ id, wizard file name, icon, description ] [ "DHCP wizard", "dhcp", 'server-mdk', N("The DHCP wizard will help you configuring the DHCP services of your server") ], [ "DNS Client wizard", "client", 'server-mdk', N("The DNS Client wizard will help you in adding a new client in your local DNS") ], [ "DNS wizard", "dns", 'server-mdk', N("The DNS wizard will help you configuring the DNS services of your server.") ], [ "Firewall wizard", "firewall", 'server-mdk', N("The Firewall wizard will help you configuring your server firewall that will protects your internal network from unauthorized accesses from the Internet") ], #NEW [ "FTP wizard", "ftp", 'ftp-mdk', N("The FTP wizard will help you configuring the FTP Server for your network") ], [ "News wizard", "news", 'news-mdk', N("The News wizard will help you configuring the Internet News services for your network") ], [ "NFS wizard", "nfs", 'news-mdk', N("The NFS wizard will help you configuring the NFS Server for your network") ], #NEW [ "Postfix wizard", "postfix", 'postfix-mdk', N("The Postfix wizard will help you configuring the Internet Mail services for your network") ], [ "Squid wizard", "proxy", 'web-mdk', N("The Proxy wizard will help you configuring a web caching proxy server") ], [ "Samba wizard", "samba", 'diskdrake_samba', N("The Samba wizard will help you configuring your server to behave as a file and print server for workstations running non-Linux systems") ], [ "Server wizard", "server", 'diskdrake_samba', N("The Server wizard will help you configuring the basic networking services of your server") ], #NEW [ "Time wizard", "time", 'time-mdk', N("The Time wizard will help you to set the time of your server synchronized with an external time server") ], [ "Web wizard", "web", 'web-mdk', N("The Web wizard will help you configuring the Web Server for your network") ] ) ) ] ]), ); #------------------------------------------------------------- # let build the GUI # main window : my ($global_width, $global_height) = (720, 578); my ($timeout, $show_log_check_box, $embedded_check_box, $expert_wizard_check_box); my $window_global = gtkset_size_request(Gtk2::Window->new('toplevel'), $global_width, $global_height); my $pending_app = 0; my ($menu, $factory) = create_factory_menu($window_global, ({ path => N("/_File"), type => '' }, { path => N("/_File") . N("/_Quit"), accelerator => N("Q"), callback => \&quit_global }, #-PO Don't remember to translate "_Options" the same way "Options" is (but for the underscore of course) { path => N("/_Options"), type => '' }, { path => N("/_Options") . N("/Display _Logs"), type => '', callback => sub { $show_logs = $show_log_check_box->active; update_exp(); } }, { path => N("/_Options") . N("/_Embedded Mode"), type => '', callback => sub { $embedded = $embedded_check_box->active; } }, if_($::isWiz, { path => N("/_Options") . N("/Expert mode in _wizards"), type => '', callback => sub { $expert_wizard = $expert_wizard_check_box->active } }, ), if_(all($themes_dir) > 1, { path => N("/_Themes"), type => '' }, (map { my $name = $_; { path => N("/_Themes") . "/" . ($name eq $theme ? " O " : " ") . "_$_", callback => 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 sig_usr1(), exec "$0 --theme $name"; } }; } grep { -d "$themes_dir/$_" } all($themes_dir)), { path => N("/_Themes").N("/_More themes"), callback => \&more_themes } ), { path => N("/_Help"), type => '' }, { path => N("/_Help").N("/_"), callback => sub { fork_("drakhelp Starter.html/control-center.html") } }, { path => N("/_Help").N("/_Report Bug"), callback => sub { fork_("drakbug --report drakconf &") } }, { path => N("/_Help").N("/_About..."), callback => \&about_mdk_cc } )); #-PO Don't remember to translate "Options" the same way "_Options" is (but without the underscore of course) $show_log_check_box = $factory->get_widget("
" . N("/Options") . N("/Display Logs")); $embedded_check_box = $factory->get_widget("
" . N("/Options") . N("/Embedded Mode")); $expert_wizard_check_box = $factory->get_widget("
" . N("/Options") . N("/Expert mode in wizards")); gtkadd($window_global, gtkpack_(Gtk2::VBox->new(0, 3), 0, $menu, 0, gtkset_size_request(my $darea_title = Gtk2::DrawingArea->new, $global_width, 55), 0, Gtk2::HSeparator->new, 1, gtkpack_(Gtk2::HBox->new(0, 0), 0, my $fixed_left = Gtk2::Fixed->new, 1, gtkpack_(my $right_box = Gtk2::VBox->new(0, 0), 1, gtkpack_(my $emb_box = Gtk2::VBox->new(0, 0), 1, my $emb_wait = gtkpack_(Gtk2::VBox->new(0, 0), 1, Gtk2::HBox->new(0, 0), 0, gtkpack_(Gtk2::HBox->new(0, 0), 1, Gtk2::VBox->new(0, 0), 0, gtkadd(gtkset_shadow_type(Gtk2::Frame->new, 'etched_out'), my $run_darea = gtkset_size_request(Gtk2::DrawingArea->new, 128, 128) ), 1, Gtk2::VBox->new(0, 0), ), 0, Gtk2::Label->new(N("Please wait...")), 1, Gtk2::HBox->new(0, 0), 0, gtkadd(gtkset_layout(gtkset_border_width(Gtk2::HButtonBox->new, 10), 'end'), gtksignal_connect(Gtk2::Button->new(N("Cancel")), clicked => sub { Gtk2->timeout_remove($timeout) if $timeout; kill('USR1', $$) }), ) ) ), 1, my $notebook_global = Gtk2::Notebook->new, ) ) ) ); $window_global->signal_connect(delete_event => \&quit_global); $window_global->set_title(N("Mandrake Control Center %s", $version)); $window_global->set_position('center'); $notebook_global->set_property('show-border', 0); $notebook_global->set_property('show-tabs', 0); #$notebook_global->set_show_tabs(0); # banner : $darea_title->signal_connect(realize => sub { set_back_pixbuf($darea_title, gtkcreate_pixbuf('mcc-title-back')) }); my $pixbuf_icon = gtkcreate_pixbuf('mcc-title-icon'); $darea_title->signal_connect(expose_event => sub { $pixbuf_icon->render_to_drawable($darea_title->window, $darea_title->style->white_gc, 0, 0, $darea_title->allocation->width - $pixbuf_icon->get_width, 0, -1, -1, 'none', 0, 0); }); # main page (summary) : my $summary = Gtk2::Fixed->new; $summary->set_has_window(1); $notebook_global->append_page(gtksignal_connect($summary, realize => sub { set_back_pixbuf($summary, gtkcreate_pixbuf("mcc-splash")) })); use POSIX qw(:sys_utsname_h :math_h sys_wait_h); my (undef, $nodename, $release, undef, $machine) = POSIX::uname(); $summary->put(gtkmodify_font(Gtk2::Label->new(N("Welcome to the Mandrake Control Center")), Gtk2::Pango::FontDescription->from_string('15')), 80, 115); # FIXME: better center it at realize time @(summary->width - (vbox->width/2), summary->height - (vbox->height/2) ) # left icons : my @darea_left_list; my ($cursor_hand, $cursor_normal) = (Gtk2::Gdk::Cursor->new('hand2'), Gtk2::Gdk::Cursor->new('left-ptr')); my $right_back_pixbuf = gtkcreate_pixbuf('mcc-core-back'); my $left_back_pixbuf_unaltered = gtkcreate_pixbuf('mcc-left-back'); my $left_back_pixbuf_unaltered_h = gtkcreate_pixbuf('mcc-left-back2'); my ($back_width, $back_height) = ($left_back_pixbuf_unaltered->get_width, $left_back_pixbuf_unaltered->get_height); # 0 => unselected, 1 => highlited, 2 => selected my @left_back_pixbuf = ($left_back_pixbuf_unaltered, $left_back_pixbuf_unaltered, $left_back_pixbuf_unaltered_h); my ($index, $left_locked) = (0, 0); my $index_sav = -1; my (@curr_state, @old_state); my ($d_width, $d_height) = (160, 45); my @colors = (gtkcolor(0, 0, 0), gtkcolor(0xAA, 0xAA, 0xFF), gtkcolor(0, 0, 0)); my $spacing = 25; my $scale = 0; my (@lspacing, $txt_offset); my $top_lspacing = 4; # Create left icons foreach (@tree) { my ($text, $icon, $subtree) = @$_; my $my_index = $index++; # die "gtkput(fixed_left, VBox of StockButtons there or\n (while waiting for gc to implement IconFactory) VBox of Hbox[icon|text]"; my $darea_left = gtkset_size_request(Gtk2::DrawingArea->new, $d_width, $d_height); $darea_left->set_events([ 'exposure_mask', 'enter_notify_mask', 'leave_notify_mask', 'button_press_mask', 'button_release_mask' ]); my $icon_pixbuf = gtkcreate_pixbuf($icon); my ($icon_width, $icon_height) = ($icon_pixbuf->get_width, $icon_pixbuf->get_height); unless (@lspacing) { # $lspacing = round_up(($d_height-$icon_height)/2, 1); my $lspacing = ($d_height-$icon_height)/2; $txt_offset = $lspacing * 2 + $icon_width; $lspacing = round_up($lspacing, 1); @lspacing = ($lspacing, $lspacing+$scale/2, $lspacing); } # my @icon_pixbufs = ($icon_pixbuf, scale(render_shiner($icon_pixbuf, 1.89), $scale), $icon_pixbuf); my @icon_pixbufs = ($icon_pixbuf, render_shiner($icon_pixbuf, 1.89), $icon_pixbuf); my @fonts = map { Gtk2::Pango::FontDescription->from_string($_) } '', 'Bold', 'Bold'; my ($lines, $widths, $heights, @dbl_area_left); push @curr_state, 0; push @old_state, -1; $darea_left->signal_connect(expose_event => sub { my (undef, $event) = @_; my $curr_state = $curr_state[$my_index]; my $full_redraw = $curr_state != $old_state[$my_index]; my ($x, $y, $width, $height) = $full_redraw ? (0, 0, $d_width, $d_height) : $event->area->values; # Redraw double buffer on first expose in that particular state (selected <=> not selected): render background, then icon, then text unless ($dbl_area_left[$curr_state]) { my $extra = $curr_state == 1 ? $scale : 0; my $window = $darea_left->window; # return unless $window; my $lspacing = $lspacing[$curr_state]; $dbl_area_left[$curr_state] = Gtk2::Gdk::Pixmap->new($window, $d_width, $d_height, $window->get_depth); my $gc = $darea_left->style->fg_gc('normal'); $left_back_pixbuf[$curr_state]->render_to_drawable($dbl_area_left[$curr_state], $gc, 0, 0, 0, 0, $back_width, $back_height, 'normal', 0, 0); $icon_pixbufs[$curr_state]->render_to_drawable($dbl_area_left[$curr_state], $gc, 0, 0, $lspacing-$extra, $top_lspacing-$extra/2, $icon_width+$extra, $icon_height+$extra, 'normal', 0, 0); $darea_left->style->black_gc->set_rgb_fg_color($colors[$curr_state]); # $darea_left->style->black_gc->set_fg_gc('normal', $colors[$curr_state]); # $darea_left->style->set_rgb_fg_color($colors[$curr_state]); $darea_left->modify_font($fonts[$curr_state]); (undef, undef, $lines, $widths, $heights) = get_text_coord($text, $darea_left, $d_width-$txt_offset, $d_height, 0, 0, 0, 0); my $offset = listlength(@$lines) > 1 ? $heights->[0]/2 : 0; # multi line texts are offsetted mapn { # $_ = "$_" if $curr_state == 1; # we need Gtk2::Pango::Layout->set_markup to render in blue in highlighted state $dbl_area_left[$curr_state]->draw_layout($darea_left->style->black_gc, $_[1]+$txt_offset, $_[2]-$offset, $darea_left->create_pango_layout($_[0])); } $lines, $widths, $heights; } $old_state[$my_index] = $curr_state; $darea_left->window->draw_drawable($darea_left->style->bg_gc('normal'), $dbl_area_left[$curr_state], $x, $y, $x, $y, $width, $height); }); $darea_left->signal_connect(realize => sub { $darea_left->window->set_cursor($cursor_hand) }); $darea_left->signal_connect(enter_notify_event => sub { return if $old_state[$my_index] == -1 || $curr_state[$my_index] != 0; $curr_state[$my_index] = 1; $darea_left->queue_draw; }); $darea_left->signal_connect(leave_notify_event => sub { return if $curr_state[$my_index] != 1; $curr_state[$my_index] = 0; $darea_left->queue_draw; }); $darea_left->signal_connect(button_release_event => sub { return if $left_locked; return if $pending_app && !splash_warning(N("The modifications done in the current module won't be saved."), 1); clean_socket(); # deselect previously selected darea if ($index_sav != -1) { $curr_state[$index_sav] = 0; $darea_left_list[$index_sav]->window->set_cursor($cursor_hand); $darea_left_list[$index_sav]->queue_draw; } else { $still_in_splash_screen = 0 } $index_sav = $my_index; $curr_state[$my_index] = 2; $darea_left->window->set_cursor($cursor_normal); $darea_left->queue_draw; set_page($my_index+1); }); # push left icons $fixed_left->put($darea_left, 0, $my_index*$d_height); push @darea_left_list, $darea_left; # Create right notebook pages : my $tbl = create_packtable({ col_spacings => $spacing, row_spacings => $spacing, homogeneous => 1 }, group_by2(map { my ($label, $tag) = @$_; my $text = $exec_hash->{$label}[3]; die "$label 's icon is missing" unless $exec_hash->{$label}; my $event_box = gtkadd(Gtk2::EventBox->new(), my $icon = gtkcreate_img($tag)); $event_box->set_events([ 'enter_notify_mask', 'leave_notify_mask', 'button_press_mask', 'button_release_mask' ]); # FIXME: do ->set_pixbuf() on {enter,leave}_events $event_box->signal_connect(realize => sub { $event_box->window->set_cursor($cursor_hand) }); $event_box->signal_connect(button_release_event => sub { compute_exec_string($tag, @{$exec_hash->{$label}}) }); # FIXME : resize sig: ->foreach; set_size_request my $hbox_spacing = 10; gtkpack_(Gtk2::HBox->new(0, $hbox_spacing), 0, $event_box, 1, gtktext_insert(Gtk2::TextView->new, [ [ $text, {'background_set' => 0, 'background_stipple_set' => 0 } ] ]) ); } @$subtree)); $notebook_global->append_page(my $w_ret = create_scrolled_window($tbl, undef, 'none')); # $w_ret->vscrollbar->set_size_request(19, undef); } $notebook_global->set_size_request(-1, $index * 60); my ($exp_frame, $emb_socket); sub update_exp { return if $still_in_splash_screen || $pending_app; if ($show_logs) { if ($exp_frame) { $exp_frame->show_all; } else { gtkpack__($right_box, gtkadd($exp_frame = gtkset_shadow_type(gtkset_size_request(gtkset_border_width(Gtk2::Frame->new(N("Logs")), 5), 0, 120), 'etched_out'))); } } elsif ($exp_frame) { $exp_frame->hide } } $emb_box->set_size_request(-1, $index * 50); eval { if (defined $show_log_check_box) { $show_log_check_box->set_active($show_logs); $embedded_check_box->set_active($embedded); $expert_wizard_check_box->set_active($expert_wizard); }; }; print STDERR "BUG with LANGUAGE $ENV{LANGUAGE}\n" if $@; hide_socket_and_clean(); # default left background $fixed_left->set_has_window(1); $fixed_left->signal_connect(realize => sub { set_back_pixbuf($fixed_left, $left_back_pixbuf[0]) }); # "wait while launching a program" area : my ($run_pixbuf, $run_counter, $run_counter_add); $run_darea->signal_connect(expose_event => sub { my $pixbuf = render_shiner($run_pixbuf, $run_counter); my ($window, $gc, $width, $height) = ($run_darea->window, $run_darea->style->fg_gc('normal'), $pixbuf->get_width, $pixbuf->get_height); $right_back_pixbuf->render_to_drawable($window, $gc, 0, 0, 0, 0, $width, $height, 'normal', 0, 0); $pixbuf->render_to_drawable($window, $gc, 0, 0, 0, 0, $width, $height, 'normal', 0, 0); $run_counter += $run_counter_add; $run_counter_add = -$run_counter_add if $run_counter < 100; $run_counter_add = -$run_counter_add if 245 < $run_counter; }); gtkflush(); $notebook_global->set_current_page(0); $notebook_global->signal_connect(switch_page => sub { my (undef, undef, $tab_number) = @_; return unless $tab_number > 0; }); $window_global->show_all; #$darea_title->hide; $emb_box->hide; $SIG{USR1} = \&sig_usr1; $SIG{USR2} = \&sig_usr2; $SIG{TERM} = \&quit_global; $SIG{CHLD} = \&sig_child; #$SIG{CONT} = sub { Gtk2->main }; $window_splash->destroy; undef $window_splash; eval { Gtk2->main } while 1; # got when child unexpectedly died and gone in zombie state sub sig_child { # reap zombies my $kid; do { $kid = waitpid(-1, POSIX::WNOHANG) } until $kid > 0; return unless $left_locked; kill('USR1', $$); splash_warning(N("This program was abnomarly exited")); # Gtk2->main } # got when child properly exited sub sig_usr1 { $left_locked = 0; clean_socket(); gtkset_mousecursor_normal(); $notebook_global->show; } # got when apps begin to draw sub sig_usr2 { $left_locked = 0; $emb_wait->hide; $emb_socket->show; } # embedded processes pid will be stocked there my @pid_launched; # logdrake pid are stocked here my @pid_exp; sub fork_ { my ($prog, $do_not_kill) = @_; my $pid; unless ($pid = fork()) { splash_warning(N("cannot fork: %s", "$!")) unless defined $pid; exec($prog); } return if $do_not_kill; push @pid_launched, $pid if $embedded; } sub compute_exec_string { my ($icon, $log_exp, $exec_, $gtkplug, undef, $alternate) = @_; #($_[0], @{$_[1]}); my $exec = $exec_ . " --summary" if $expert_wizard && $exec_ =~ /drakwizard/; if ($embedded) { if ($gtkplug != -1) { # not explicitely not embedded $notebook_global->hide; create_hidden_socket_if_needed(); $emb_box->show; $emb_socket->realize; $exec .= " --embedded " . $emb_socket->window->XWINDOW . " " . $$; } if ($gtkplug > 0) { $emb_wait->show; undef $run_pixbuf if $run_pixbuf; #->unref; $run_pixbuf = gtkcreate_pixbuf($icon . "_128"); $run_counter = 255; $run_counter_add = -10; Gtk2->timeout_remove($timeout) if $timeout; $timeout = Gtk2->timeout_add(70, sub { $run_darea->draw(undef); 1 }); $left_locked = 1; $pending_app = 1; fork_($exec); } elsif ($gtkplug == -1) { # explicitely not embedded fork_($exec, 1); } else { # gtkplug == 0 $emb_socket->show; $SIG{CHLD} = undef; $emb_socket->steal(launch_xapp(@{$exec_})); $SIG{CHLD} = \&sig_child; } } else { # not embedded fork_($gtkplug == 0 ? $exec->[0] : $alternate || $exec); } #FIXME # if ($embedded && $gtkplug != -1) { # foreach (@darea_left_list) { # $_->->window->set_cursor($cursor_hand); # if ($_->{state} != 0) { # $_->{state} = 0; # $_->->draw(undef); # } # } # } # (re)start logdrake if needed if ($show_logs && $freeze_log) { #FIXME && !$exp_socket my $pid; my $exp_socket; gtkadd($exp_frame, $exp_socket = Gtk2::Socket->new); $exp_socket->realize; my $exec_log = "logdrake --explain=$log_exp --embedded " . $exp_socket->window->XWINDOW . " " . $$; $freeze_log = 0; if ($exec =~ /(drakfont|drakconnect|drakboot)/) { $exp_frame->hide } # $window_global->height < 600 # fork_($exec_log, 1); unless ($pid = fork()) { splash_warning(N("cannot fork: %s", "$!")) unless defined $pid; exec($exec_log); } push @pid_exp, $pid; } } sub launch_xapp { my ($exec, $name, $xx) = @_; my $find_windows = sub { split '\n', `xwininfo -root -tree -int | grep '$name'` }; my @before = &$find_windows(); fork_("$exec; kill -USR1 $$"); while (1) { my @after = &$find_windows(); while (@after ne $xx + @before) { @after = &$find_windows(); } my $c = top(difference2(\@after, \@before)); $c =~ /\s*([0-9]*)\s*/; return $1; } } sub hide_socket_and_clean { $emb_box->hide; $pending_app = 0; update_exp(); } sub clean_socket { hide_socket_and_clean(); # map { kill 'TERM', $_ if defined $_ } @pid_launched; map { if__($_, kill 'TERM', $_) } @pid_launched; @pid_launched = (); $emb_socket and $emb_socket->destroy; # should not happen since our child should have cause the socket to be destroyes when it exited undef $emb_socket; } sub create_hidden_socket_if_needed { hide_socket_and_clean(); # clean_socket(); gtkpack($emb_box, $emb_socket = Gtk2::Socket->new) unless $emb_socket; $emb_socket->hide; $emb_wait->hide; } sub quit_global { map { if__($_, kill 'TERM', $_) } @pid_exp; setVarsInSh($conffile, { EMBEDDED => bool2text($embedded), LOGS => bool2text($show_logs), EXPERT_WIZARD => bool2text($expert_wizard), THEME => $theme, }); gtkset_mousecursor_normal(); Gtk2->exit(0); } sub splash_warning { my ($label, $cancel_button) = @_; my $ret; my $window = new_dialog(N("Warning"), 1); gtkpack__($window->action_area, gtkadd(Gtk2::HButtonBox->new, gtksignal_connect(Gtk2::Button->new($cancel_button ? N("OK") : N("Close")), clicked => sub { $ret = 1; Gtk2->main_quit }), if_($cancel_button, gtksignal_connect(Gtk2::Button->new(N("Cancel")), clicked => sub { Gtk2->main_quit })), ) ); gtkpack($window->vbox, gtkcreate_img("warning"), Gtk2::Label->new($label), ); $window->show_all; Gtk2->main; $window->destroy; $ret; } sub new_dialog { my ($title, $no_button) = @_; my $dialog = Gtk2::Dialog->new; $dialog->set_transient_for($window_global); $dialog->set_position('center-on-parent'); $dialog->set_border_width(10); $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 $no_button; gtkset_modal($dialog, 1); } sub more_themes { my $window_about = new_dialog(N("More themes")); my $style1 = $window_about->style->copy; # $style1->font(Gtk2::Gdk::Font->fontset_load(N("-*-helvetica-medium-r-normal-*-20-*-100-100-p-*-iso8859-1,*-r-*"))); gtkpack_($window_about->vbox, 0, gtksetstyle(Gtk2::Label->new(N("Getting new themes")), $style1), 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 - Mandrake Control Center")); my $tree_model = Gtk2::TreeStore->new(Gtk2::GType->STRING, Gtk2::GType->STRING, Gtk2::GType->STRING); my $list = Gtk2::TreeView->new_with_model($tree_model); 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', '(original C version' ], [ '', 'Damien "dam\'s" Krotkine', '(perl version)' ], [ '', 'Daouda Lo', '' ], [ '', 'Thierry Vignaud', '' ], [ '', 'Yves Duret', '(perl version)' ], [ '', '' ], [ N("Artwork: "), '', '' ], [ '', 'Anh-Van Nguyen', '' ], #-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 ])->free; } # 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("~ * ~"); #-PO Add your E-Mail address here if you want to show it in the about doialog. my $translator_email = N("~ @ ~"); if ($translator_name ne "~ * ~ " && 0) { $list->append_set(undef, [ 0 => $_->[0], 1 => $_->[1] ])->free foreach [ '', '' ], [ N("Translator: "), $translator_name, $translator_email ]; } $list->get_selection()->set_mode('none'); gtkpack_($window_about->vbox, -r "$themes_dir/$theme/splash_screen_about.png" ? (0, gtkcreate_img("splash_screen_about")) : (1, gtkmodify_font(Gtk2::Label->new(N("Mandrake Control Center %s\n", $version)), 'Bold 24'),), 0, Gtk2::Label->new("\n" . N("Copyright (C) 2001-2002 Mandrakesoft SA") . "\n"), 1, $list, ); $window_about->show_all; } sub connect_to_site { my ($link, $help)=@_; my $browser = $ENV{BROWSER}; my $initial_user = $ENV{INITIAL_USER}; unless ($browser) { splash_warning(" " . N("Warning: No browser specified") . " "); return; } if ($help) { fork_("$browser $link &"); } else { if ($initial_user && $initial_user ne "root") { fork_("su -m -l $initial_user -c \"$browser $link &\""); } else { splash_warning(" ".N("Security Warning: I'm not allowed to connect to the internet as root user")." "); } } } sub set_page { my ($index) = @_; update_exp(); $notebook_global->set_current_page($index); } sub new_pixbuf { my ($pixbuf, $width, $height) = @_; $width ||= $pixbuf->get_height; $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 (undef, undef, $new_pixbuf) = new_pixbuf($pixbuf); $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'); }